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

>From 2ee7226716f7b240eeee4bd290f5a059d46b0a0d Mon Sep 17 00:00:00 2001
From: David Zbarsky <[email protected]>
Date: Wed, 10 Jun 2026 07:35:54 -0400
Subject: [PATCH] [clang][ASTMatchers] Share variadic dyn-cast matcher
 marshalling

Replace the templated DynCastAllOfMatcherDescriptor implementation with one
descriptor that stores the base and derived AST node kinds. Keep the typed
conversion and dyn-cast operations in the shared implementation, including the
derived-kind restriction needed for adaptive matchers.

This removes 209 marshaller specializations from Registry.cpp.o. In an arm64
Release build, the two affected objects shrink by 768,528 bytes, including
551,176 bytes of loaded sections and 9,495 relocations. clang-query shrinks by
785,664 bytes unstripped and 721,456 bytes stripped, with linked text down
531,856 bytes and dyld fixups down 209.

All 39 Dynamic AST matcher unit tests and all six clang-query tests pass.
Behavior and command-line diagnostic corpora are byte-identical. Randomized
paired benchmarks found construction 8.2% faster, parsing statistically
neutral, and matcher execution neutral at +0.8% with a 95% confidence interval
of -1.5% to +3.1%.
---
 clang/lib/ASTMatchers/Dynamic/Marshallers.cpp | 53 +++++++++++++++++++
 clang/lib/ASTMatchers/Dynamic/Marshallers.h   | 50 ++++++++---------
 .../ASTMatchers/Dynamic/RegistryTest.cpp      |  9 ++++
 3 files changed, 84 insertions(+), 28 deletions(-)

diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp 
b/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp
index 37c91abb5c839..1c4fbf6b106d6 100644
--- a/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp
@@ -13,6 +13,59 @@
 #include <optional>
 #include <string>
 
+namespace clang::ast_matchers::dynamic::internal {
+
+VariantMatcher DynCastAllOfMatcherDescriptor::create(SourceRange,
+                                                     ArrayRef<ParserValue> 
Args,
+                                                     Diagnostics *Error) const 
{
+  std::vector<ast_matchers::internal::DynTypedMatcher> InnerMatchers;
+  InnerMatchers.reserve(Args.size());
+  for (size_t I = 0; I != Args.size(); ++I) {
+    const ParserValue &Arg = Args[I];
+    if (!Arg.Value.isMatcher() ||
+        !Arg.Value.getMatcher().hasTypedMatcher(DerivedKind)) {
+      Error->addError(Arg.Range, Error->ET_RegistryWrongArgType)
+          << (I + 1) << ArgKind::MakeMatcherArg(DerivedKind).asString()
+          << Arg.Value.getTypeAsString();
+      return {};
+    }
+    InnerMatchers.push_back(Arg.Value.getMatcher()
+                                .getTypedMatcher(DerivedKind)
+                                .dynCastTo(DerivedKind));
+  }
+
+  ast_matchers::internal::DynTypedMatcher Result =
+      InnerMatchers.empty()
+          ? ast_matchers::internal::DynTypedMatcher::trueMatcher(DerivedKind)
+      : InnerMatchers.size() == 1
+          ? InnerMatchers.front()
+          : ast_matchers::internal::DynTypedMatcher::constructVariadic(
+                ast_matchers::internal::DynTypedMatcher::VO_AllOf, DerivedKind,
+                std::move(InnerMatchers));
+  Result = Result.dynCastTo(BaseKind);
+  Result.setAllowBind(true);
+  return VariantMatcher::SingleMatcher(Result);
+}
+
+bool DynCastAllOfMatcherDescriptor::isConvertibleTo(
+    ASTNodeKind Kind, unsigned *Specificity,
+    ASTNodeKind *LeastDerivedKind) const {
+  if (!isRetKindConvertibleTo(ArrayRef(BaseKind), Kind, Specificity,
+                              LeastDerivedKind))
+    return false;
+
+  // If Kind is not a base of DerivedKind, either DerivedKind is a base of Kind
+  // (in which case the match will always succeed) or Kind and DerivedKind are
+  // unrelated (in which case it will always fail), so set Specificity to 0.
+  if (Kind.isSame(DerivedKind) || !Kind.isBaseOf(DerivedKind)) {
+    if (Specificity)
+      *Specificity = 0;
+  }
+  return true;
+}
+
+} // namespace clang::ast_matchers::dynamic::internal
+
 static std::optional<std::string>
 getBestGuess(llvm::StringRef Search, llvm::ArrayRef<llvm::StringRef> Allowed,
              llvm::StringRef DropPrefix = "", unsigned MaxEditDistance = 3) {
diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.h 
b/clang/lib/ASTMatchers/Dynamic/Marshallers.h
index 8c0ee465b3eb3..669245f5fd07a 100644
--- a/clang/lib/ASTMatchers/Dynamic/Marshallers.h
+++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.h
@@ -584,37 +584,30 @@ class VariadicFuncMatcherDescriptor : public 
MatcherDescriptor {
   const ArgKind ArgsKind;
 };
 
-/// Return CK_Trivial when appropriate for VariadicDynCastAllOfMatchers.
-class DynCastAllOfMatcherDescriptor : public VariadicFuncMatcherDescriptor {
+/// Matcher descriptor for VariadicDynCastAllOfMatchers.
+class DynCastAllOfMatcherDescriptor : public MatcherDescriptor {
 public:
-  template <typename BaseT, typename DerivedT>
-  DynCastAllOfMatcherDescriptor(
-      ast_matchers::internal::VariadicDynCastAllOfMatcher<BaseT, DerivedT> 
Func,
-      StringRef MatcherName)
-      : VariadicFuncMatcherDescriptor(Func, MatcherName),
-        DerivedKind(ASTNodeKind::getFromNodeKind<DerivedT>()) {}
+  DynCastAllOfMatcherDescriptor(ASTNodeKind BaseKind, ASTNodeKind DerivedKind)
+      : BaseKind(BaseKind), DerivedKind(DerivedKind) {}
 
-  bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity,
-                       ASTNodeKind *LeastDerivedKind) const override {
-    // If Kind is not a base of DerivedKind, either DerivedKind is a base of
-    // Kind (in which case the match will always succeed) or Kind and
-    // DerivedKind are unrelated (in which case it will always fail), so set
-    // Specificity to 0.
-    if (VariadicFuncMatcherDescriptor::isConvertibleTo(Kind, Specificity,
-                                                 LeastDerivedKind)) {
-      if (Kind.isSame(DerivedKind) || !Kind.isBaseOf(DerivedKind)) {
-        if (Specificity)
-          *Specificity = 0;
-      }
-      return true;
-    } else {
-      return false;
-    }
+  VariantMatcher create(SourceRange NameRange, ArrayRef<ParserValue> Args,
+                        Diagnostics *Error) const override;
+
+  bool isVariadic() const override { return true; }
+  unsigned getNumArgs() const override { return 0; }
+
+  void getArgKinds(ASTNodeKind, unsigned,
+                   std::vector<ArgKind> &Kinds) const override {
+    Kinds.push_back(ArgKind::MakeMatcherArg(DerivedKind));
   }
 
+  bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity,
+                       ASTNodeKind *LeastDerivedKind) const override;
+
   ASTNodeKind nodeMatcherType() const override { return DerivedKind; }
 
 private:
+  const ASTNodeKind BaseKind;
   const ASTNodeKind DerivedKind;
 };
 
@@ -1110,10 +1103,11 @@ std::unique_ptr<MatcherDescriptor> 
makeMatcherAutoMarshall(
 /// completion results for that type of matcher.
 template <typename BaseT, typename DerivedT>
 std::unique_ptr<MatcherDescriptor> makeMatcherAutoMarshall(
-    ast_matchers::internal::VariadicDynCastAllOfMatcher<BaseT, DerivedT>
-        VarFunc,
-    StringRef MatcherName) {
-  return std::make_unique<DynCastAllOfMatcherDescriptor>(VarFunc, MatcherName);
+    ast_matchers::internal::VariadicDynCastAllOfMatcher<BaseT, DerivedT>,
+    StringRef) {
+  return std::make_unique<DynCastAllOfMatcherDescriptor>(
+      ASTNodeKind::getFromNodeKind<BaseT>(),
+      ASTNodeKind::getFromNodeKind<DerivedT>());
 }
 
 /// Argument adaptative overload.
diff --git a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp 
b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
index 013bb912dfb8c..be9bfa9d5986b 100644
--- a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -287,6 +287,15 @@ TEST_F(RegistryTest, PolymorphicMatchers) {
       matches("class Foo { public: Foo(); }; Foo foo = Foo();", 
ConstructExpr));
 }
 
+TEST_F(RegistryTest, DynCastAllOfConvertsArgumentsToDerivedKind) {
+  VariantMatcher AnyDecl = VariantMatcher::SingleMatcher(decl());
+  Matcher<Decl> Record =
+      constructMatcher("recordDecl", AnyDecl).getTypedMatcher<Decl>();
+
+  EXPECT_TRUE(matches("struct X {};", Record));
+  EXPECT_FALSE(matches("void f();", Record));
+}
+
 TEST_F(RegistryTest, TemplateArgument) {
   Matcher<Decl> HasTemplateArgument = constructMatcher(
       "classTemplateSpecializationDecl",

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

Reply via email to