Skip to content

[Clang][TableGen] CLANG_ABI on Attr classes breaks inline methods with dllimport on Windows #163349

@zond

Description

@zond

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

  1. Build LLVM/Clang 20+ on Windows with shared library support (LLVM_BUILD_LLVM_DYLIB=ON, CLANG_LINK_CLANG_DYLIB=ON)
  2. Create an external plugin that includes generated Attr headers (e.g., clang/AST/Attrs.inc)
  3. Use any inline methods from Attr classes (e.g., AnnotateAttr::classof())
  4. Link the plugin as a DLL against clang.dll
  5. 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:

  1. Remove CLANG_ABI from Attr classes entirely (revert to pre-d7979c111ef8 behavior)
    - Con: Breaks the AnnotateFunctions and Attribute example plugins on some configurations
  2. Mark specific methods for export instead of the entire class
    - Use CLANG_ABI on individual virtual methods that need exports
    - Leave inline methods unmarked
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    ABIApplication Binary InterfaceclangClang issues not falling into any other categoryplatform:windows

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions