[clang] [AST] RecursiveASTVisitor: Don't traverse the alias deduction guides in the default mode. (PR #91454)

Haojian Wu via cfe-commits cfe-commits at lists.llvm.org
Thu May 16 01:18:49 PDT 2024


https://github.com/hokein updated https://github.com/llvm/llvm-project/pull/91454

>From e560fe2bf2d4bdc07a71682aa4d3a4bee8730b80 Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Wed, 8 May 2024 12:11:10 +0200
Subject: [PATCH 1/2] [AST] RecursiveASTVisitor: Don't traverse the alias
 deduction guides in default mode.

---
 clang/include/clang/AST/RecursiveASTVisitor.h | 28 ++++--
 .../DeductionGuide.cpp                        | 89 +++++++++++++++++++
 2 files changed, 110 insertions(+), 7 deletions(-)
 create mode 100644 clang/unittests/Tooling/RecursiveASTVisitorTests/DeductionGuide.cpp

diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index f9b145b4e86a5..2517189c95300 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -736,13 +736,27 @@ bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) {
 
   // As a syntax visitor, by default we want to ignore declarations for
   // implicit declarations (ones not typed explicitly by the user).
-  if (!getDerived().shouldVisitImplicitCode() && D->isImplicit()) {
-    // For an implicit template type parameter, its type constraints are not
-    // implicit and are not represented anywhere else. We still need to visit
-    // them.
-    if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(D))
-      return TraverseTemplateTypeParamDeclConstraints(TTPD);
-    return true;
+  if (!getDerived().shouldVisitImplicitCode()) {
+    if (D->isImplicit()) {
+      // For an implicit template type parameter, its type constraints are not
+      // implicit and are not represented anywhere else. We still need to visit
+      // them.
+      if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(D))
+        return TraverseTemplateTypeParamDeclConstraints(TTPD);
+      return true;
+    }
+
+    // Deduction guides for alias templates are always synthesized, so they
+    // should not be traversed unless shouldVisitImplicitCode() returns true.
+    //
+    // It's important to note that checking the implicit bit is not efficient
+    // for the alias case. For deduction guides synthesized from explicit
+    // user-defined deduction guides, we must maintain the explicit bit to
+    // ensure correct overload resolution.
+    if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
+      if (llvm::isa_and_present<TypeAliasTemplateDecl>(
+              FTD->getDeclName().getCXXDeductionGuideTemplate()))
+        return true;
   }
 
   switch (D->getKind()) {
diff --git a/clang/unittests/Tooling/RecursiveASTVisitorTests/DeductionGuide.cpp b/clang/unittests/Tooling/RecursiveASTVisitorTests/DeductionGuide.cpp
new file mode 100644
index 0000000000000..abfdbaea4a615
--- /dev/null
+++ b/clang/unittests/Tooling/RecursiveASTVisitorTests/DeductionGuide.cpp
@@ -0,0 +1,89 @@
+//===- unittest/Tooling/RecursiveASTVisitorTests/DeductionGuide.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 "TestVisitor.h"
+#include <string>
+
+using namespace clang;
+
+namespace {
+
+class DeductionGuideVisitor
+    : public ExpectedLocationVisitor<DeductionGuideVisitor> {
+public:
+  DeductionGuideVisitor(bool ShouldVisitImplicitCode)
+      : ShouldVisitImplicitCode(ShouldVisitImplicitCode) {}
+  bool VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
+    std::string Storage;
+    llvm::raw_string_ostream Stream(Storage);
+    D->print(Stream);
+    Match(Stream.str(),D->getLocation());
+    return true;
+  }
+
+  bool shouldVisitTemplateInstantiations() const {
+    return false;
+  }
+
+  bool shouldVisitImplicitCode() const {
+    return ShouldVisitImplicitCode;
+  }
+  bool ShouldVisitImplicitCode;
+};
+
+TEST(RecursiveASTVisitor, DeductionGuideNonImplicitMode) {
+  DeductionGuideVisitor Visitor(/*ShouldVisitImplicitCode*/ false);
+  // Verify that the synthezied deduction guide for alias is not visited in
+  // RAV's implicit mode.
+  Visitor.ExpectMatch("Foo(T) -> Foo<int>", 11, 1);
+  Visitor.DisallowMatch("Bar(type-parameter-0-0) -> Foo<int>", 14, 1);
+  EXPECT_TRUE(Visitor.runOver(
+    R"cpp(
+template <typename T>
+concept False = true;
+
+template <typename T> 
+struct Foo { 
+  Foo(T);
+};
+
+template<typename T> requires False<T>
+Foo(T) -> Foo<int>;
+
+template <typename U>
+using Bar = Foo<U>;
+Bar s(1); 
+   )cpp"
+  , DeductionGuideVisitor::Lang_CXX2a));
+}
+
+TEST(RecursiveASTVisitor, DeductionGuideImplicitMode) {
+  DeductionGuideVisitor Visitor(/*ShouldVisitImplicitCode*/ true);
+  Visitor.ExpectMatch("Foo(T) -> Foo<int>", 11, 1);
+  Visitor.ExpectMatch("Bar(type-parameter-0-0) -> Foo<int>", 14, 1);
+  EXPECT_TRUE(Visitor.runOver(
+    R"cpp(
+template <typename T>
+concept False = true;
+
+template <typename T> 
+struct Foo { 
+  Foo(T);
+};
+
+template<typename T> requires False<T>
+Foo(T) -> Foo<int>;
+
+template <typename U>
+using Bar = Foo<U>;
+Bar s(1); 
+   )cpp"
+  , DeductionGuideVisitor::Lang_CXX2a));
+}
+
+} // end anonymous namespace

>From f449f1f9902031d567f037afc97bccf053abdaaa Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Thu, 16 May 2024 10:18:30 +0200
Subject: [PATCH 2/2] clang-format

---
 .../DeductionGuide.cpp                        | 22 ++++++++-----------
 1 file changed, 9 insertions(+), 13 deletions(-)

diff --git a/clang/unittests/Tooling/RecursiveASTVisitorTests/DeductionGuide.cpp b/clang/unittests/Tooling/RecursiveASTVisitorTests/DeductionGuide.cpp
index abfdbaea4a615..274f275ea66a9 100644
--- a/clang/unittests/Tooling/RecursiveASTVisitorTests/DeductionGuide.cpp
+++ b/clang/unittests/Tooling/RecursiveASTVisitorTests/DeductionGuide.cpp
@@ -22,17 +22,13 @@ class DeductionGuideVisitor
     std::string Storage;
     llvm::raw_string_ostream Stream(Storage);
     D->print(Stream);
-    Match(Stream.str(),D->getLocation());
+    Match(Stream.str(), D->getLocation());
     return true;
   }
 
-  bool shouldVisitTemplateInstantiations() const {
-    return false;
-  }
+  bool shouldVisitTemplateInstantiations() const { return false; }
 
-  bool shouldVisitImplicitCode() const {
-    return ShouldVisitImplicitCode;
-  }
+  bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
   bool ShouldVisitImplicitCode;
 };
 
@@ -43,7 +39,7 @@ TEST(RecursiveASTVisitor, DeductionGuideNonImplicitMode) {
   Visitor.ExpectMatch("Foo(T) -> Foo<int>", 11, 1);
   Visitor.DisallowMatch("Bar(type-parameter-0-0) -> Foo<int>", 14, 1);
   EXPECT_TRUE(Visitor.runOver(
-    R"cpp(
+      R"cpp(
 template <typename T>
 concept False = true;
 
@@ -58,8 +54,8 @@ Foo(T) -> Foo<int>;
 template <typename U>
 using Bar = Foo<U>;
 Bar s(1); 
-   )cpp"
-  , DeductionGuideVisitor::Lang_CXX2a));
+   )cpp",
+      DeductionGuideVisitor::Lang_CXX2a));
 }
 
 TEST(RecursiveASTVisitor, DeductionGuideImplicitMode) {
@@ -67,7 +63,7 @@ TEST(RecursiveASTVisitor, DeductionGuideImplicitMode) {
   Visitor.ExpectMatch("Foo(T) -> Foo<int>", 11, 1);
   Visitor.ExpectMatch("Bar(type-parameter-0-0) -> Foo<int>", 14, 1);
   EXPECT_TRUE(Visitor.runOver(
-    R"cpp(
+      R"cpp(
 template <typename T>
 concept False = true;
 
@@ -82,8 +78,8 @@ Foo(T) -> Foo<int>;
 template <typename U>
 using Bar = Foo<U>;
 Bar s(1); 
-   )cpp"
-  , DeductionGuideVisitor::Lang_CXX2a));
+   )cpp",
+      DeductionGuideVisitor::Lang_CXX2a));
 }
 
 } // end anonymous namespace



More information about the cfe-commits mailing list