https://github.com/steakhal created https://github.com/llvm/llvm-project/pull/173290
This patch adds the TUSummaryExtractorRegistry for plugging in custom summary extractors. This also adds a fake TUSummaryBuilder to observe the side effects of inserting into the registry. The original TUSummaryBuilder class will be used to create EntityIDs and to map those to summary "facts" in the shape of "TUSummaryData" objects, but that part is not yet upstreamed. The important point is that TUSummaryBuilders have a use beyond just testing. From 00ba5665f95846d4ac8c567bf95f3db1e7f3d466 Mon Sep 17 00:00:00 2001 From: Balazs Benics <[email protected]> Date: Mon, 22 Dec 2025 18:39:58 +0100 Subject: [PATCH] [clang][ssaf] Add the TUSummaryExtractorRegistry This patch adds the TUSummaryExtractorRegistry for plugging in custom summary extractors. This also adds a fake TUSummaryBuilder to observe the side effects of inserting into the registry. The original TUSummaryBuilder class will be used to create EntityIDs and to map those to summary "facts" in the shape of "TUSummaryData" objects, but that part is not yet upstreamed. The important point is that TUSummaryBuilders have a use beyond just testing. --- .../Scalable/TUSummary/ExtractorRegistry.h | 42 ++++ .../Scalable/TUSummary/TUSummaryBuilder.h | 20 ++ .../Scalable/TUSummary/TUSummaryExtractor.h | 28 +++ clang/lib/Analysis/Scalable/CMakeLists.txt | 1 + .../Scalable/TUSummary/ExtractorRegistry.cpp | 37 ++++ .../Analysis/Scalable/CMakeLists.txt | 3 + .../Registries/MockSummaryExtractor1.cpp | 44 ++++ .../Registries/MockSummaryExtractor2.cpp | 44 ++++ .../Registries/MockTUSummaryBuilder.h | 25 +++ .../SummaryExtractorRegistryTest.cpp | 99 +++++++++ llvm/include/llvm/Support/Registry.h | 205 +++++++++--------- 11 files changed, 447 insertions(+), 101 deletions(-) create mode 100644 clang/include/clang/Analysis/Scalable/TUSummary/ExtractorRegistry.h create mode 100644 clang/include/clang/Analysis/Scalable/TUSummary/TUSummaryBuilder.h create mode 100644 clang/include/clang/Analysis/Scalable/TUSummary/TUSummaryExtractor.h create mode 100644 clang/lib/Analysis/Scalable/TUSummary/ExtractorRegistry.cpp create mode 100644 clang/unittests/Analysis/Scalable/Registries/MockSummaryExtractor1.cpp create mode 100644 clang/unittests/Analysis/Scalable/Registries/MockSummaryExtractor2.cpp create mode 100644 clang/unittests/Analysis/Scalable/Registries/MockTUSummaryBuilder.h create mode 100644 clang/unittests/Analysis/Scalable/Registries/SummaryExtractorRegistryTest.cpp diff --git a/clang/include/clang/Analysis/Scalable/TUSummary/ExtractorRegistry.h b/clang/include/clang/Analysis/Scalable/TUSummary/ExtractorRegistry.h new file mode 100644 index 0000000000000..704fe54ce5edd --- /dev/null +++ b/clang/include/clang/Analysis/Scalable/TUSummary/ExtractorRegistry.h @@ -0,0 +1,42 @@ +//===- ExtractorRegistry.h --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Registry for TUSummaryExtractors, and some helper functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_TUSUMMARY_EXTRACTORREGISTRY_H +#define LLVM_CLANG_ANALYSIS_SCALABLE_TUSUMMARY_EXTRACTORREGISTRY_H + +#include "clang/Analysis/Scalable/TUSummary/TUSummaryExtractor.h" +#include "clang/Support/Compiler.h" +#include "llvm/Support/Registry.h" + +namespace clang::ssaf { +class SummaryName; +class TUSummaryBuilder; + +/// Check if a TUSummaryExtractor was registered with a given name. +bool isTUSummaryExtractorRegistered(const SummaryName &Name); + +/// Try to instantiate a TUSummaryExtractor with a given name. +std::unique_ptr<ASTConsumer> makeTUSummaryExtractor(const SummaryName &Name, + TUSummaryBuilder &Builder); + +// Registry for adding new TUSummaryExtractor implementations. +using TUSummaryExtractorRegistry = + llvm::Registry<TUSummaryExtractor, TUSummaryBuilder &>; + +} // namespace clang::ssaf + +namespace llvm { +extern template class CLANG_TEMPLATE_ABI + Registry<clang::ssaf::TUSummaryExtractorRegistry>; +} // namespace llvm + +#endif // LLVM_CLANG_ANALYSIS_SCALABLE_TUSUMMARY_EXTRACTORREGISTRY_H diff --git a/clang/include/clang/Analysis/Scalable/TUSummary/TUSummaryBuilder.h b/clang/include/clang/Analysis/Scalable/TUSummary/TUSummaryBuilder.h new file mode 100644 index 0000000000000..fa679c145faa5 --- /dev/null +++ b/clang/include/clang/Analysis/Scalable/TUSummary/TUSummaryBuilder.h @@ -0,0 +1,20 @@ +//===- TUSummaryBuilder.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_TUSUMMARY_TUSUMMARYBUILDER_H +#define LLVM_CLANG_ANALYSIS_SCALABLE_TUSUMMARY_TUSUMMARYBUILDER_H + +namespace clang::ssaf { + +class TUSummaryBuilder { + // Empty for now. +}; + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_ANALYSIS_SCALABLE_TUSUMMARY_TUSUMMARYBUILDER_H diff --git a/clang/include/clang/Analysis/Scalable/TUSummary/TUSummaryExtractor.h b/clang/include/clang/Analysis/Scalable/TUSummary/TUSummaryExtractor.h new file mode 100644 index 0000000000000..7734d97fcd24b --- /dev/null +++ b/clang/include/clang/Analysis/Scalable/TUSummary/TUSummaryExtractor.h @@ -0,0 +1,28 @@ +//===- TUSummaryExtractor.h -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_TUSUMMARY_TUSUMMARYEXTRACTOR_H +#define LLVM_CLANG_ANALYSIS_SCALABLE_TUSUMMARY_TUSUMMARYEXTRACTOR_H + +#include "clang/AST/ASTConsumer.h" + +namespace clang::ssaf { +class TUSummaryBuilder; + +class TUSummaryExtractor : public ASTConsumer { +public: + explicit TUSummaryExtractor(TUSummaryBuilder &Builder) + : SummaryBuilder(Builder) {} + +protected: + TUSummaryBuilder &SummaryBuilder; +}; + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_ANALYSIS_SCALABLE_TUSUMMARY_TUSUMMARYEXTRACTOR_H diff --git a/clang/lib/Analysis/Scalable/CMakeLists.txt b/clang/lib/Analysis/Scalable/CMakeLists.txt index ea4693f102cb2..5ffac277dc697 100644 --- a/clang/lib/Analysis/Scalable/CMakeLists.txt +++ b/clang/lib/Analysis/Scalable/CMakeLists.txt @@ -6,6 +6,7 @@ add_clang_library(clangAnalysisScalable ASTEntityMapping.cpp Model/BuildNamespace.cpp Model/EntityName.cpp + TUSummary/ExtractorRegistry.cpp LINK_LIBS clangAST diff --git a/clang/lib/Analysis/Scalable/TUSummary/ExtractorRegistry.cpp b/clang/lib/Analysis/Scalable/TUSummary/ExtractorRegistry.cpp new file mode 100644 index 0000000000000..461de82b86150 --- /dev/null +++ b/clang/lib/Analysis/Scalable/TUSummary/ExtractorRegistry.cpp @@ -0,0 +1,37 @@ +//===- ExtractorRegistry.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Scalable/TUSummary/ExtractorRegistry.h" +#include "clang/Analysis/Scalable/Model/SummaryName.h" +#include <memory> + +using namespace clang; +using namespace ssaf; + +LLVM_INSTANTIATE_REGISTRY(TUSummaryExtractorRegistry) + +bool ssaf::isTUSummaryExtractorRegistered(const SummaryName &Name) { + for (const auto &Entry : TUSummaryExtractorRegistry::entries()) { + if (Entry.getName() == Name.str()) { + return true; + } + } + return false; +} + +std::unique_ptr<ASTConsumer> +ssaf::makeTUSummaryExtractor(const SummaryName &Name, + TUSummaryBuilder &Builder) { + for (const auto &Entry : TUSummaryExtractorRegistry::entries()) { + if (Entry.getName() == Name.str()) { + return Entry.instantiate(Builder); + } + } + assert(false && "Unknown SummaryExtractor name"); + return nullptr; +} diff --git a/clang/unittests/Analysis/Scalable/CMakeLists.txt b/clang/unittests/Analysis/Scalable/CMakeLists.txt index c2be6debddae4..656954c363ac8 100644 --- a/clang/unittests/Analysis/Scalable/CMakeLists.txt +++ b/clang/unittests/Analysis/Scalable/CMakeLists.txt @@ -2,6 +2,9 @@ add_distinct_clang_unittest(ClangScalableAnalysisFrameworkTests ASTEntityMappingTest.cpp BuildNamespaceTest.cpp EntityNameTest.cpp + Registries/MockSummaryExtractor1.cpp + Registries/MockSummaryExtractor2.cpp + Registries/SummaryExtractorRegistryTest.cpp SummaryNameTest.cpp CLANG_LIBS diff --git a/clang/unittests/Analysis/Scalable/Registries/MockSummaryExtractor1.cpp b/clang/unittests/Analysis/Scalable/Registries/MockSummaryExtractor1.cpp new file mode 100644 index 0000000000000..ec31e2e16bc0a --- /dev/null +++ b/clang/unittests/Analysis/Scalable/Registries/MockSummaryExtractor1.cpp @@ -0,0 +1,44 @@ +//===- MockSummaryExtractor1.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MockTUSummaryBuilder.h" +#include "clang/AST/ASTContext.h" +#include "clang/Analysis/Scalable/TUSummary/ExtractorRegistry.h" +#include "clang/Analysis/Scalable/TUSummary/TUSummaryBuilder.h" + +using namespace clang; +using namespace ssaf; + +namespace { +class MockSummaryExtractor1 : public TUSummaryExtractor { +public: + MockSummaryExtractor1(TUSummaryBuilder &Builder) + : TUSummaryExtractor(Builder) { + getFakeBuilder().sendMessage( + "MockSummaryExtractor1 constructor was invoked"); + } + + ~MockSummaryExtractor1() { + getFakeBuilder().sendMessage( + "MockSummaryExtractor1 destructor was invoked"); + } + + void HandleTranslationUnit(ASTContext &Ctx) override { + getFakeBuilder().sendMessage( + "MockSummaryExtractor1 HandleTranslationUnit was invoked"); + } + + MockTUSummaryBuilder &getFakeBuilder() { + return static_cast<MockTUSummaryBuilder &>(SummaryBuilder); + } +}; + +static TUSummaryExtractorRegistry::Add<MockSummaryExtractor1> + RegisterExtractor("MockSummaryExtractor1", "Mock summary extractor 1"); + +} // namespace diff --git a/clang/unittests/Analysis/Scalable/Registries/MockSummaryExtractor2.cpp b/clang/unittests/Analysis/Scalable/Registries/MockSummaryExtractor2.cpp new file mode 100644 index 0000000000000..90127a160bfa9 --- /dev/null +++ b/clang/unittests/Analysis/Scalable/Registries/MockSummaryExtractor2.cpp @@ -0,0 +1,44 @@ +//===- MockSummaryExtractor2.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MockTUSummaryBuilder.h" +#include "clang/AST/ASTContext.h" +#include "clang/Analysis/Scalable/TUSummary/ExtractorRegistry.h" +#include "clang/Analysis/Scalable/TUSummary/TUSummaryBuilder.h" + +using namespace clang; +using namespace ssaf; + +namespace { +class MockSummaryExtractor2 : public TUSummaryExtractor { +public: + MockSummaryExtractor2(TUSummaryBuilder &Builder) + : TUSummaryExtractor(Builder) { + getFakeBuilder().sendMessage( + "MockSummaryExtractor2 constructor was invoked"); + } + + ~MockSummaryExtractor2() { + getFakeBuilder().sendMessage( + "MockSummaryExtractor2 destructor was invoked"); + } + + void HandleTranslationUnit(ASTContext &Ctx) override { + getFakeBuilder().sendMessage( + "MockSummaryExtractor2 HandleTranslationUnit was invoked"); + } + + MockTUSummaryBuilder &getFakeBuilder() { + return static_cast<MockTUSummaryBuilder &>(SummaryBuilder); + } +}; + +static TUSummaryExtractorRegistry::Add<MockSummaryExtractor2> + RegisterExtractor("MockSummaryExtractor2", "Mock summary extractor 2"); + +} // namespace diff --git a/clang/unittests/Analysis/Scalable/Registries/MockTUSummaryBuilder.h b/clang/unittests/Analysis/Scalable/Registries/MockTUSummaryBuilder.h new file mode 100644 index 0000000000000..ccb79ae042625 --- /dev/null +++ b/clang/unittests/Analysis/Scalable/Registries/MockTUSummaryBuilder.h @@ -0,0 +1,25 @@ +//===- MockTUSummaryBuilder.h -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Scalable/TUSummary/TUSummaryBuilder.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang::ssaf { + +class MockTUSummaryBuilder : public TUSummaryBuilder { +public: + void sendMessage(llvm::Twine Message) { Stream << Message << '\n'; } + std::string consumeMessages() { return std::move(OutputBuffer); } + +private: + std::string OutputBuffer; + llvm::raw_string_ostream Stream = llvm::raw_string_ostream{OutputBuffer}; +}; + +} // namespace clang::ssaf diff --git a/clang/unittests/Analysis/Scalable/Registries/SummaryExtractorRegistryTest.cpp b/clang/unittests/Analysis/Scalable/Registries/SummaryExtractorRegistryTest.cpp new file mode 100644 index 0000000000000..338f28b268633 --- /dev/null +++ b/clang/unittests/Analysis/Scalable/Registries/SummaryExtractorRegistryTest.cpp @@ -0,0 +1,99 @@ +//===- SummaryExtractorRegistryTest.cpp -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MockTUSummaryBuilder.h" +#include "clang/Analysis/Scalable/Model/SummaryName.h" +#include "clang/Analysis/Scalable/TUSummary/ExtractorRegistry.h" +#include "clang/Frontend/MultiplexConsumer.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/StringRef.h" +#include "gtest/gtest.h" +#include <memory> + +using namespace clang; +using namespace ssaf; + +namespace { + +TEST(SummaryExtractorRegistryTest, isTUSummaryExtractorRegistered) { + EXPECT_FALSE( + isTUSummaryExtractorRegistered(SummaryName("Non-existent-extractor"))); + EXPECT_TRUE( + isTUSummaryExtractorRegistered(SummaryName("MockSummaryExtractor1"))); + EXPECT_TRUE( + isTUSummaryExtractorRegistered(SummaryName("MockSummaryExtractor2"))); +} + +TEST(SummaryExtractorRegistryTest, EnumeratingRegistryEntries) { + std::set<llvm::StringRef> ActualNames; + for (const auto &Entry : TUSummaryExtractorRegistry::entries()) { + bool Inserted = ActualNames.insert(Entry.getName()).second; + EXPECT_TRUE(Inserted); + } + + EXPECT_EQ(ActualNames, (std::set<llvm::StringRef>{ + "MockSummaryExtractor1", + "MockSummaryExtractor2", + })); +} + +TEST(SummaryExtractorRegistryTest, InstantiatingExtractor1) { + MockTUSummaryBuilder FakeBuilder; + { + auto Consumer = makeTUSummaryExtractor(SummaryName{"MockSummaryExtractor1"}, + FakeBuilder); + EXPECT_TRUE(Consumer); + EXPECT_EQ(FakeBuilder.consumeMessages(), + "MockSummaryExtractor1 constructor was invoked\n"); + } + EXPECT_EQ(FakeBuilder.consumeMessages(), + "MockSummaryExtractor1 destructor was invoked\n"); +} + +TEST(SummaryExtractorRegistryTest, InstantiatingExtractor2) { + MockTUSummaryBuilder FakeBuilder; + { + auto Consumer = makeTUSummaryExtractor(SummaryName{"MockSummaryExtractor2"}, + FakeBuilder); + EXPECT_TRUE(Consumer); + EXPECT_EQ(FakeBuilder.consumeMessages(), + "MockSummaryExtractor2 constructor was invoked\n"); + } + EXPECT_EQ(FakeBuilder.consumeMessages(), + "MockSummaryExtractor2 destructor was invoked\n"); +} + +TEST(SummaryExtractorRegistryTest, InvokingExtractors) { + MockTUSummaryBuilder FakeBuilder; + std::vector<std::unique_ptr<ASTConsumer>> Consumers; + for (std::string Name : {"MockSummaryExtractor1", "MockSummaryExtractor2"}) { + auto Consumer = makeTUSummaryExtractor(SummaryName{Name}, FakeBuilder); + ASSERT_TRUE(Consumer); + Consumers.push_back(std::move(Consumer)); + } + EXPECT_EQ(FakeBuilder.consumeMessages(), + "MockSummaryExtractor1 constructor was invoked\n" + "MockSummaryExtractor2 constructor was invoked\n"); + + { + MultiplexConsumer Multiplexer(std::move(Consumers)); + auto AST = tooling::buildASTFromCode(R"cpp(int x = 42;)cpp"); + ASSERT_TRUE(AST); + + Multiplexer.HandleTranslationUnit(AST->getASTContext()); + EXPECT_EQ(FakeBuilder.consumeMessages(), + "MockSummaryExtractor1 HandleTranslationUnit was invoked\n" + "MockSummaryExtractor2 HandleTranslationUnit was invoked\n"); + } + + EXPECT_EQ(FakeBuilder.consumeMessages(), + "MockSummaryExtractor2 destructor was invoked\n" + "MockSummaryExtractor1 destructor was invoked\n"); +} + +} // namespace diff --git a/llvm/include/llvm/Support/Registry.h b/llvm/include/llvm/Support/Registry.h index acd3b06fde6e7..7ec7e52d6eefc 100644 --- a/llvm/include/llvm/Support/Registry.h +++ b/llvm/include/llvm/Support/Registry.h @@ -14,6 +14,7 @@ #define LLVM_SUPPORT_REGISTRY_H #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Compiler.h" @@ -21,121 +22,123 @@ #include <memory> namespace llvm { - /// A simple registry entry which provides only a name, description, and - /// no-argument constructor. - template <typename T> - class SimpleRegistryEntry { - StringRef Name, Desc; - std::unique_ptr<T> (*Ctor)(); +/// A simple registry entry which provides only a name, description, and +/// no-argument constructor. +template <typename T, typename... CtorParamTypes> class SimpleRegistryEntry { + StringRef Name, Desc; + using FactoryFnRef = function_ref<std::unique_ptr<T>(CtorParamTypes &&...)>; + FactoryFnRef Ctor; + +public: + SimpleRegistryEntry(StringRef N, StringRef D, FactoryFnRef C) + : Name(N), Desc(D), Ctor(C) {} + + StringRef getName() const { return Name; } + StringRef getDesc() const { return Desc; } + std::unique_ptr<T> instantiate(CtorParamTypes &&...Params) const { + return Ctor(std::forward<CtorParamTypes>(Params)...); + } +}; + +/// A global registry used in conjunction with static constructors to make +/// pluggable components (like targets or garbage collectors) "just work" when +/// linked with an executable. +template <typename T, typename... CtorParamTypes> class Registry { +public: + using type = T; + using entry = SimpleRegistryEntry<T, CtorParamTypes...>; + + class node; + class iterator; + +private: + Registry() = delete; + + friend class node; + // 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 inline node *Head = nullptr; + static inline node *Tail = nullptr; + +public: + /// Node in linked list of entries. + /// + class node { + friend class iterator; + friend Registry<T, CtorParamTypes...>; + + node *Next; + const entry &Val; public: - SimpleRegistryEntry(StringRef N, StringRef D, std::unique_ptr<T> (*C)()) - : Name(N), Desc(D), Ctor(C) {} - - StringRef getName() const { return Name; } - StringRef getDesc() const { return Desc; } - std::unique_ptr<T> instantiate() const { return Ctor(); } + node(const entry &V) : Next(nullptr), Val(V) {} }; - /// A global registry used in conjunction with static constructors to make - /// pluggable components (like targets or garbage collectors) "just work" when - /// linked with an executable. - template <typename T> - class Registry { - public: - using type = T; - using entry = SimpleRegistryEntry<T>; - - class node; - class iterator; - - private: - Registry() = delete; + /// Add a node to the Registry: this is the interface between the plugin and + /// the executable. + /// + /// This function is exported by the executable and called by the plugin to + /// 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) { + if (Tail) + Tail->Next = N; + else + Head = N; + Tail = N; + } - friend class node; - // 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 inline node *Head = nullptr; - static inline node *Tail = nullptr; + /// Iterators for registry entries. + /// + class iterator + : public llvm::iterator_facade_base<iterator, std::forward_iterator_tag, + const entry> { + const node *Cur; public: - /// Node in linked list of entries. - /// - class node { - friend class iterator; - friend Registry<T>; - - node *Next; - const entry& Val; - - public: - node(const entry &V) : Next(nullptr), Val(V) {} - }; - - /// Add a node to the Registry: this is the interface between the plugin and - /// the executable. - /// - /// This function is exported by the executable and called by the plugin to - /// 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) { - if (Tail) - Tail->Next = N; - else - Head = N; - Tail = N; - } + explicit iterator(const node *N) : Cur(N) {} - /// Iterators for registry entries. - /// - class iterator - : public llvm::iterator_facade_base<iterator, std::forward_iterator_tag, - const entry> { - const node *Cur; - - public: - explicit iterator(const node *N) : Cur(N) {} + bool operator==(const iterator &That) const { return Cur == That.Cur; } + iterator &operator++() { + Cur = Cur->Next; + return *this; + } + const entry &operator*() const { return Cur->Val; } + }; - bool operator==(const iterator &That) const { return Cur == That.Cur; } - iterator &operator++() { Cur = Cur->Next; return *this; } - const entry &operator*() const { return Cur->Val; } - }; + // 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() { return iterator(Head); } + static iterator end() { return iterator(nullptr); } - // 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() { return iterator(Head); } - static iterator end() { return iterator(nullptr); } + static iterator_range<iterator> entries() { + return make_range(begin(), end()); + } - static iterator_range<iterator> entries() { - return make_range(begin(), end()); + /// A static registration template. Use like such: + /// + /// Registry<Collector>::Add<FancyGC> + /// X("fancy-gc", "Newfangled garbage collector."); + /// + template <typename V> class Add { + entry Entry; + node Node; + + static std::unique_ptr<T> CtorFn(CtorParamTypes &&...Params) { + return std::make_unique<V>(std::forward<CtorParamTypes>(Params)...); } - /// A static registration template. Use like such: - /// - /// Registry<Collector>::Add<FancyGC> - /// X("fancy-gc", "Newfangled garbage collector."); - /// - /// Use of this template requires that: - /// - /// 1. The registered subclass has a default constructor. - template <typename V> - class Add { - entry Entry; - node Node; - - static std::unique_ptr<T> CtorFn() { return std::make_unique<V>(); } - - public: - Add(StringRef Name, StringRef Desc) - : Entry(Name, Desc, CtorFn), Node(Entry) { - add_node(&Node); - } - }; + public: + Add(StringRef Name, StringRef Desc) + : Entry(Name, Desc, CtorFn), Node(Entry) { + add_node(&Node); + } }; +}; } // end namespace llvm _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
