diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index f9b145b4e86a55..2517189c95300c 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -736,13 +736,27 @@ bool RecursiveASTVisitor::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(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(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(D)) + if (llvm::isa_and_present( + 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 00000000000000..274f275ea66a9d --- /dev/null +++ b/clang/unittests/Tooling/RecursiveASTVisitorTests/DeductionGuide.cpp @@ -0,0 +1,85 @@ +//===- 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 + +using namespace clang; + +namespace { + +class DeductionGuideVisitor + : public ExpectedLocationVisitor { +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", 11, 1); + Visitor.DisallowMatch("Bar(type-parameter-0-0) -> Foo", 14, 1); + EXPECT_TRUE(Visitor.runOver( + R"cpp( +template +concept False = true; + +template +struct Foo { + Foo(T); +}; + +template requires False +Foo(T) -> Foo; + +template +using Bar = Foo; +Bar s(1); + )cpp", + DeductionGuideVisitor::Lang_CXX2a)); +} + +TEST(RecursiveASTVisitor, DeductionGuideImplicitMode) { + DeductionGuideVisitor Visitor(/*ShouldVisitImplicitCode*/ true); + Visitor.ExpectMatch("Foo(T) -> Foo", 11, 1); + Visitor.ExpectMatch("Bar(type-parameter-0-0) -> Foo", 14, 1); + EXPECT_TRUE(Visitor.runOver( + R"cpp( +template +concept False = true; + +template +struct Foo { + Foo(T); +}; + +template requires False +Foo(T) -> Foo; + +template +using Bar = Foo; +Bar s(1); + )cpp", + DeductionGuideVisitor::Lang_CXX2a)); +} + +} // end anonymous namespace