https://github.com/dzbarsky updated 
https://github.com/llvm/llvm-project/pull/202625

>From 3cd1d68835e5c26e29c38bb8f5de2638f3937c65 Mon Sep 17 00:00:00 2001
From: David Zbarsky <[email protected]>
Date: Mon, 8 Jun 2026 13:27:54 -0400
Subject: [PATCH] [clang-tidy] Store stateless check factories as function
 pointers

Most clang-tidy checks use a factory whose only state is the check constructor. 
Instantiating a separate templated factory class for every check emits 
duplicate virtual machinery and RTTI into clang-tidy.

Store a constructor function pointer directly for stateless checks while 
retaining the existing factory-object path for checks that carry state. This 
preserves registration and construction behavior while allowing the compiler 
and linker to coalesce the shared factory implementation.

On arm64 Release builds, the fully stripped standalone clang-tidy binary 
shrinks from 71,643,328 to 71,542,816 bytes, saving 100,512 bytes (0.140%). The 
stripped all-tools multicall binary shrinks from 147,944,136 to 147,861,144 
bytes, saving 82,992 bytes.

ClangTidyTests passes all 347 tests. The list-checks and custom-query-check lit 
tests pass, including the stateful factory path. The complete check listing and 
representative diagnostics are byte-identical before and after the change.

LLVM has no dedicated benchmark for this path. Five hundred repeated list-check 
invocations show no measurable regression, and the all-check workload changed 
by 0.46%, within run-to-run noise.
---
 .../clang-tidy/ClangTidyModule.cpp            | 43 ++++++++++++++++++-
 .../clang-tidy/ClangTidyModule.h              | 39 ++++++++++++++---
 2 files changed, 76 insertions(+), 6 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/ClangTidyModule.cpp 
b/clang-tools-extra/clang-tidy/ClangTidyModule.cpp
index 976e87dffb0bf..b599714fa1bb0 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyModule.cpp
@@ -15,9 +15,50 @@
 
 namespace clang::tidy {
 
+ClangTidyCheckFactories::FactoryEntry::FactoryEntry(
+    CheckFactoryFunction Function)
+    : Function(Function) {}
+
+ClangTidyCheckFactories::FactoryEntry::FactoryEntry(CheckFactory Factory)
+    : Factory(std::make_unique<CheckFactory>(std::move(Factory))) {}
+
+ClangTidyCheckFactories::FactoryEntry::FactoryEntry(const FactoryEntry &Other)
+    : Function(Other.Function) {
+  if (Other.Factory)
+    Factory = std::make_unique<CheckFactory>(*Other.Factory);
+}
+
+ClangTidyCheckFactories::FactoryEntry &
+ClangTidyCheckFactories::FactoryEntry::operator=(const FactoryEntry &Other) {
+  if (this == &Other)
+    return *this;
+  Function = Other.Function;
+  Factory =
+      Other.Factory ? std::make_unique<CheckFactory>(*Other.Factory) : nullptr;
+  return *this;
+}
+
+std::unique_ptr<ClangTidyCheck>
+ClangTidyCheckFactories::FactoryEntry::operator()(
+    StringRef Name, ClangTidyContext *Context) const {
+  if (Function)
+    return Function(Name, Context);
+  return (*Factory)(Name, Context);
+}
+
 void ClangTidyCheckFactories::registerCheckFactory(StringRef Name,
                                                    CheckFactory Factory) {
-  Factories.insert_or_assign(Name, std::move(Factory));
+  Factories.insert_or_assign(Name, FactoryEntry(std::move(Factory)));
+}
+
+void ClangTidyCheckFactories::registerCheckFactory(
+    StringRef Name, const FactoryEntry &Factory) {
+  Factories.insert_or_assign(Name, Factory);
+}
+
+void ClangTidyCheckFactories::registerCheckFunction(
+    StringRef Name, CheckFactoryFunction Function) {
+  Factories.insert_or_assign(Name, FactoryEntry(Function));
 }
 
 std::vector<std::unique_ptr<ClangTidyCheck>>
diff --git a/clang-tools-extra/clang-tidy/ClangTidyModule.h 
b/clang-tools-extra/clang-tidy/ClangTidyModule.h
index 3db92c2dab981..56f4ba19deafe 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyModule.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyModule.h
@@ -29,11 +29,32 @@ class ClangTidyCheckFactories {
 public:
   using CheckFactory = std::function<std::unique_ptr<ClangTidyCheck>(
       StringRef Name, ClangTidyContext *Context)>;
+  using CheckFactoryFunction = std::unique_ptr<ClangTidyCheck> (*)(
+      StringRef Name, ClangTidyContext *Context);
+
+  class FactoryEntry {
+  public:
+    FactoryEntry(CheckFactoryFunction Function);
+    FactoryEntry(CheckFactory Factory);
+    FactoryEntry(const FactoryEntry &Other);
+    FactoryEntry &operator=(const FactoryEntry &Other);
+    FactoryEntry(FactoryEntry &&) = default;
+    FactoryEntry &operator=(FactoryEntry &&) = default;
+
+    std::unique_ptr<ClangTidyCheck> operator()(StringRef Name,
+                                               ClangTidyContext *Context) 
const;
+
+  private:
+    CheckFactoryFunction Function = nullptr;
+    std::unique_ptr<CheckFactory> Factory;
+  };
+  static_assert(sizeof(FactoryEntry) == 2 * sizeof(void *));
 
   /// Registers check \p Factory with name \p Name.
   ///
   /// For all checks that have default constructors, use \c registerCheck.
   void registerCheckFactory(StringRef Name, CheckFactory Factory);
+  void registerCheckFactory(StringRef Name, const FactoryEntry &Factory);
 
   /// Registers the \c CheckType with the name \p Name.
   ///
@@ -57,10 +78,7 @@ class ClangTidyCheckFactories {
   /// };
   /// \endcode
   template <typename CheckType> void registerCheck(StringRef CheckName) {
-    registerCheckFactory(CheckName,
-                         [](StringRef Name, ClangTidyContext *Context) {
-                           return std::make_unique<CheckType>(Name, Context);
-                         });
+    registerCheckFunction(CheckName, &createCheck<CheckType>);
   }
 
   void eraseCheck(StringRef CheckName) { Factories.erase(CheckName); }
@@ -73,12 +91,23 @@ class ClangTidyCheckFactories {
   std::vector<std::unique_ptr<ClangTidyCheck>>
   createChecksForLanguage(ClangTidyContext *Context) const;
 
-  using FactoryMap = llvm::StringMap<CheckFactory>;
+  using FactoryMap = llvm::StringMap<FactoryEntry>;
   FactoryMap::const_iterator begin() const { return Factories.begin(); }
   FactoryMap::const_iterator end() const { return Factories.end(); }
   bool empty() const { return Factories.empty(); }
 
 private:
+  template <typename CheckType>
+#if defined(__clang__)
+  __attribute__((internal_linkage))
+#endif
+  static std::unique_ptr<ClangTidyCheck>
+  createCheck(StringRef Name, ClangTidyContext *Context) {
+    return std::make_unique<CheckType>(Name, Context);
+  }
+
+  void registerCheckFunction(StringRef Name, CheckFactoryFunction Function);
+
   FactoryMap Factories;
 };
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to