Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reland 'Update llvm::Registry to work for LLVM shared library builds on windows' (#109024) #112640

Merged
merged 3 commits into from
Oct 22, 2024

Conversation

fsfod
Copy link
Contributor

@fsfod fsfod commented Oct 17, 2024

Fix missing extern templates for llvm::Registry use in other projects of llvm

Windows doesn't implicitly import and merge exported symbols across shared libraries
like Linux does so we need to explicitly export/import each instantiation of llvm::Registry.
Updated LLVM_INSTANTIATE_REGISTRY to just be a full explicit template instantiation.

This is part of the work to enable LLVM_BUILD_LLVM_DYLIB and LLVM plugins on window.

fsfod added 3 commits October 17, 2024 01:53
…on windows' (llvm#109024)

Fix missing extern templates for llvm::Registry use in other projects of llvm

Windows doesn't implicitly import and merge exported symbols across shared libraries
like Linux does so we need to explicitly export/import each instantiation of llvm::Registry.
Updated LLVM_INSTANTIATE_REGISTRY to just be a full explicit template instantiation.

This is part of the work to enable LLVM_BUILD_LLVM_DYLIB and LLVM plugins on window.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang-tools-extra clangd clang-tidy clang:frontend Language frontend issues, e.g. anything involving "Sema" flang:driver flang Flang issues not falling into any other category llvm:support llvm:ir labels Oct 17, 2024
@llvmbot
Copy link
Member

llvmbot commented Oct 17, 2024

@llvm/pr-subscribers-clang
@llvm/pr-subscribers-llvm-support

@llvm/pr-subscribers-clang-tools-extra

Author: Thomas Fransham (fsfod)

Changes

Fix missing extern templates for llvm::Registry use in other projects of llvm

Windows doesn't implicitly import and merge exported symbols across shared libraries
like Linux does so we need to explicitly export/import each instantiation of llvm::Registry.
Updated LLVM_INSTANTIATE_REGISTRY to just be a full explicit template instantiation.

This is part of the work to enable LLVM_BUILD_LLVM_DYLIB and LLVM plugins on window.


Full diff: https://github.com/llvm/llvm-project/pull/112640.diff

15 Files Affected:

  • (modified) clang-tools-extra/clang-doc/Generators.h (+4)
  • (modified) clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h (+4)
  • (modified) clang-tools-extra/clangd/URI.h (+4)
  • (modified) clang-tools-extra/clangd/refactor/Tweak.h (+4)
  • (modified) clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h (+4)
  • (modified) clang/include/clang/Basic/ParsedAttrInfo.h (+5)
  • (modified) clang/include/clang/Frontend/FrontendPluginRegistry.h (+5)
  • (modified) clang/include/clang/Lex/Preprocessor.h (+5)
  • (modified) clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h (+6)
  • (modified) clang/include/clang/Tooling/ToolExecutorPluginRegistry.h (+6)
  • (modified) flang/include/flang/Frontend/FrontendPluginRegistry.h (+4)
  • (modified) llvm/include/llvm/CodeGen/GCMetadataPrinter.h (+2)
  • (modified) llvm/include/llvm/IR/GCStrategy.h (+2)
  • (modified) llvm/include/llvm/Support/Compiler.h (+11)
  • (modified) llvm/include/llvm/Support/Registry.h (+34-30)
diff --git a/clang-tools-extra/clang-doc/Generators.h b/clang-tools-extra/clang-doc/Generators.h
index ba0ef64d3d0f5f..d62d7faa9a69f3 100644
--- a/clang-tools-extra/clang-doc/Generators.h
+++ b/clang-tools-extra/clang-doc/Generators.h
@@ -55,4 +55,8 @@ std::string getTagType(TagTypeKind AS);
 } // namespace doc
 } // namespace clang
 
+namespace llvm {
+extern template class Registry<clang::doc::Generator>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_GENERATOR_H
diff --git a/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h b/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h
index 78d914bfedbc94..8a07b05c26446c 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h
@@ -18,4 +18,8 @@ using ClangTidyModuleRegistry = llvm::Registry<ClangTidyModule>;
 
 } // namespace clang::tidy
 
+namespace llvm {
+extern template class Registry<clang::tidy::ClangTidyModule>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYMODULEREGISTRY_H
diff --git a/clang-tools-extra/clangd/URI.h b/clang-tools-extra/clangd/URI.h
index 7f3bc9d1645a8f..d4629f17551cca 100644
--- a/clang-tools-extra/clangd/URI.h
+++ b/clang-tools-extra/clangd/URI.h
@@ -133,4 +133,8 @@ typedef llvm::Registry<URIScheme> URISchemeRegistry;
 } // namespace clangd
 } // namespace clang
 
+namespace llvm {
+extern template class Registry<clang::clangd::URIScheme>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_URI_H
diff --git a/clang-tools-extra/clangd/refactor/Tweak.h b/clang-tools-extra/clangd/refactor/Tweak.h
index 2769b401d89439..257f44a285f88a 100644
--- a/clang-tools-extra/clangd/refactor/Tweak.h
+++ b/clang-tools-extra/clangd/refactor/Tweak.h
@@ -147,4 +147,8 @@ prepareTweak(StringRef ID, const Tweak::Selection &S,
 } // namespace clangd
 } // namespace clang
 
+namespace llvm {
+extern template class Registry<clang::clangd::Tweak>;
+} // namespace llvm
+
 #endif
diff --git a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h
index 98aee5f277cf18..b07b9ed1ac25f5 100644
--- a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h
+++ b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h
@@ -46,4 +46,8 @@ using IncludeSpellingStrategy = llvm::Registry<IncludeSpeller>;
 std::string spellHeader(const IncludeSpeller::Input &Input);
 } // namespace clang::include_cleaner
 
+namespace llvm {
+extern template class Registry<clang::include_cleaner::IncludeSpeller>;
+} // namespace llvm
+
 #endif
diff --git a/clang/include/clang/Basic/ParsedAttrInfo.h b/clang/include/clang/Basic/ParsedAttrInfo.h
index fab5c6f1377d27..3b5f5d3c3f92ac 100644
--- a/clang/include/clang/Basic/ParsedAttrInfo.h
+++ b/clang/include/clang/Basic/ParsedAttrInfo.h
@@ -17,6 +17,7 @@
 
 #include "clang/Basic/AttrSubjectMatchRules.h"
 #include "clang/Basic/AttributeCommonInfo.h"
+#include "clang/Support/Compiler.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/Registry.h"
 #include <climits>
@@ -175,4 +176,8 @@ const std::list<std::unique_ptr<ParsedAttrInfo>> &getAttributePluginInstances();
 
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI Registry<clang::ParsedAttrInfo>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_BASIC_PARSEDATTRINFO_H
diff --git a/clang/include/clang/Frontend/FrontendPluginRegistry.h b/clang/include/clang/Frontend/FrontendPluginRegistry.h
index 810578534acb45..5eea9c2fd89a32 100644
--- a/clang/include/clang/Frontend/FrontendPluginRegistry.h
+++ b/clang/include/clang/Frontend/FrontendPluginRegistry.h
@@ -14,6 +14,7 @@
 #define LLVM_CLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H
 
 #include "clang/Frontend/FrontendAction.h"
+#include "clang/Support/Compiler.h"
 #include "llvm/Support/Registry.h"
 
 namespace clang {
@@ -23,4 +24,8 @@ using FrontendPluginRegistry = llvm::Registry<PluginASTAction>;
 
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI Registry<clang::PluginASTAction>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 4643b0213815f8..92749e4de44b57 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -32,6 +32,7 @@
 #include "clang/Lex/PPEmbedParameters.h"
 #include "clang/Lex/Token.h"
 #include "clang/Lex/TokenLexer.h"
+#include "clang/Support/Compiler.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
@@ -3060,4 +3061,8 @@ using PragmaHandlerRegistry = llvm::Registry<PragmaHandler>;
 
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI Registry<clang::PragmaHandler>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_LEX_PREPROCESSOR_H
diff --git a/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h b/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h
index 8c58ad926a402a..e6bcac542b0ecb 100644
--- a/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h
+++ b/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
 #define LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
 
+#include "clang/Support/Compiler.h"
 #include "clang/Tooling/CompilationDatabase.h"
 #include "llvm/Support/Registry.h"
 
@@ -42,4 +43,9 @@ using CompilationDatabasePluginRegistry =
 } // namespace tooling
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI
+    Registry<clang::tooling::CompilationDatabasePlugin>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
diff --git a/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h b/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h
index 5304ff26252def..8d54583234684e 100644
--- a/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h
+++ b/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
 #define LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
 
+#include "clang/Support/Compiler.h"
 #include "clang/Tooling/Execution.h"
 #include "llvm/Support/Registry.h"
 
@@ -20,4 +21,9 @@ using ToolExecutorPluginRegistry = llvm::Registry<ToolExecutorPlugin>;
 } // namespace tooling
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI
+    Registry<clang::tooling::ToolExecutorPlugin>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
diff --git a/flang/include/flang/Frontend/FrontendPluginRegistry.h b/flang/include/flang/Frontend/FrontendPluginRegistry.h
index 8b1f576c39e24a..a8079dbfaf8693 100644
--- a/flang/include/flang/Frontend/FrontendPluginRegistry.h
+++ b/flang/include/flang/Frontend/FrontendPluginRegistry.h
@@ -25,4 +25,8 @@ using FrontendPluginRegistry = llvm::Registry<PluginParseTreeAction>;
 
 } // namespace Fortran::frontend
 
+namespace llvm {
+extern template class Registry<Fortran::frontend::PluginParseTreeAction>;
+}
+
 #endif // FORTRAN_FRONTEND_FRONTENDPLUGINREGISTRY_H
diff --git a/llvm/include/llvm/CodeGen/GCMetadataPrinter.h b/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
index f9527c9f8752e9..9d421be8313f01 100644
--- a/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
+++ b/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
@@ -34,6 +34,8 @@ class StackMaps;
 /// defaults from Registry.
 using GCMetadataPrinterRegistry = Registry<GCMetadataPrinter>;
 
+extern template class LLVM_TEMPLATE_ABI Registry<GCMetadataPrinter>;
+
 /// GCMetadataPrinter - Emits GC metadata as assembly code.  Instances are
 /// created, managed, and owned by the AsmPrinter.
 class GCMetadataPrinter {
diff --git a/llvm/include/llvm/IR/GCStrategy.h b/llvm/include/llvm/IR/GCStrategy.h
index 3186465f001812..cbfbe23aaa0683 100644
--- a/llvm/include/llvm/IR/GCStrategy.h
+++ b/llvm/include/llvm/IR/GCStrategy.h
@@ -141,6 +141,8 @@ class GCStrategy {
 /// GCMetadataPrinterRegistery as well.
 using GCRegistry = Registry<GCStrategy>;
 
+extern template class LLVM_TEMPLATE_ABI Registry<GCStrategy>;
+
 /// Lookup the GCStrategy object associated with the given gc name.
 std::unique_ptr<GCStrategy> getGCStrategy(const StringRef Name);
 
diff --git a/llvm/include/llvm/Support/Compiler.h b/llvm/include/llvm/Support/Compiler.h
index 1d2d751d4dc11a..ab0cbff43d749c 100644
--- a/llvm/include/llvm/Support/Compiler.h
+++ b/llvm/include/llvm/Support/Compiler.h
@@ -153,6 +153,12 @@
 /// exported when llvm is built as a shared library with everything else that is
 /// unannotated will have internal visibility.
 ///
+/// LLVM_ABI_EXPORT is for the special case for things like plugin symbol
+/// declarations or definitions where we don't want the macro to be switching
+/// between dllexport and dllimport on windows based on what codebase is being
+/// built, it will only be dllexport. For non windows platforms this macro
+/// behaves the same as LLVM_ABI.
+///
 /// LLVM_EXPORT_TEMPLATE is used on explicit template instantiations in source
 /// files that were declared extern in a header. This macro is only set as a
 /// compiler export attribute on windows, on other platforms it does nothing.
@@ -179,6 +185,7 @@
 #define LLVM_ABI
 #define LLVM_TEMPLATE_ABI
 #define LLVM_EXPORT_TEMPLATE
+#define LLVM_ABI_EXPORT
 #elif defined(_WIN32) && !defined(__MINGW32__)
 #if defined(LLVM_EXPORTS)
 #define LLVM_ABI __declspec(dllexport)
@@ -189,19 +196,23 @@
 #define LLVM_TEMPLATE_ABI __declspec(dllimport)
 #define LLVM_EXPORT_TEMPLATE
 #endif
+#define LLVM_ABI_EXPORT __declspec(dllexport)
 #elif defined(__ELF__) || defined(__MINGW32__) || defined(_AIX)
 #define LLVM_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #define LLVM_TEMPLATE_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #define LLVM_EXPORT_TEMPLATE
+#define LLVM_ABI_EXPORT LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #elif defined(__MACH__) || defined(__WASM__)
 #define LLVM_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #define LLVM_TEMPLATE_ABI
 #define LLVM_EXPORT_TEMPLATE
+#define LLVM_ABI_EXPORT LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #endif
 #else
 #define LLVM_ABI
 #define LLVM_TEMPLATE_ABI
 #define LLVM_EXPORT_TEMPLATE
+#define LLVM_ABI_EXPORT
 #endif
 #define LLVM_C_ABI LLVM_ABI
 #endif
diff --git a/llvm/include/llvm/Support/Registry.h b/llvm/include/llvm/Support/Registry.h
index 5bb6a254a47f4c..ff9226c39359c5 100644
--- a/llvm/include/llvm/Support/Registry.h
+++ b/llvm/include/llvm/Support/Registry.h
@@ -53,7 +53,13 @@ namespace llvm {
     Registry() = delete;
 
     friend class node;
-    static node *Head, *Tail;
+    // These must be must two separate declarations to workaround a 20 year
+    // old MSVC bug with dllexport and multiple static fields in the same
+    // declaration causing error C2487 "member of dll interface class may not
+    // be declared with dll interface".
+    // https://developercommunity.visualstudio.com/t/c2487-in-dllexport-class-with-static-members/69878
+    static node *Head;
+    static node *Tail;
 
   public:
     /// Node in linked list of entries.
@@ -76,7 +82,13 @@ namespace llvm {
     /// add a node to the executable's registry. Therefore it's not defined here
     /// to avoid it being instantiated in the plugin and is instead defined in
     /// the executable (see LLVM_INSTANTIATE_REGISTRY below).
-    static void add_node(node *N);
+    static void add_node(node *N) {
+      if (Tail)
+        Tail->Next = N;
+      else
+        Head = N;
+      Tail = N;
+    }
 
     /// Iterators for registry entries.
     ///
@@ -95,7 +107,7 @@ namespace llvm {
 
     // begin is not defined here in order to avoid usage of an undefined static
     // data member, instead it's instantiated by LLVM_INSTANTIATE_REGISTRY.
-    static iterator begin();
+    static iterator begin() { return iterator(Head); }
     static iterator end()   { return iterator(nullptr); }
 
     static iterator_range<iterator> entries() {
@@ -124,36 +136,28 @@ namespace llvm {
       }
     };
   };
+
 } // end namespace llvm
 
+#ifdef _WIN32
 /// Instantiate a registry class.
-///
-/// This provides template definitions of add_node, begin, and the Head and Tail
-/// pointers, then explicitly instantiates them. We could explicitly specialize
-/// them, instead of the two-step process of define then instantiate, but
-/// strictly speaking that's not allowed by the C++ standard (we would need to
-/// have explicit specialization declarations in all translation units where the
-/// specialization is used) so we don't.
-#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS) \
-  namespace llvm { \
-  template<typename T> typename Registry<T>::node *Registry<T>::Head = nullptr;\
-  template<typename T> typename Registry<T>::node *Registry<T>::Tail = nullptr;\
-  template<typename T> \
-  void Registry<T>::add_node(typename Registry<T>::node *N) { \
-    if (Tail) \
-      Tail->Next = N; \
-    else \
-      Head = N; \
-    Tail = N; \
-  } \
-  template<typename T> typename Registry<T>::iterator Registry<T>::begin() { \
-    return iterator(Head); \
-  } \
-  template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Head; \
-  template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Tail; \
-  template \
-  void Registry<REGISTRY_CLASS::type>::add_node(REGISTRY_CLASS::node*); \
-  template REGISTRY_CLASS::iterator Registry<REGISTRY_CLASS::type>::begin(); \
+#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS)                              \
+  namespace llvm {                                                             \
+  template <typename T>                                                        \
+  typename Registry<T>::node *Registry<T>::Head = nullptr;                     \
+  template <typename T>                                                        \
+  typename Registry<T>::node *Registry<T>::Tail = nullptr;                     \
+  template class LLVM_ABI_EXPORT Registry<REGISTRY_CLASS::type>;               \
+  }
+#else
+#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS)                              \
+  namespace llvm {                                                             \
+  template <typename T>                                                        \
+  typename Registry<T>::node *Registry<T>::Head = nullptr;                     \
+  template <typename T>                                                        \
+  typename Registry<T>::node *Registry<T>::Tail = nullptr;                     \
+  template class Registry<REGISTRY_CLASS::type>;                               \
   }
+#endif
 
 #endif // LLVM_SUPPORT_REGISTRY_H

@llvmbot
Copy link
Member

llvmbot commented Oct 17, 2024

@llvm/pr-subscribers-flang-driver

Author: Thomas Fransham (fsfod)

Changes

Fix missing extern templates for llvm::Registry use in other projects of llvm

Windows doesn't implicitly import and merge exported symbols across shared libraries
like Linux does so we need to explicitly export/import each instantiation of llvm::Registry.
Updated LLVM_INSTANTIATE_REGISTRY to just be a full explicit template instantiation.

This is part of the work to enable LLVM_BUILD_LLVM_DYLIB and LLVM plugins on window.


Full diff: https://github.com/llvm/llvm-project/pull/112640.diff

15 Files Affected:

  • (modified) clang-tools-extra/clang-doc/Generators.h (+4)
  • (modified) clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h (+4)
  • (modified) clang-tools-extra/clangd/URI.h (+4)
  • (modified) clang-tools-extra/clangd/refactor/Tweak.h (+4)
  • (modified) clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h (+4)
  • (modified) clang/include/clang/Basic/ParsedAttrInfo.h (+5)
  • (modified) clang/include/clang/Frontend/FrontendPluginRegistry.h (+5)
  • (modified) clang/include/clang/Lex/Preprocessor.h (+5)
  • (modified) clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h (+6)
  • (modified) clang/include/clang/Tooling/ToolExecutorPluginRegistry.h (+6)
  • (modified) flang/include/flang/Frontend/FrontendPluginRegistry.h (+4)
  • (modified) llvm/include/llvm/CodeGen/GCMetadataPrinter.h (+2)
  • (modified) llvm/include/llvm/IR/GCStrategy.h (+2)
  • (modified) llvm/include/llvm/Support/Compiler.h (+11)
  • (modified) llvm/include/llvm/Support/Registry.h (+34-30)
diff --git a/clang-tools-extra/clang-doc/Generators.h b/clang-tools-extra/clang-doc/Generators.h
index ba0ef64d3d0f5f..d62d7faa9a69f3 100644
--- a/clang-tools-extra/clang-doc/Generators.h
+++ b/clang-tools-extra/clang-doc/Generators.h
@@ -55,4 +55,8 @@ std::string getTagType(TagTypeKind AS);
 } // namespace doc
 } // namespace clang
 
+namespace llvm {
+extern template class Registry<clang::doc::Generator>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_GENERATOR_H
diff --git a/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h b/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h
index 78d914bfedbc94..8a07b05c26446c 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h
@@ -18,4 +18,8 @@ using ClangTidyModuleRegistry = llvm::Registry<ClangTidyModule>;
 
 } // namespace clang::tidy
 
+namespace llvm {
+extern template class Registry<clang::tidy::ClangTidyModule>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYMODULEREGISTRY_H
diff --git a/clang-tools-extra/clangd/URI.h b/clang-tools-extra/clangd/URI.h
index 7f3bc9d1645a8f..d4629f17551cca 100644
--- a/clang-tools-extra/clangd/URI.h
+++ b/clang-tools-extra/clangd/URI.h
@@ -133,4 +133,8 @@ typedef llvm::Registry<URIScheme> URISchemeRegistry;
 } // namespace clangd
 } // namespace clang
 
+namespace llvm {
+extern template class Registry<clang::clangd::URIScheme>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_URI_H
diff --git a/clang-tools-extra/clangd/refactor/Tweak.h b/clang-tools-extra/clangd/refactor/Tweak.h
index 2769b401d89439..257f44a285f88a 100644
--- a/clang-tools-extra/clangd/refactor/Tweak.h
+++ b/clang-tools-extra/clangd/refactor/Tweak.h
@@ -147,4 +147,8 @@ prepareTweak(StringRef ID, const Tweak::Selection &S,
 } // namespace clangd
 } // namespace clang
 
+namespace llvm {
+extern template class Registry<clang::clangd::Tweak>;
+} // namespace llvm
+
 #endif
diff --git a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h
index 98aee5f277cf18..b07b9ed1ac25f5 100644
--- a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h
+++ b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h
@@ -46,4 +46,8 @@ using IncludeSpellingStrategy = llvm::Registry<IncludeSpeller>;
 std::string spellHeader(const IncludeSpeller::Input &Input);
 } // namespace clang::include_cleaner
 
+namespace llvm {
+extern template class Registry<clang::include_cleaner::IncludeSpeller>;
+} // namespace llvm
+
 #endif
diff --git a/clang/include/clang/Basic/ParsedAttrInfo.h b/clang/include/clang/Basic/ParsedAttrInfo.h
index fab5c6f1377d27..3b5f5d3c3f92ac 100644
--- a/clang/include/clang/Basic/ParsedAttrInfo.h
+++ b/clang/include/clang/Basic/ParsedAttrInfo.h
@@ -17,6 +17,7 @@
 
 #include "clang/Basic/AttrSubjectMatchRules.h"
 #include "clang/Basic/AttributeCommonInfo.h"
+#include "clang/Support/Compiler.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/Registry.h"
 #include <climits>
@@ -175,4 +176,8 @@ const std::list<std::unique_ptr<ParsedAttrInfo>> &getAttributePluginInstances();
 
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI Registry<clang::ParsedAttrInfo>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_BASIC_PARSEDATTRINFO_H
diff --git a/clang/include/clang/Frontend/FrontendPluginRegistry.h b/clang/include/clang/Frontend/FrontendPluginRegistry.h
index 810578534acb45..5eea9c2fd89a32 100644
--- a/clang/include/clang/Frontend/FrontendPluginRegistry.h
+++ b/clang/include/clang/Frontend/FrontendPluginRegistry.h
@@ -14,6 +14,7 @@
 #define LLVM_CLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H
 
 #include "clang/Frontend/FrontendAction.h"
+#include "clang/Support/Compiler.h"
 #include "llvm/Support/Registry.h"
 
 namespace clang {
@@ -23,4 +24,8 @@ using FrontendPluginRegistry = llvm::Registry<PluginASTAction>;
 
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI Registry<clang::PluginASTAction>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 4643b0213815f8..92749e4de44b57 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -32,6 +32,7 @@
 #include "clang/Lex/PPEmbedParameters.h"
 #include "clang/Lex/Token.h"
 #include "clang/Lex/TokenLexer.h"
+#include "clang/Support/Compiler.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
@@ -3060,4 +3061,8 @@ using PragmaHandlerRegistry = llvm::Registry<PragmaHandler>;
 
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI Registry<clang::PragmaHandler>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_LEX_PREPROCESSOR_H
diff --git a/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h b/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h
index 8c58ad926a402a..e6bcac542b0ecb 100644
--- a/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h
+++ b/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
 #define LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
 
+#include "clang/Support/Compiler.h"
 #include "clang/Tooling/CompilationDatabase.h"
 #include "llvm/Support/Registry.h"
 
@@ -42,4 +43,9 @@ using CompilationDatabasePluginRegistry =
 } // namespace tooling
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI
+    Registry<clang::tooling::CompilationDatabasePlugin>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
diff --git a/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h b/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h
index 5304ff26252def..8d54583234684e 100644
--- a/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h
+++ b/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
 #define LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
 
+#include "clang/Support/Compiler.h"
 #include "clang/Tooling/Execution.h"
 #include "llvm/Support/Registry.h"
 
@@ -20,4 +21,9 @@ using ToolExecutorPluginRegistry = llvm::Registry<ToolExecutorPlugin>;
 } // namespace tooling
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI
+    Registry<clang::tooling::ToolExecutorPlugin>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
diff --git a/flang/include/flang/Frontend/FrontendPluginRegistry.h b/flang/include/flang/Frontend/FrontendPluginRegistry.h
index 8b1f576c39e24a..a8079dbfaf8693 100644
--- a/flang/include/flang/Frontend/FrontendPluginRegistry.h
+++ b/flang/include/flang/Frontend/FrontendPluginRegistry.h
@@ -25,4 +25,8 @@ using FrontendPluginRegistry = llvm::Registry<PluginParseTreeAction>;
 
 } // namespace Fortran::frontend
 
+namespace llvm {
+extern template class Registry<Fortran::frontend::PluginParseTreeAction>;
+}
+
 #endif // FORTRAN_FRONTEND_FRONTENDPLUGINREGISTRY_H
diff --git a/llvm/include/llvm/CodeGen/GCMetadataPrinter.h b/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
index f9527c9f8752e9..9d421be8313f01 100644
--- a/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
+++ b/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
@@ -34,6 +34,8 @@ class StackMaps;
 /// defaults from Registry.
 using GCMetadataPrinterRegistry = Registry<GCMetadataPrinter>;
 
+extern template class LLVM_TEMPLATE_ABI Registry<GCMetadataPrinter>;
+
 /// GCMetadataPrinter - Emits GC metadata as assembly code.  Instances are
 /// created, managed, and owned by the AsmPrinter.
 class GCMetadataPrinter {
diff --git a/llvm/include/llvm/IR/GCStrategy.h b/llvm/include/llvm/IR/GCStrategy.h
index 3186465f001812..cbfbe23aaa0683 100644
--- a/llvm/include/llvm/IR/GCStrategy.h
+++ b/llvm/include/llvm/IR/GCStrategy.h
@@ -141,6 +141,8 @@ class GCStrategy {
 /// GCMetadataPrinterRegistery as well.
 using GCRegistry = Registry<GCStrategy>;
 
+extern template class LLVM_TEMPLATE_ABI Registry<GCStrategy>;
+
 /// Lookup the GCStrategy object associated with the given gc name.
 std::unique_ptr<GCStrategy> getGCStrategy(const StringRef Name);
 
diff --git a/llvm/include/llvm/Support/Compiler.h b/llvm/include/llvm/Support/Compiler.h
index 1d2d751d4dc11a..ab0cbff43d749c 100644
--- a/llvm/include/llvm/Support/Compiler.h
+++ b/llvm/include/llvm/Support/Compiler.h
@@ -153,6 +153,12 @@
 /// exported when llvm is built as a shared library with everything else that is
 /// unannotated will have internal visibility.
 ///
+/// LLVM_ABI_EXPORT is for the special case for things like plugin symbol
+/// declarations or definitions where we don't want the macro to be switching
+/// between dllexport and dllimport on windows based on what codebase is being
+/// built, it will only be dllexport. For non windows platforms this macro
+/// behaves the same as LLVM_ABI.
+///
 /// LLVM_EXPORT_TEMPLATE is used on explicit template instantiations in source
 /// files that were declared extern in a header. This macro is only set as a
 /// compiler export attribute on windows, on other platforms it does nothing.
@@ -179,6 +185,7 @@
 #define LLVM_ABI
 #define LLVM_TEMPLATE_ABI
 #define LLVM_EXPORT_TEMPLATE
+#define LLVM_ABI_EXPORT
 #elif defined(_WIN32) && !defined(__MINGW32__)
 #if defined(LLVM_EXPORTS)
 #define LLVM_ABI __declspec(dllexport)
@@ -189,19 +196,23 @@
 #define LLVM_TEMPLATE_ABI __declspec(dllimport)
 #define LLVM_EXPORT_TEMPLATE
 #endif
+#define LLVM_ABI_EXPORT __declspec(dllexport)
 #elif defined(__ELF__) || defined(__MINGW32__) || defined(_AIX)
 #define LLVM_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #define LLVM_TEMPLATE_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #define LLVM_EXPORT_TEMPLATE
+#define LLVM_ABI_EXPORT LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #elif defined(__MACH__) || defined(__WASM__)
 #define LLVM_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #define LLVM_TEMPLATE_ABI
 #define LLVM_EXPORT_TEMPLATE
+#define LLVM_ABI_EXPORT LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #endif
 #else
 #define LLVM_ABI
 #define LLVM_TEMPLATE_ABI
 #define LLVM_EXPORT_TEMPLATE
+#define LLVM_ABI_EXPORT
 #endif
 #define LLVM_C_ABI LLVM_ABI
 #endif
diff --git a/llvm/include/llvm/Support/Registry.h b/llvm/include/llvm/Support/Registry.h
index 5bb6a254a47f4c..ff9226c39359c5 100644
--- a/llvm/include/llvm/Support/Registry.h
+++ b/llvm/include/llvm/Support/Registry.h
@@ -53,7 +53,13 @@ namespace llvm {
     Registry() = delete;
 
     friend class node;
-    static node *Head, *Tail;
+    // These must be must two separate declarations to workaround a 20 year
+    // old MSVC bug with dllexport and multiple static fields in the same
+    // declaration causing error C2487 "member of dll interface class may not
+    // be declared with dll interface".
+    // https://developercommunity.visualstudio.com/t/c2487-in-dllexport-class-with-static-members/69878
+    static node *Head;
+    static node *Tail;
 
   public:
     /// Node in linked list of entries.
@@ -76,7 +82,13 @@ namespace llvm {
     /// add a node to the executable's registry. Therefore it's not defined here
     /// to avoid it being instantiated in the plugin and is instead defined in
     /// the executable (see LLVM_INSTANTIATE_REGISTRY below).
-    static void add_node(node *N);
+    static void add_node(node *N) {
+      if (Tail)
+        Tail->Next = N;
+      else
+        Head = N;
+      Tail = N;
+    }
 
     /// Iterators for registry entries.
     ///
@@ -95,7 +107,7 @@ namespace llvm {
 
     // begin is not defined here in order to avoid usage of an undefined static
     // data member, instead it's instantiated by LLVM_INSTANTIATE_REGISTRY.
-    static iterator begin();
+    static iterator begin() { return iterator(Head); }
     static iterator end()   { return iterator(nullptr); }
 
     static iterator_range<iterator> entries() {
@@ -124,36 +136,28 @@ namespace llvm {
       }
     };
   };
+
 } // end namespace llvm
 
+#ifdef _WIN32
 /// Instantiate a registry class.
-///
-/// This provides template definitions of add_node, begin, and the Head and Tail
-/// pointers, then explicitly instantiates them. We could explicitly specialize
-/// them, instead of the two-step process of define then instantiate, but
-/// strictly speaking that's not allowed by the C++ standard (we would need to
-/// have explicit specialization declarations in all translation units where the
-/// specialization is used) so we don't.
-#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS) \
-  namespace llvm { \
-  template<typename T> typename Registry<T>::node *Registry<T>::Head = nullptr;\
-  template<typename T> typename Registry<T>::node *Registry<T>::Tail = nullptr;\
-  template<typename T> \
-  void Registry<T>::add_node(typename Registry<T>::node *N) { \
-    if (Tail) \
-      Tail->Next = N; \
-    else \
-      Head = N; \
-    Tail = N; \
-  } \
-  template<typename T> typename Registry<T>::iterator Registry<T>::begin() { \
-    return iterator(Head); \
-  } \
-  template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Head; \
-  template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Tail; \
-  template \
-  void Registry<REGISTRY_CLASS::type>::add_node(REGISTRY_CLASS::node*); \
-  template REGISTRY_CLASS::iterator Registry<REGISTRY_CLASS::type>::begin(); \
+#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS)                              \
+  namespace llvm {                                                             \
+  template <typename T>                                                        \
+  typename Registry<T>::node *Registry<T>::Head = nullptr;                     \
+  template <typename T>                                                        \
+  typename Registry<T>::node *Registry<T>::Tail = nullptr;                     \
+  template class LLVM_ABI_EXPORT Registry<REGISTRY_CLASS::type>;               \
+  }
+#else
+#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS)                              \
+  namespace llvm {                                                             \
+  template <typename T>                                                        \
+  typename Registry<T>::node *Registry<T>::Head = nullptr;                     \
+  template <typename T>                                                        \
+  typename Registry<T>::node *Registry<T>::Tail = nullptr;                     \
+  template class Registry<REGISTRY_CLASS::type>;                               \
   }
+#endif
 
 #endif // LLVM_SUPPORT_REGISTRY_H

@llvmbot
Copy link
Member

llvmbot commented Oct 17, 2024

@llvm/pr-subscribers-llvm-ir

Author: Thomas Fransham (fsfod)

Changes

Fix missing extern templates for llvm::Registry use in other projects of llvm

Windows doesn't implicitly import and merge exported symbols across shared libraries
like Linux does so we need to explicitly export/import each instantiation of llvm::Registry.
Updated LLVM_INSTANTIATE_REGISTRY to just be a full explicit template instantiation.

This is part of the work to enable LLVM_BUILD_LLVM_DYLIB and LLVM plugins on window.


Full diff: https://github.com/llvm/llvm-project/pull/112640.diff

15 Files Affected:

  • (modified) clang-tools-extra/clang-doc/Generators.h (+4)
  • (modified) clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h (+4)
  • (modified) clang-tools-extra/clangd/URI.h (+4)
  • (modified) clang-tools-extra/clangd/refactor/Tweak.h (+4)
  • (modified) clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h (+4)
  • (modified) clang/include/clang/Basic/ParsedAttrInfo.h (+5)
  • (modified) clang/include/clang/Frontend/FrontendPluginRegistry.h (+5)
  • (modified) clang/include/clang/Lex/Preprocessor.h (+5)
  • (modified) clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h (+6)
  • (modified) clang/include/clang/Tooling/ToolExecutorPluginRegistry.h (+6)
  • (modified) flang/include/flang/Frontend/FrontendPluginRegistry.h (+4)
  • (modified) llvm/include/llvm/CodeGen/GCMetadataPrinter.h (+2)
  • (modified) llvm/include/llvm/IR/GCStrategy.h (+2)
  • (modified) llvm/include/llvm/Support/Compiler.h (+11)
  • (modified) llvm/include/llvm/Support/Registry.h (+34-30)
diff --git a/clang-tools-extra/clang-doc/Generators.h b/clang-tools-extra/clang-doc/Generators.h
index ba0ef64d3d0f5f..d62d7faa9a69f3 100644
--- a/clang-tools-extra/clang-doc/Generators.h
+++ b/clang-tools-extra/clang-doc/Generators.h
@@ -55,4 +55,8 @@ std::string getTagType(TagTypeKind AS);
 } // namespace doc
 } // namespace clang
 
+namespace llvm {
+extern template class Registry<clang::doc::Generator>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_GENERATOR_H
diff --git a/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h b/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h
index 78d914bfedbc94..8a07b05c26446c 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h
@@ -18,4 +18,8 @@ using ClangTidyModuleRegistry = llvm::Registry<ClangTidyModule>;
 
 } // namespace clang::tidy
 
+namespace llvm {
+extern template class Registry<clang::tidy::ClangTidyModule>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYMODULEREGISTRY_H
diff --git a/clang-tools-extra/clangd/URI.h b/clang-tools-extra/clangd/URI.h
index 7f3bc9d1645a8f..d4629f17551cca 100644
--- a/clang-tools-extra/clangd/URI.h
+++ b/clang-tools-extra/clangd/URI.h
@@ -133,4 +133,8 @@ typedef llvm::Registry<URIScheme> URISchemeRegistry;
 } // namespace clangd
 } // namespace clang
 
+namespace llvm {
+extern template class Registry<clang::clangd::URIScheme>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_URI_H
diff --git a/clang-tools-extra/clangd/refactor/Tweak.h b/clang-tools-extra/clangd/refactor/Tweak.h
index 2769b401d89439..257f44a285f88a 100644
--- a/clang-tools-extra/clangd/refactor/Tweak.h
+++ b/clang-tools-extra/clangd/refactor/Tweak.h
@@ -147,4 +147,8 @@ prepareTweak(StringRef ID, const Tweak::Selection &S,
 } // namespace clangd
 } // namespace clang
 
+namespace llvm {
+extern template class Registry<clang::clangd::Tweak>;
+} // namespace llvm
+
 #endif
diff --git a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h
index 98aee5f277cf18..b07b9ed1ac25f5 100644
--- a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h
+++ b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h
@@ -46,4 +46,8 @@ using IncludeSpellingStrategy = llvm::Registry<IncludeSpeller>;
 std::string spellHeader(const IncludeSpeller::Input &Input);
 } // namespace clang::include_cleaner
 
+namespace llvm {
+extern template class Registry<clang::include_cleaner::IncludeSpeller>;
+} // namespace llvm
+
 #endif
diff --git a/clang/include/clang/Basic/ParsedAttrInfo.h b/clang/include/clang/Basic/ParsedAttrInfo.h
index fab5c6f1377d27..3b5f5d3c3f92ac 100644
--- a/clang/include/clang/Basic/ParsedAttrInfo.h
+++ b/clang/include/clang/Basic/ParsedAttrInfo.h
@@ -17,6 +17,7 @@
 
 #include "clang/Basic/AttrSubjectMatchRules.h"
 #include "clang/Basic/AttributeCommonInfo.h"
+#include "clang/Support/Compiler.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/Registry.h"
 #include <climits>
@@ -175,4 +176,8 @@ const std::list<std::unique_ptr<ParsedAttrInfo>> &getAttributePluginInstances();
 
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI Registry<clang::ParsedAttrInfo>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_BASIC_PARSEDATTRINFO_H
diff --git a/clang/include/clang/Frontend/FrontendPluginRegistry.h b/clang/include/clang/Frontend/FrontendPluginRegistry.h
index 810578534acb45..5eea9c2fd89a32 100644
--- a/clang/include/clang/Frontend/FrontendPluginRegistry.h
+++ b/clang/include/clang/Frontend/FrontendPluginRegistry.h
@@ -14,6 +14,7 @@
 #define LLVM_CLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H
 
 #include "clang/Frontend/FrontendAction.h"
+#include "clang/Support/Compiler.h"
 #include "llvm/Support/Registry.h"
 
 namespace clang {
@@ -23,4 +24,8 @@ using FrontendPluginRegistry = llvm::Registry<PluginASTAction>;
 
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI Registry<clang::PluginASTAction>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 4643b0213815f8..92749e4de44b57 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -32,6 +32,7 @@
 #include "clang/Lex/PPEmbedParameters.h"
 #include "clang/Lex/Token.h"
 #include "clang/Lex/TokenLexer.h"
+#include "clang/Support/Compiler.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
@@ -3060,4 +3061,8 @@ using PragmaHandlerRegistry = llvm::Registry<PragmaHandler>;
 
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI Registry<clang::PragmaHandler>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_LEX_PREPROCESSOR_H
diff --git a/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h b/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h
index 8c58ad926a402a..e6bcac542b0ecb 100644
--- a/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h
+++ b/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
 #define LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
 
+#include "clang/Support/Compiler.h"
 #include "clang/Tooling/CompilationDatabase.h"
 #include "llvm/Support/Registry.h"
 
@@ -42,4 +43,9 @@ using CompilationDatabasePluginRegistry =
 } // namespace tooling
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI
+    Registry<clang::tooling::CompilationDatabasePlugin>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
diff --git a/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h b/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h
index 5304ff26252def..8d54583234684e 100644
--- a/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h
+++ b/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
 #define LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
 
+#include "clang/Support/Compiler.h"
 #include "clang/Tooling/Execution.h"
 #include "llvm/Support/Registry.h"
 
@@ -20,4 +21,9 @@ using ToolExecutorPluginRegistry = llvm::Registry<ToolExecutorPlugin>;
 } // namespace tooling
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI
+    Registry<clang::tooling::ToolExecutorPlugin>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
diff --git a/flang/include/flang/Frontend/FrontendPluginRegistry.h b/flang/include/flang/Frontend/FrontendPluginRegistry.h
index 8b1f576c39e24a..a8079dbfaf8693 100644
--- a/flang/include/flang/Frontend/FrontendPluginRegistry.h
+++ b/flang/include/flang/Frontend/FrontendPluginRegistry.h
@@ -25,4 +25,8 @@ using FrontendPluginRegistry = llvm::Registry<PluginParseTreeAction>;
 
 } // namespace Fortran::frontend
 
+namespace llvm {
+extern template class Registry<Fortran::frontend::PluginParseTreeAction>;
+}
+
 #endif // FORTRAN_FRONTEND_FRONTENDPLUGINREGISTRY_H
diff --git a/llvm/include/llvm/CodeGen/GCMetadataPrinter.h b/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
index f9527c9f8752e9..9d421be8313f01 100644
--- a/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
+++ b/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
@@ -34,6 +34,8 @@ class StackMaps;
 /// defaults from Registry.
 using GCMetadataPrinterRegistry = Registry<GCMetadataPrinter>;
 
+extern template class LLVM_TEMPLATE_ABI Registry<GCMetadataPrinter>;
+
 /// GCMetadataPrinter - Emits GC metadata as assembly code.  Instances are
 /// created, managed, and owned by the AsmPrinter.
 class GCMetadataPrinter {
diff --git a/llvm/include/llvm/IR/GCStrategy.h b/llvm/include/llvm/IR/GCStrategy.h
index 3186465f001812..cbfbe23aaa0683 100644
--- a/llvm/include/llvm/IR/GCStrategy.h
+++ b/llvm/include/llvm/IR/GCStrategy.h
@@ -141,6 +141,8 @@ class GCStrategy {
 /// GCMetadataPrinterRegistery as well.
 using GCRegistry = Registry<GCStrategy>;
 
+extern template class LLVM_TEMPLATE_ABI Registry<GCStrategy>;
+
 /// Lookup the GCStrategy object associated with the given gc name.
 std::unique_ptr<GCStrategy> getGCStrategy(const StringRef Name);
 
diff --git a/llvm/include/llvm/Support/Compiler.h b/llvm/include/llvm/Support/Compiler.h
index 1d2d751d4dc11a..ab0cbff43d749c 100644
--- a/llvm/include/llvm/Support/Compiler.h
+++ b/llvm/include/llvm/Support/Compiler.h
@@ -153,6 +153,12 @@
 /// exported when llvm is built as a shared library with everything else that is
 /// unannotated will have internal visibility.
 ///
+/// LLVM_ABI_EXPORT is for the special case for things like plugin symbol
+/// declarations or definitions where we don't want the macro to be switching
+/// between dllexport and dllimport on windows based on what codebase is being
+/// built, it will only be dllexport. For non windows platforms this macro
+/// behaves the same as LLVM_ABI.
+///
 /// LLVM_EXPORT_TEMPLATE is used on explicit template instantiations in source
 /// files that were declared extern in a header. This macro is only set as a
 /// compiler export attribute on windows, on other platforms it does nothing.
@@ -179,6 +185,7 @@
 #define LLVM_ABI
 #define LLVM_TEMPLATE_ABI
 #define LLVM_EXPORT_TEMPLATE
+#define LLVM_ABI_EXPORT
 #elif defined(_WIN32) && !defined(__MINGW32__)
 #if defined(LLVM_EXPORTS)
 #define LLVM_ABI __declspec(dllexport)
@@ -189,19 +196,23 @@
 #define LLVM_TEMPLATE_ABI __declspec(dllimport)
 #define LLVM_EXPORT_TEMPLATE
 #endif
+#define LLVM_ABI_EXPORT __declspec(dllexport)
 #elif defined(__ELF__) || defined(__MINGW32__) || defined(_AIX)
 #define LLVM_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #define LLVM_TEMPLATE_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #define LLVM_EXPORT_TEMPLATE
+#define LLVM_ABI_EXPORT LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #elif defined(__MACH__) || defined(__WASM__)
 #define LLVM_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #define LLVM_TEMPLATE_ABI
 #define LLVM_EXPORT_TEMPLATE
+#define LLVM_ABI_EXPORT LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #endif
 #else
 #define LLVM_ABI
 #define LLVM_TEMPLATE_ABI
 #define LLVM_EXPORT_TEMPLATE
+#define LLVM_ABI_EXPORT
 #endif
 #define LLVM_C_ABI LLVM_ABI
 #endif
diff --git a/llvm/include/llvm/Support/Registry.h b/llvm/include/llvm/Support/Registry.h
index 5bb6a254a47f4c..ff9226c39359c5 100644
--- a/llvm/include/llvm/Support/Registry.h
+++ b/llvm/include/llvm/Support/Registry.h
@@ -53,7 +53,13 @@ namespace llvm {
     Registry() = delete;
 
     friend class node;
-    static node *Head, *Tail;
+    // These must be must two separate declarations to workaround a 20 year
+    // old MSVC bug with dllexport and multiple static fields in the same
+    // declaration causing error C2487 "member of dll interface class may not
+    // be declared with dll interface".
+    // https://developercommunity.visualstudio.com/t/c2487-in-dllexport-class-with-static-members/69878
+    static node *Head;
+    static node *Tail;
 
   public:
     /// Node in linked list of entries.
@@ -76,7 +82,13 @@ namespace llvm {
     /// add a node to the executable's registry. Therefore it's not defined here
     /// to avoid it being instantiated in the plugin and is instead defined in
     /// the executable (see LLVM_INSTANTIATE_REGISTRY below).
-    static void add_node(node *N);
+    static void add_node(node *N) {
+      if (Tail)
+        Tail->Next = N;
+      else
+        Head = N;
+      Tail = N;
+    }
 
     /// Iterators for registry entries.
     ///
@@ -95,7 +107,7 @@ namespace llvm {
 
     // begin is not defined here in order to avoid usage of an undefined static
     // data member, instead it's instantiated by LLVM_INSTANTIATE_REGISTRY.
-    static iterator begin();
+    static iterator begin() { return iterator(Head); }
     static iterator end()   { return iterator(nullptr); }
 
     static iterator_range<iterator> entries() {
@@ -124,36 +136,28 @@ namespace llvm {
       }
     };
   };
+
 } // end namespace llvm
 
+#ifdef _WIN32
 /// Instantiate a registry class.
-///
-/// This provides template definitions of add_node, begin, and the Head and Tail
-/// pointers, then explicitly instantiates them. We could explicitly specialize
-/// them, instead of the two-step process of define then instantiate, but
-/// strictly speaking that's not allowed by the C++ standard (we would need to
-/// have explicit specialization declarations in all translation units where the
-/// specialization is used) so we don't.
-#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS) \
-  namespace llvm { \
-  template<typename T> typename Registry<T>::node *Registry<T>::Head = nullptr;\
-  template<typename T> typename Registry<T>::node *Registry<T>::Tail = nullptr;\
-  template<typename T> \
-  void Registry<T>::add_node(typename Registry<T>::node *N) { \
-    if (Tail) \
-      Tail->Next = N; \
-    else \
-      Head = N; \
-    Tail = N; \
-  } \
-  template<typename T> typename Registry<T>::iterator Registry<T>::begin() { \
-    return iterator(Head); \
-  } \
-  template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Head; \
-  template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Tail; \
-  template \
-  void Registry<REGISTRY_CLASS::type>::add_node(REGISTRY_CLASS::node*); \
-  template REGISTRY_CLASS::iterator Registry<REGISTRY_CLASS::type>::begin(); \
+#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS)                              \
+  namespace llvm {                                                             \
+  template <typename T>                                                        \
+  typename Registry<T>::node *Registry<T>::Head = nullptr;                     \
+  template <typename T>                                                        \
+  typename Registry<T>::node *Registry<T>::Tail = nullptr;                     \
+  template class LLVM_ABI_EXPORT Registry<REGISTRY_CLASS::type>;               \
+  }
+#else
+#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS)                              \
+  namespace llvm {                                                             \
+  template <typename T>                                                        \
+  typename Registry<T>::node *Registry<T>::Head = nullptr;                     \
+  template <typename T>                                                        \
+  typename Registry<T>::node *Registry<T>::Tail = nullptr;                     \
+  template class Registry<REGISTRY_CLASS::type>;                               \
   }
+#endif
 
 #endif // LLVM_SUPPORT_REGISTRY_H

@llvmbot
Copy link
Member

llvmbot commented Oct 17, 2024

@llvm/pr-subscribers-clang-tidy

Author: Thomas Fransham (fsfod)

Changes

Fix missing extern templates for llvm::Registry use in other projects of llvm

Windows doesn't implicitly import and merge exported symbols across shared libraries
like Linux does so we need to explicitly export/import each instantiation of llvm::Registry.
Updated LLVM_INSTANTIATE_REGISTRY to just be a full explicit template instantiation.

This is part of the work to enable LLVM_BUILD_LLVM_DYLIB and LLVM plugins on window.


Full diff: https://github.com/llvm/llvm-project/pull/112640.diff

15 Files Affected:

  • (modified) clang-tools-extra/clang-doc/Generators.h (+4)
  • (modified) clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h (+4)
  • (modified) clang-tools-extra/clangd/URI.h (+4)
  • (modified) clang-tools-extra/clangd/refactor/Tweak.h (+4)
  • (modified) clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h (+4)
  • (modified) clang/include/clang/Basic/ParsedAttrInfo.h (+5)
  • (modified) clang/include/clang/Frontend/FrontendPluginRegistry.h (+5)
  • (modified) clang/include/clang/Lex/Preprocessor.h (+5)
  • (modified) clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h (+6)
  • (modified) clang/include/clang/Tooling/ToolExecutorPluginRegistry.h (+6)
  • (modified) flang/include/flang/Frontend/FrontendPluginRegistry.h (+4)
  • (modified) llvm/include/llvm/CodeGen/GCMetadataPrinter.h (+2)
  • (modified) llvm/include/llvm/IR/GCStrategy.h (+2)
  • (modified) llvm/include/llvm/Support/Compiler.h (+11)
  • (modified) llvm/include/llvm/Support/Registry.h (+34-30)
diff --git a/clang-tools-extra/clang-doc/Generators.h b/clang-tools-extra/clang-doc/Generators.h
index ba0ef64d3d0f5f..d62d7faa9a69f3 100644
--- a/clang-tools-extra/clang-doc/Generators.h
+++ b/clang-tools-extra/clang-doc/Generators.h
@@ -55,4 +55,8 @@ std::string getTagType(TagTypeKind AS);
 } // namespace doc
 } // namespace clang
 
+namespace llvm {
+extern template class Registry<clang::doc::Generator>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_GENERATOR_H
diff --git a/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h b/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h
index 78d914bfedbc94..8a07b05c26446c 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h
@@ -18,4 +18,8 @@ using ClangTidyModuleRegistry = llvm::Registry<ClangTidyModule>;
 
 } // namespace clang::tidy
 
+namespace llvm {
+extern template class Registry<clang::tidy::ClangTidyModule>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYMODULEREGISTRY_H
diff --git a/clang-tools-extra/clangd/URI.h b/clang-tools-extra/clangd/URI.h
index 7f3bc9d1645a8f..d4629f17551cca 100644
--- a/clang-tools-extra/clangd/URI.h
+++ b/clang-tools-extra/clangd/URI.h
@@ -133,4 +133,8 @@ typedef llvm::Registry<URIScheme> URISchemeRegistry;
 } // namespace clangd
 } // namespace clang
 
+namespace llvm {
+extern template class Registry<clang::clangd::URIScheme>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_URI_H
diff --git a/clang-tools-extra/clangd/refactor/Tweak.h b/clang-tools-extra/clangd/refactor/Tweak.h
index 2769b401d89439..257f44a285f88a 100644
--- a/clang-tools-extra/clangd/refactor/Tweak.h
+++ b/clang-tools-extra/clangd/refactor/Tweak.h
@@ -147,4 +147,8 @@ prepareTweak(StringRef ID, const Tweak::Selection &S,
 } // namespace clangd
 } // namespace clang
 
+namespace llvm {
+extern template class Registry<clang::clangd::Tweak>;
+} // namespace llvm
+
 #endif
diff --git a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h
index 98aee5f277cf18..b07b9ed1ac25f5 100644
--- a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h
+++ b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/IncludeSpeller.h
@@ -46,4 +46,8 @@ using IncludeSpellingStrategy = llvm::Registry<IncludeSpeller>;
 std::string spellHeader(const IncludeSpeller::Input &Input);
 } // namespace clang::include_cleaner
 
+namespace llvm {
+extern template class Registry<clang::include_cleaner::IncludeSpeller>;
+} // namespace llvm
+
 #endif
diff --git a/clang/include/clang/Basic/ParsedAttrInfo.h b/clang/include/clang/Basic/ParsedAttrInfo.h
index fab5c6f1377d27..3b5f5d3c3f92ac 100644
--- a/clang/include/clang/Basic/ParsedAttrInfo.h
+++ b/clang/include/clang/Basic/ParsedAttrInfo.h
@@ -17,6 +17,7 @@
 
 #include "clang/Basic/AttrSubjectMatchRules.h"
 #include "clang/Basic/AttributeCommonInfo.h"
+#include "clang/Support/Compiler.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/Registry.h"
 #include <climits>
@@ -175,4 +176,8 @@ const std::list<std::unique_ptr<ParsedAttrInfo>> &getAttributePluginInstances();
 
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI Registry<clang::ParsedAttrInfo>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_BASIC_PARSEDATTRINFO_H
diff --git a/clang/include/clang/Frontend/FrontendPluginRegistry.h b/clang/include/clang/Frontend/FrontendPluginRegistry.h
index 810578534acb45..5eea9c2fd89a32 100644
--- a/clang/include/clang/Frontend/FrontendPluginRegistry.h
+++ b/clang/include/clang/Frontend/FrontendPluginRegistry.h
@@ -14,6 +14,7 @@
 #define LLVM_CLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H
 
 #include "clang/Frontend/FrontendAction.h"
+#include "clang/Support/Compiler.h"
 #include "llvm/Support/Registry.h"
 
 namespace clang {
@@ -23,4 +24,8 @@ using FrontendPluginRegistry = llvm::Registry<PluginASTAction>;
 
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI Registry<clang::PluginASTAction>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 4643b0213815f8..92749e4de44b57 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -32,6 +32,7 @@
 #include "clang/Lex/PPEmbedParameters.h"
 #include "clang/Lex/Token.h"
 #include "clang/Lex/TokenLexer.h"
+#include "clang/Support/Compiler.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
@@ -3060,4 +3061,8 @@ using PragmaHandlerRegistry = llvm::Registry<PragmaHandler>;
 
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI Registry<clang::PragmaHandler>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_LEX_PREPROCESSOR_H
diff --git a/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h b/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h
index 8c58ad926a402a..e6bcac542b0ecb 100644
--- a/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h
+++ b/clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
 #define LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
 
+#include "clang/Support/Compiler.h"
 #include "clang/Tooling/CompilationDatabase.h"
 #include "llvm/Support/Registry.h"
 
@@ -42,4 +43,9 @@ using CompilationDatabasePluginRegistry =
 } // namespace tooling
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI
+    Registry<clang::tooling::CompilationDatabasePlugin>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
diff --git a/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h b/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h
index 5304ff26252def..8d54583234684e 100644
--- a/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h
+++ b/clang/include/clang/Tooling/ToolExecutorPluginRegistry.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
 #define LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
 
+#include "clang/Support/Compiler.h"
 #include "clang/Tooling/Execution.h"
 #include "llvm/Support/Registry.h"
 
@@ -20,4 +21,9 @@ using ToolExecutorPluginRegistry = llvm::Registry<ToolExecutorPlugin>;
 } // namespace tooling
 } // namespace clang
 
+namespace llvm {
+extern template class CLANG_TEMPLATE_ABI
+    Registry<clang::tooling::ToolExecutorPlugin>;
+} // namespace llvm
+
 #endif // LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
diff --git a/flang/include/flang/Frontend/FrontendPluginRegistry.h b/flang/include/flang/Frontend/FrontendPluginRegistry.h
index 8b1f576c39e24a..a8079dbfaf8693 100644
--- a/flang/include/flang/Frontend/FrontendPluginRegistry.h
+++ b/flang/include/flang/Frontend/FrontendPluginRegistry.h
@@ -25,4 +25,8 @@ using FrontendPluginRegistry = llvm::Registry<PluginParseTreeAction>;
 
 } // namespace Fortran::frontend
 
+namespace llvm {
+extern template class Registry<Fortran::frontend::PluginParseTreeAction>;
+}
+
 #endif // FORTRAN_FRONTEND_FRONTENDPLUGINREGISTRY_H
diff --git a/llvm/include/llvm/CodeGen/GCMetadataPrinter.h b/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
index f9527c9f8752e9..9d421be8313f01 100644
--- a/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
+++ b/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
@@ -34,6 +34,8 @@ class StackMaps;
 /// defaults from Registry.
 using GCMetadataPrinterRegistry = Registry<GCMetadataPrinter>;
 
+extern template class LLVM_TEMPLATE_ABI Registry<GCMetadataPrinter>;
+
 /// GCMetadataPrinter - Emits GC metadata as assembly code.  Instances are
 /// created, managed, and owned by the AsmPrinter.
 class GCMetadataPrinter {
diff --git a/llvm/include/llvm/IR/GCStrategy.h b/llvm/include/llvm/IR/GCStrategy.h
index 3186465f001812..cbfbe23aaa0683 100644
--- a/llvm/include/llvm/IR/GCStrategy.h
+++ b/llvm/include/llvm/IR/GCStrategy.h
@@ -141,6 +141,8 @@ class GCStrategy {
 /// GCMetadataPrinterRegistery as well.
 using GCRegistry = Registry<GCStrategy>;
 
+extern template class LLVM_TEMPLATE_ABI Registry<GCStrategy>;
+
 /// Lookup the GCStrategy object associated with the given gc name.
 std::unique_ptr<GCStrategy> getGCStrategy(const StringRef Name);
 
diff --git a/llvm/include/llvm/Support/Compiler.h b/llvm/include/llvm/Support/Compiler.h
index 1d2d751d4dc11a..ab0cbff43d749c 100644
--- a/llvm/include/llvm/Support/Compiler.h
+++ b/llvm/include/llvm/Support/Compiler.h
@@ -153,6 +153,12 @@
 /// exported when llvm is built as a shared library with everything else that is
 /// unannotated will have internal visibility.
 ///
+/// LLVM_ABI_EXPORT is for the special case for things like plugin symbol
+/// declarations or definitions where we don't want the macro to be switching
+/// between dllexport and dllimport on windows based on what codebase is being
+/// built, it will only be dllexport. For non windows platforms this macro
+/// behaves the same as LLVM_ABI.
+///
 /// LLVM_EXPORT_TEMPLATE is used on explicit template instantiations in source
 /// files that were declared extern in a header. This macro is only set as a
 /// compiler export attribute on windows, on other platforms it does nothing.
@@ -179,6 +185,7 @@
 #define LLVM_ABI
 #define LLVM_TEMPLATE_ABI
 #define LLVM_EXPORT_TEMPLATE
+#define LLVM_ABI_EXPORT
 #elif defined(_WIN32) && !defined(__MINGW32__)
 #if defined(LLVM_EXPORTS)
 #define LLVM_ABI __declspec(dllexport)
@@ -189,19 +196,23 @@
 #define LLVM_TEMPLATE_ABI __declspec(dllimport)
 #define LLVM_EXPORT_TEMPLATE
 #endif
+#define LLVM_ABI_EXPORT __declspec(dllexport)
 #elif defined(__ELF__) || defined(__MINGW32__) || defined(_AIX)
 #define LLVM_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #define LLVM_TEMPLATE_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #define LLVM_EXPORT_TEMPLATE
+#define LLVM_ABI_EXPORT LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #elif defined(__MACH__) || defined(__WASM__)
 #define LLVM_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #define LLVM_TEMPLATE_ABI
 #define LLVM_EXPORT_TEMPLATE
+#define LLVM_ABI_EXPORT LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
 #endif
 #else
 #define LLVM_ABI
 #define LLVM_TEMPLATE_ABI
 #define LLVM_EXPORT_TEMPLATE
+#define LLVM_ABI_EXPORT
 #endif
 #define LLVM_C_ABI LLVM_ABI
 #endif
diff --git a/llvm/include/llvm/Support/Registry.h b/llvm/include/llvm/Support/Registry.h
index 5bb6a254a47f4c..ff9226c39359c5 100644
--- a/llvm/include/llvm/Support/Registry.h
+++ b/llvm/include/llvm/Support/Registry.h
@@ -53,7 +53,13 @@ namespace llvm {
     Registry() = delete;
 
     friend class node;
-    static node *Head, *Tail;
+    // These must be must two separate declarations to workaround a 20 year
+    // old MSVC bug with dllexport and multiple static fields in the same
+    // declaration causing error C2487 "member of dll interface class may not
+    // be declared with dll interface".
+    // https://developercommunity.visualstudio.com/t/c2487-in-dllexport-class-with-static-members/69878
+    static node *Head;
+    static node *Tail;
 
   public:
     /// Node in linked list of entries.
@@ -76,7 +82,13 @@ namespace llvm {
     /// add a node to the executable's registry. Therefore it's not defined here
     /// to avoid it being instantiated in the plugin and is instead defined in
     /// the executable (see LLVM_INSTANTIATE_REGISTRY below).
-    static void add_node(node *N);
+    static void add_node(node *N) {
+      if (Tail)
+        Tail->Next = N;
+      else
+        Head = N;
+      Tail = N;
+    }
 
     /// Iterators for registry entries.
     ///
@@ -95,7 +107,7 @@ namespace llvm {
 
     // begin is not defined here in order to avoid usage of an undefined static
     // data member, instead it's instantiated by LLVM_INSTANTIATE_REGISTRY.
-    static iterator begin();
+    static iterator begin() { return iterator(Head); }
     static iterator end()   { return iterator(nullptr); }
 
     static iterator_range<iterator> entries() {
@@ -124,36 +136,28 @@ namespace llvm {
       }
     };
   };
+
 } // end namespace llvm
 
+#ifdef _WIN32
 /// Instantiate a registry class.
-///
-/// This provides template definitions of add_node, begin, and the Head and Tail
-/// pointers, then explicitly instantiates them. We could explicitly specialize
-/// them, instead of the two-step process of define then instantiate, but
-/// strictly speaking that's not allowed by the C++ standard (we would need to
-/// have explicit specialization declarations in all translation units where the
-/// specialization is used) so we don't.
-#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS) \
-  namespace llvm { \
-  template<typename T> typename Registry<T>::node *Registry<T>::Head = nullptr;\
-  template<typename T> typename Registry<T>::node *Registry<T>::Tail = nullptr;\
-  template<typename T> \
-  void Registry<T>::add_node(typename Registry<T>::node *N) { \
-    if (Tail) \
-      Tail->Next = N; \
-    else \
-      Head = N; \
-    Tail = N; \
-  } \
-  template<typename T> typename Registry<T>::iterator Registry<T>::begin() { \
-    return iterator(Head); \
-  } \
-  template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Head; \
-  template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Tail; \
-  template \
-  void Registry<REGISTRY_CLASS::type>::add_node(REGISTRY_CLASS::node*); \
-  template REGISTRY_CLASS::iterator Registry<REGISTRY_CLASS::type>::begin(); \
+#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS)                              \
+  namespace llvm {                                                             \
+  template <typename T>                                                        \
+  typename Registry<T>::node *Registry<T>::Head = nullptr;                     \
+  template <typename T>                                                        \
+  typename Registry<T>::node *Registry<T>::Tail = nullptr;                     \
+  template class LLVM_ABI_EXPORT Registry<REGISTRY_CLASS::type>;               \
+  }
+#else
+#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS)                              \
+  namespace llvm {                                                             \
+  template <typename T>                                                        \
+  typename Registry<T>::node *Registry<T>::Head = nullptr;                     \
+  template <typename T>                                                        \
+  typename Registry<T>::node *Registry<T>::Tail = nullptr;                     \
+  template class Registry<REGISTRY_CLASS::type>;                               \
   }
+#endif
 
 #endif // LLVM_SUPPORT_REGISTRY_H

@vgvassilev vgvassilev merged commit b735c66 into llvm:main Oct 22, 2024
18 checks passed
EricWF pushed a commit to efcs/llvm-project that referenced this pull request Oct 22, 2024
…on windows' (llvm#109024) (llvm#112640)

Fix missing extern templates for llvm::Registry use in other projects of
llvm

Windows doesn't implicitly import and merge exported symbols across
shared libraries
like Linux does so we need to explicitly export/import each
instantiation of llvm::Registry.
Updated LLVM_INSTANTIATE_REGISTRY to just be a full explicit template
instantiation.

This is part of the work to enable LLVM_BUILD_LLVM_DYLIB and LLVM
plugins on window.
@nico
Copy link
Contributor

nico commented Oct 24, 2024

This seems to break building of clang-tools-extra binaries: http://45.33.8.238/win/95986/step_3.txt

Please take a look and revert for now if it takes a while to fix.

@fsfod
Copy link
Contributor Author

fsfod commented Oct 24, 2024

Its strange that visibility macros are enabled for windows but its not a shared library build, idk if the gn build script need to be manually updated to define the macros correctly to turn off visibility macros by default.

@fsfod
Copy link
Contributor Author

fsfod commented Oct 24, 2024

The fix for the gn build system would be to unconditionally define CLANG_BUILD_STATIC for the windows platform for now.

@fsfod fsfod deleted the exported-api/llvm-registry branch December 2, 2024 11:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category clang-tidy clang-tools-extra clangd flang:driver flang Flang issues not falling into any other category llvm:ir llvm:support
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants