-
Notifications
You must be signed in to change notification settings - Fork 14.9k
Description
Summary
Commit d7979c1 added CLANG_ABI
to all TableGen-generated Attr classes to support plugin exports. However, on Windows this expands to __declspec(dllimport)
for consumers, which causes linker errors for inline methods like classof()
and getAnnotation()
that are defined in the generated header files.
Affected Versions
- LLVM 20.x (release/20.x branch)
- LLVM 21.x (release/21.x branch)
- LLVM main branch
Problem Description
When building external Clang plugins on Windows that use generated Attr classes, the linker fails with unresolved external symbol errors for inline methods:
error LNK2001: unresolved external symbol "__declspec(dllimport) public: static bool __cdecl clang::AnnotateAttr::classof(class clang::Attr const *)"
error LNK2001: unresolved external symbol "__declspec(dllimport) public: class llvm::StringRef __cdecl clang::AnnotateAttr::getAnnotation(void)const"
The issue is that when CLANG_ABI
expands to __declspec(dllimport)
, it marks the entire class for import, including inline methods defined in the header. These inline methods have no corresponding export in clang.dll because they're defined inline and never emitted as exports.
Root Cause
In clang/utils/TableGen/ClangAttrEmitter.cpp (from commit d7979c1):
if (Header)
OS << "class CLANG_ABI " << R.getName() << "Attr : public " << SuperName
<< " {\n";
On Windows when CLANG_EXPORTS
is not defined (i.e., in plugin code consuming clang.dll), CLANG_ABI
expands to __declspec(dllimport)
per clang/include/clang/Support/Compiler.h
:
#elif defined(_WIN32) && !defined(__MINGW32__)
#if defined(CLANG_EXPORTS)
#define CLANG_ABI __declspec(dllexport)
#else
#define CLANG_ABI __declspec(dllimport)
#endif
The __declspec(dllimport)
applies to the entire class, causing the linker to expect all methods (including inline ones) to be imported from the DLL.
Reproduction
- Build LLVM/Clang 20+ on Windows with shared library support (LLVM_BUILD_LLVM_DYLIB=ON, CLANG_LINK_CLANG_DYLIB=ON)
- Create an external plugin that includes generated Attr headers (e.g., clang/AST/Attrs.inc)
- Use any inline methods from Attr classes (e.g., AnnotateAttr::classof())
- Link the plugin as a DLL against clang.dll
- Observe linker errors for unresolved dllimport symbols
Proposed Solution
The CLANG_ABI
macro should not be applied to classes that contain inline methods defined in headers. Possible approaches:
- Remove CLANG_ABI from Attr classes entirely (revert to pre-d7979c111ef8 behavior)
- Con: Breaks the AnnotateFunctions and Attribute example plugins on some configurations - Mark specific methods for export instead of the entire class
- Use CLANG_ABI on individual virtual methods that need exports
- Leave inline methods unmarked - Use CLANG_ABI_NOT_EXPORTED for inline methods
- Apply CLANG_ABI to the class
- Override with CLANG_ABI_NOT_EXPORTED for inline methods
- Requires TableGen changes to detect inline vs. non-inline methods
Workaround
External plugin developers can work around this by removing CLANG_ABI from the generated Attr class declarations with a patch to ClangAttrEmitter.cpp:
- OS << "class CLANG_ABI " << R.getName() << "Attr : public " << SuperName
+ OS << "class " << R.getName() << "Attr : public " << SuperName
Related Issues
- Original PR: [Clang][TableGen] Add explicit symbol visibility macros to code generated #109362 (commit d7979c1)
- Dependency PR: [Clang] Add explicit visibility symbol macros #108276 (added CLANG_ABI macros)