https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/85032
>From 6469dca42dae503bf08a65e55d60ccf48e012f25 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Wed, 13 Mar 2024 13:47:33 +0800 Subject: [PATCH 1/4] [concepts] Preserve the FoundDecl of ConceptReference properly --- .../clangd/unittests/SelectionTests.cpp | 28 +++++++++++ clang/docs/ReleaseNotes.rst | 1 + clang/include/clang/Sema/Sema.h | 1 + clang/lib/Sema/SemaDecl.cpp | 6 ++- clang/lib/Sema/SemaTemplate.cpp | 42 +++++++++------- clang/lib/Sema/SemaTemplateInstantiate.cpp | 3 +- clang/lib/Sema/SemaType.cpp | 8 ++- clang/test/AST/ast-dump-concepts.cpp | 50 +++++++++++++++++++ 8 files changed, 116 insertions(+), 23 deletions(-) diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp index 754e8c287c5148..db516a1f62a357 100644 --- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp @@ -10,6 +10,7 @@ #include "SourceCode.h" #include "TestTU.h" #include "support/TestTracer.h" +#include "clang/AST/ASTConcept.h" #include "clang/AST/Decl.h" #include "llvm/Support/Casting.h" #include "gmock/gmock.h" @@ -893,6 +894,33 @@ TEST(SelectionTest, DeclContextLambda) { EXPECT_TRUE(ST.commonAncestor()->getDeclContext().isFunctionOrMethod()); } +TEST(SelectionTest, UsingConcepts) { + llvm::Annotations Test(R"cpp( +namespace ns { +template <typename T> +concept Foo = true; +} + +using ns::Foo; + +template <Fo^o... T, Fo^o auto U> +auto Func(Fo^o auto V) -> Fo^o decltype(auto) { + Fo^o auto W = V; + return W; +} +)cpp"); + auto TU = TestTU::withCode(Test.code()); + TU.ExtraArgs.emplace_back("-std=c++2c"); + auto AST = TU.build(); + for (auto Point : Test.points()) { + auto ST = SelectionTree::createRight(AST.getASTContext(), AST.getTokens(), + Point, Point); + auto *C = ST.commonAncestor()->ASTNode.get<ConceptReference>(); + EXPECT_TRUE(C && C->getFoundDecl() && + C->getFoundDecl()->getKind() == Decl::UsingShadow); + } +} + } // namespace } // namespace clangd } // namespace clang diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 690fc7ed271a3d..faee6e048229c2 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -347,6 +347,7 @@ Bug Fixes to C++ Support Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ +- Clang now properly preserves ``FoundDecls`` within a ``ConceptReference``. (#GH82628) Miscellaneous Bug Fixes ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index cfc1c3b3494788..00506d6ef227db 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9207,6 +9207,7 @@ class Sema final { bool AttachTypeConstraint(NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, ConceptDecl *NamedConcept, + NamedDecl *FoundDecl, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 1f4a041e88dfff..5850cd0ab6b9aa 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1192,9 +1192,13 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, return ParsedType::make(T); } - if (isa<ConceptDecl>(FirstDecl)) + if (isa<ConceptDecl>(FirstDecl)) { + // We want to preserve the UsingShadowDecl for concepts. + if (auto *USD = dyn_cast<UsingShadowDecl>(Result.getRepresentativeDecl())) + return NameClassification::Concept(TemplateName(USD)); return NameClassification::Concept( TemplateName(cast<TemplateDecl>(FirstDecl))); + } if (auto *EmptyD = dyn_cast<UnresolvedUsingIfExistsDecl>(FirstDecl)) { (void)DiagnoseUseOfDecl(EmptyD, NameLoc); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index d62095558d0ffb..ad7055226f2631 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1156,6 +1156,7 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS, TemplateName TN = TypeConstr->Template.get(); ConceptDecl *CD = cast<ConceptDecl>(TN.getAsTemplateDecl()); + UsingShadowDecl *USD = TN.getAsUsingShadowDecl(); DeclarationNameInfo ConceptName(DeclarationName(TypeConstr->Name), TypeConstr->TemplateNameLoc); @@ -1174,15 +1175,15 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS, } return AttachTypeConstraint( SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(), - ConceptName, CD, + ConceptName, CD, /*FoundDecl=*/USD, TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, ConstrainedParameter, EllipsisLoc); } -template<typename ArgumentLocAppender> +template <typename ArgumentLocAppender> static ExprResult formImmediatelyDeclaredConstraint( Sema &S, NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, - ConceptDecl *NamedConcept, SourceLocation LAngleLoc, + ConceptDecl *NamedConcept, NamedDecl *FoundDecl, SourceLocation LAngleLoc, SourceLocation RAngleLoc, QualType ConstrainedType, SourceLocation ParamNameLoc, ArgumentLocAppender Appender, SourceLocation EllipsisLoc) { @@ -1203,7 +1204,8 @@ static ExprResult formImmediatelyDeclaredConstraint( SS.Adopt(NS); ExprResult ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId( SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, - /*FoundDecl=*/NamedConcept, NamedConcept, &ConstraintArgs); + /*FoundDecl=*/FoundDecl ? FoundDecl : NamedConcept, NamedConcept, + &ConstraintArgs); if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid()) return ImmediatelyDeclaredConstraint; @@ -1234,6 +1236,7 @@ static ExprResult formImmediatelyDeclaredConstraint( bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, ConceptDecl *NamedConcept, + NamedDecl *FoundDecl, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc) { @@ -1246,24 +1249,24 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0); - ExprResult ImmediatelyDeclaredConstraint = - formImmediatelyDeclaredConstraint( - *this, NS, NameInfo, NamedConcept, - TemplateArgs ? TemplateArgs->getLAngleLoc() : SourceLocation(), - TemplateArgs ? TemplateArgs->getRAngleLoc() : SourceLocation(), - ParamAsArgument, ConstrainedParameter->getLocation(), - [&] (TemplateArgumentListInfo &ConstraintArgs) { - if (TemplateArgs) - for (const auto &ArgLoc : TemplateArgs->arguments()) - ConstraintArgs.addArgument(ArgLoc); - }, EllipsisLoc); + ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint( + *this, NS, NameInfo, NamedConcept, FoundDecl, + TemplateArgs ? TemplateArgs->getLAngleLoc() : SourceLocation(), + TemplateArgs ? TemplateArgs->getRAngleLoc() : SourceLocation(), + ParamAsArgument, ConstrainedParameter->getLocation(), + [&](TemplateArgumentListInfo &ConstraintArgs) { + if (TemplateArgs) + for (const auto &ArgLoc : TemplateArgs->arguments()) + ConstraintArgs.addArgument(ArgLoc); + }, + EllipsisLoc); if (ImmediatelyDeclaredConstraint.isInvalid()) return true; auto *CL = ConceptReference::Create(Context, /*NNS=*/NS, /*TemplateKWLoc=*/SourceLocation{}, /*ConceptNameInfo=*/NameInfo, - /*FoundDecl=*/NamedConcept, + /*FoundDecl=*/FoundDecl, /*NamedConcept=*/NamedConcept, /*ArgsWritten=*/ArgsAsWritten); ConstrainedParameter->setTypeConstraint(CL, @@ -1293,8 +1296,9 @@ bool Sema::AttachTypeConstraint(AutoTypeLoc TL, return true; ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint( *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), - TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), - BuildDecltypeType(Ref), OrigConstrainedParm->getLocation(), + TL.getNamedConcept(), /*FoundDecl=*/TL.getFoundDecl(), TL.getLAngleLoc(), + TL.getRAngleLoc(), BuildDecltypeType(Ref), + OrigConstrainedParm->getLocation(), [&](TemplateArgumentListInfo &ConstraintArgs) { for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I) ConstraintArgs.addArgument(TL.getArgLoc(I)); @@ -5402,7 +5406,7 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, if (R.getAsSingle<ConceptDecl>()) { return CheckConceptTemplateId(SS, TemplateKWLoc, R.getLookupNameInfo(), - R.getFoundDecl(), + R.getRepresentativeDecl(), R.getAsSingle<ConceptDecl>(), TemplateArgs); } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index d9994d7fd37adb..5292b2fda6cb58 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2954,7 +2954,8 @@ bool Sema::SubstTypeConstraint( } return AttachTypeConstraint( TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), - TC->getNamedConcept(), &InstArgs, Inst, + TC->getNamedConcept(), + /*FoundDecl=*/TC->getConceptReference()->getFoundDecl(), &InstArgs, Inst, Inst->isParameterPack() ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint()) ->getEllipsisLoc() diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 3148299f6467af..3423b74993eecb 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3499,7 +3499,7 @@ InventTemplateParameter(TypeProcessingState &state, QualType T, if (!Invalid) { S.AttachTypeConstraint( AutoLoc.getNestedNameSpecifierLoc(), AutoLoc.getConceptNameInfo(), - AutoLoc.getNamedConcept(), + AutoLoc.getNamedConcept(), /*FoundDecl=*/AutoLoc.getFoundDecl(), AutoLoc.hasExplicitTemplateArgs() ? &TAL : nullptr, InventedTemplateParam, D.getEllipsisLoc()); } @@ -3530,6 +3530,7 @@ InventTemplateParameter(TypeProcessingState &state, QualType T, DeclarationNameInfo(DeclarationName(TemplateId->Name), TemplateId->TemplateNameLoc), cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl()), + /*FoundDecl=*/TemplateId->Template.get().getAsUsingShadowDecl(), TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr, InventedTemplateParam, D.getEllipsisLoc()); } @@ -6423,9 +6424,12 @@ namespace { DeclarationNameInfo DNI = DeclarationNameInfo( TL.getTypePtr()->getTypeConstraintConcept()->getDeclName(), TemplateId->TemplateNameLoc); + auto TN = TemplateId->Template.get(); auto *CR = ConceptReference::Create( Context, NNS, TemplateId->TemplateKWLoc, DNI, - /*FoundDecl=*/nullptr, + /*FoundDecl=*/TN.getKind() == TemplateName::NameKind::UsingTemplate + ? cast<NamedDecl>(TN.getAsUsingShadowDecl()) + : cast_if_present<NamedDecl>(TN.getAsTemplateDecl()), /*NamedDecl=*/TL.getTypePtr()->getTypeConstraintConcept(), ASTTemplateArgumentListInfo::Create(Context, TemplateArgsInfo)); TL.setConceptReference(CR); diff --git a/clang/test/AST/ast-dump-concepts.cpp b/clang/test/AST/ast-dump-concepts.cpp index 06518a71987a22..5bb174e3548ed2 100644 --- a/clang/test/AST/ast-dump-concepts.cpp +++ b/clang/test/AST/ast-dump-concepts.cpp @@ -57,3 +57,53 @@ struct Foo { template <variadic_concept<int>... Ts> Foo(); }; + +namespace GH82628 { +namespace ns { + +template <typename T> +concept C = true; + +} // namespace ns + +using ns::C; + +// CHECK: ConceptDecl {{.*}} Foo +// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} typename depth 0 index 0 T +// CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} UsingShadow {{.*}} 'C' +template <typename T> +concept Foo = C<T>; + +// CHECK: TemplateTypeParmDecl {{.*}} Concept {{.*}} 'C' (UsingShadow {{.*}} 'C') +template <C T> +constexpr bool FooVar = false; + +// CHECK: ConceptSpecializationExpr {{.*}} UsingShadow {{.*}} 'C' +template <typename T> requires C<T> +constexpr bool FooVar2 = true; + +// CHECK: SimpleRequirement +// CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} UsingShadow {{.*}} 'C' +template <typename T> requires requires (T) { C<T>; } +constexpr bool FooVar3 = true; + +// CHECK: NonTypeTemplateParmDecl +// CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} UsingShadow {{.*}} 'C' +template <C auto T> +constexpr bool FooVar4 = bool(T()); + +// CHECK: FunctionTemplateDecl +// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} Concept {{.*}} 'C' (UsingShadow {{.*}} 'C') depth 0 index 0 ... T +// CHECK: NonTypeTemplateParmDecl {{.*}} depth 0 index 1 U +// CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} UsingShadow {{.*}} 'C' +// CHECK: |-TemplateTypeParmDecl {{.*}} Concept {{.*}} 'C' (UsingShadow {{.*}} 'C') depth 0 index 2 V:auto + +template <C... T, C auto U> +auto FooFunc(C auto V) -> C decltype(auto) { + // FIXME: TypeLocs inside of the function body cannot be dumped via -ast-dump for now. + // See clang-tools-extra/clangd/unittests/SelectionTests.cpp:SelectionTest.UsingConcepts for their checkings. + C auto W = V; + return W; +} + +} >From 006b6e8ec2257ff8d9466b3d789679aa9207aa11 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Wed, 13 Mar 2024 15:21:06 +0800 Subject: [PATCH 2/4] Format --- clang/include/clang/Sema/Sema.h | 3 +-- clang/lib/Sema/SemaTemplate.cpp | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 00506d6ef227db..6826e917b7e38b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9206,8 +9206,7 @@ class Sema final { bool AttachTypeConstraint(NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, - ConceptDecl *NamedConcept, - NamedDecl *FoundDecl, + ConceptDecl *NamedConcept, NamedDecl *FoundDecl, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index ad7055226f2631..c626c3cf85f40d 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1235,8 +1235,7 @@ static ExprResult formImmediatelyDeclaredConstraint( /// of arguments for the named concept). bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, - ConceptDecl *NamedConcept, - NamedDecl *FoundDecl, + ConceptDecl *NamedConcept, NamedDecl *FoundDecl, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc) { >From df2cde246b392e43f119d40f9dc9b44cc34a16ee Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Wed, 13 Mar 2024 16:44:03 +0800 Subject: [PATCH 3/4] Fix the include-cleaner regressions --- .../include-cleaner/unittests/WalkASTTest.cpp | 4 +--- clang/lib/Sema/SemaTemplate.cpp | 3 ++- clang/lib/Sema/SemaType.cpp | 9 +++++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp index 5dc88157e13af0..dac3f39e1a6584 100644 --- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -548,9 +548,7 @@ TEST(WalkAST, Concepts) { testWalk(Concept, "template<typename T> requires ^Foo<T> void func() {}"); testWalk(Concept, "template<typename T> void func() requires ^Foo<T> {}"); testWalk(Concept, "void func(^Foo auto x) {}"); - // FIXME: Foo should be explicitly referenced. - testWalk("template<typename T> concept Foo = true;", - "void func() { ^Foo auto x = 1; }"); + testWalk(Concept, "void func() { ^Foo auto x = 1; }"); } TEST(WalkAST, FriendDecl) { diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index c626c3cf85f40d..260f84f7583164 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1175,7 +1175,8 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS, } return AttachTypeConstraint( SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(), - ConceptName, CD, /*FoundDecl=*/USD, + ConceptName, CD, /*FoundDecl=*/USD ? cast<NamedDecl>(USD) : CD, + // ConceptName, CD, /*FoundDecl=*/USD, TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, ConstrainedParameter, EllipsisLoc); } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 3423b74993eecb..9aaacaa0771f2f 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3525,12 +3525,17 @@ InventTemplateParameter(TypeProcessingState &state, QualType T, } } if (!Invalid) { + UsingShadowDecl *USD = + TemplateId->Template.get().getAsUsingShadowDecl(); + auto *CD = + cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl()); S.AttachTypeConstraint( D.getDeclSpec().getTypeSpecScope().getWithLocInContext(S.Context), DeclarationNameInfo(DeclarationName(TemplateId->Name), TemplateId->TemplateNameLoc), - cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl()), - /*FoundDecl=*/TemplateId->Template.get().getAsUsingShadowDecl(), + CD, + /*FoundDecl=*/ + USD ? cast<NamedDecl>(USD) : CD, TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr, InventedTemplateParam, D.getEllipsisLoc()); } >From 9f3f047142f9ca4a89bb4932accbe068038a23d3 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Wed, 13 Mar 2024 16:50:36 +0800 Subject: [PATCH 4/4] fixup --- clang/lib/Sema/SemaTemplate.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 260f84f7583164..73d813dbf31933 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1175,8 +1175,7 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS, } return AttachTypeConstraint( SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(), - ConceptName, CD, /*FoundDecl=*/USD ? cast<NamedDecl>(USD) : CD, - // ConceptName, CD, /*FoundDecl=*/USD, + ConceptName, CD, /*FoundDecl=*/USD ? cast<NamedDecl>(USD) : CD, TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, ConstrainedParameter, EllipsisLoc); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits