[clang-tools-extra] c1c8a0c - [concepts] Preserve the FoundDecl of ConceptReference properly (#85032)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 13 19:09:52 PDT 2024
Author: Younan Zhang
Date: 2024-03-14T10:09:47+08:00
New Revision: c1c8a0cb17468bcece489adea2b31df6920c96cb
URL: https://github.com/llvm/llvm-project/commit/c1c8a0cb17468bcece489adea2b31df6920c96cb
DIFF: https://github.com/llvm/llvm-project/commit/c1c8a0cb17468bcece489adea2b31df6920c96cb.diff
LOG: [concepts] Preserve the FoundDecl of ConceptReference properly (#85032)
The `ConceptReference`'s `FoundDecl` claims it "can differ from
`NamedConcept` when, for example, the concept was found through a
`UsingShadowDecl`", but such the contract was not previously respected.
Fixes https://github.com/llvm/llvm-project/issues/82628
Added:
Modified:
clang-tools-extra/clangd/unittests/SelectionTests.cpp
clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
clang/docs/ReleaseNotes.rst
clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/SemaType.cpp
clang/test/AST/ast-dump-concepts.cpp
Removed:
################################################################################
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-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/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 5fe3fd066df235..0a963d121fd354 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -379,6 +379,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 4a853119a2bb8f..69d5709e5e2f06 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -9215,7 +9215,7 @@ class Sema final {
bool AttachTypeConstraint(NestedNameSpecifierLoc NS,
DeclarationNameInfo NameInfo,
- ConceptDecl *NamedConcept,
+ 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 51e8db2dfbaac8..005529a53270c3 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 ? cast<NamedDecl>(USD) : CD,
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;
@@ -1233,7 +1235,7 @@ static ExprResult formImmediatelyDeclaredConstraint(
/// of arguments for the named concept).
bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
DeclarationNameInfo NameInfo,
- ConceptDecl *NamedConcept,
+ ConceptDecl *NamedConcept, NamedDecl *FoundDecl,
const TemplateArgumentListInfo *TemplateArgs,
TemplateTypeParmDecl *ConstrainedParameter,
SourceLocation EllipsisLoc) {
@@ -1246,24 +1248,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 +1295,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));
@@ -5415,7 +5418,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 1a0c88703aca01..5e05cb4f790b85 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2970,7 +2970,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..9aaacaa0771f2f 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());
}
@@ -3525,11 +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()),
+ CD,
+ /*FoundDecl=*/
+ USD ? cast<NamedDecl>(USD) : CD,
TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr,
InventedTemplateParam, D.getEllipsisLoc());
}
@@ -6423,9 +6429,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;
+}
+
+}
More information about the cfe-commits
mailing list