Skip to content

Commit c1c8a0c

Browse files
authored
[concepts] Preserve the FoundDecl of ConceptReference properly (llvm#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 llvm#82628
1 parent c29b265 commit c1c8a0c

File tree

9 files changed

+123
-29
lines changed

9 files changed

+123
-29
lines changed

clang-tools-extra/clangd/unittests/SelectionTests.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "SourceCode.h"
1111
#include "TestTU.h"
1212
#include "support/TestTracer.h"
13+
#include "clang/AST/ASTConcept.h"
1314
#include "clang/AST/Decl.h"
1415
#include "llvm/Support/Casting.h"
1516
#include "gmock/gmock.h"
@@ -893,6 +894,33 @@ TEST(SelectionTest, DeclContextLambda) {
893894
EXPECT_TRUE(ST.commonAncestor()->getDeclContext().isFunctionOrMethod());
894895
}
895896

897+
TEST(SelectionTest, UsingConcepts) {
898+
llvm::Annotations Test(R"cpp(
899+
namespace ns {
900+
template <typename T>
901+
concept Foo = true;
902+
}
903+
904+
using ns::Foo;
905+
906+
template <Fo^o... T, Fo^o auto U>
907+
auto Func(Fo^o auto V) -> Fo^o decltype(auto) {
908+
Fo^o auto W = V;
909+
return W;
910+
}
911+
)cpp");
912+
auto TU = TestTU::withCode(Test.code());
913+
TU.ExtraArgs.emplace_back("-std=c++2c");
914+
auto AST = TU.build();
915+
for (auto Point : Test.points()) {
916+
auto ST = SelectionTree::createRight(AST.getASTContext(), AST.getTokens(),
917+
Point, Point);
918+
auto *C = ST.commonAncestor()->ASTNode.get<ConceptReference>();
919+
EXPECT_TRUE(C && C->getFoundDecl() &&
920+
C->getFoundDecl()->getKind() == Decl::UsingShadow);
921+
}
922+
}
923+
896924
} // namespace
897925
} // namespace clangd
898926
} // namespace clang

clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -548,9 +548,7 @@ TEST(WalkAST, Concepts) {
548548
testWalk(Concept, "template<typename T> requires ^Foo<T> void func() {}");
549549
testWalk(Concept, "template<typename T> void func() requires ^Foo<T> {}");
550550
testWalk(Concept, "void func(^Foo auto x) {}");
551-
// FIXME: Foo should be explicitly referenced.
552-
testWalk("template<typename T> concept Foo = true;",
553-
"void func() { ^Foo auto x = 1; }");
551+
testWalk(Concept, "void func() { ^Foo auto x = 1; }");
554552
}
555553

556554
TEST(WalkAST, FriendDecl) {

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ Bug Fixes to C++ Support
379379

380380
Bug Fixes to AST Handling
381381
^^^^^^^^^^^^^^^^^^^^^^^^^
382+
- Clang now properly preserves ``FoundDecls`` within a ``ConceptReference``. (#GH82628)
382383

383384
Miscellaneous Bug Fixes
384385
^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9215,7 +9215,7 @@ class Sema final {
92159215

92169216
bool AttachTypeConstraint(NestedNameSpecifierLoc NS,
92179217
DeclarationNameInfo NameInfo,
9218-
ConceptDecl *NamedConcept,
9218+
ConceptDecl *NamedConcept, NamedDecl *FoundDecl,
92199219
const TemplateArgumentListInfo *TemplateArgs,
92209220
TemplateTypeParmDecl *ConstrainedParameter,
92219221
SourceLocation EllipsisLoc);

clang/lib/Sema/SemaDecl.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1192,9 +1192,13 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
11921192
return ParsedType::make(T);
11931193
}
11941194

1195-
if (isa<ConceptDecl>(FirstDecl))
1195+
if (isa<ConceptDecl>(FirstDecl)) {
1196+
// We want to preserve the UsingShadowDecl for concepts.
1197+
if (auto *USD = dyn_cast<UsingShadowDecl>(Result.getRepresentativeDecl()))
1198+
return NameClassification::Concept(TemplateName(USD));
11961199
return NameClassification::Concept(
11971200
TemplateName(cast<TemplateDecl>(FirstDecl)));
1201+
}
11981202

11991203
if (auto *EmptyD = dyn_cast<UnresolvedUsingIfExistsDecl>(FirstDecl)) {
12001204
(void)DiagnoseUseOfDecl(EmptyD, NameLoc);

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,7 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS,
11561156

11571157
TemplateName TN = TypeConstr->Template.get();
11581158
ConceptDecl *CD = cast<ConceptDecl>(TN.getAsTemplateDecl());
1159+
UsingShadowDecl *USD = TN.getAsUsingShadowDecl();
11591160

11601161
DeclarationNameInfo ConceptName(DeclarationName(TypeConstr->Name),
11611162
TypeConstr->TemplateNameLoc);
@@ -1174,15 +1175,15 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS,
11741175
}
11751176
return AttachTypeConstraint(
11761177
SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(),
1177-
ConceptName, CD,
1178+
ConceptName, CD, /*FoundDecl=*/USD ? cast<NamedDecl>(USD) : CD,
11781179
TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr,
11791180
ConstrainedParameter, EllipsisLoc);
11801181
}
11811182

1182-
template<typename ArgumentLocAppender>
1183+
template <typename ArgumentLocAppender>
11831184
static ExprResult formImmediatelyDeclaredConstraint(
11841185
Sema &S, NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo,
1185-
ConceptDecl *NamedConcept, SourceLocation LAngleLoc,
1186+
ConceptDecl *NamedConcept, NamedDecl *FoundDecl, SourceLocation LAngleLoc,
11861187
SourceLocation RAngleLoc, QualType ConstrainedType,
11871188
SourceLocation ParamNameLoc, ArgumentLocAppender Appender,
11881189
SourceLocation EllipsisLoc) {
@@ -1203,7 +1204,8 @@ static ExprResult formImmediatelyDeclaredConstraint(
12031204
SS.Adopt(NS);
12041205
ExprResult ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId(
12051206
SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo,
1206-
/*FoundDecl=*/NamedConcept, NamedConcept, &ConstraintArgs);
1207+
/*FoundDecl=*/FoundDecl ? FoundDecl : NamedConcept, NamedConcept,
1208+
&ConstraintArgs);
12071209
if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid())
12081210
return ImmediatelyDeclaredConstraint;
12091211

@@ -1233,7 +1235,7 @@ static ExprResult formImmediatelyDeclaredConstraint(
12331235
/// of arguments for the named concept).
12341236
bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
12351237
DeclarationNameInfo NameInfo,
1236-
ConceptDecl *NamedConcept,
1238+
ConceptDecl *NamedConcept, NamedDecl *FoundDecl,
12371239
const TemplateArgumentListInfo *TemplateArgs,
12381240
TemplateTypeParmDecl *ConstrainedParameter,
12391241
SourceLocation EllipsisLoc) {
@@ -1246,24 +1248,24 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
12461248

12471249
QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0);
12481250

1249-
ExprResult ImmediatelyDeclaredConstraint =
1250-
formImmediatelyDeclaredConstraint(
1251-
*this, NS, NameInfo, NamedConcept,
1252-
TemplateArgs ? TemplateArgs->getLAngleLoc() : SourceLocation(),
1253-
TemplateArgs ? TemplateArgs->getRAngleLoc() : SourceLocation(),
1254-
ParamAsArgument, ConstrainedParameter->getLocation(),
1255-
[&] (TemplateArgumentListInfo &ConstraintArgs) {
1256-
if (TemplateArgs)
1257-
for (const auto &ArgLoc : TemplateArgs->arguments())
1258-
ConstraintArgs.addArgument(ArgLoc);
1259-
}, EllipsisLoc);
1251+
ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint(
1252+
*this, NS, NameInfo, NamedConcept, FoundDecl,
1253+
TemplateArgs ? TemplateArgs->getLAngleLoc() : SourceLocation(),
1254+
TemplateArgs ? TemplateArgs->getRAngleLoc() : SourceLocation(),
1255+
ParamAsArgument, ConstrainedParameter->getLocation(),
1256+
[&](TemplateArgumentListInfo &ConstraintArgs) {
1257+
if (TemplateArgs)
1258+
for (const auto &ArgLoc : TemplateArgs->arguments())
1259+
ConstraintArgs.addArgument(ArgLoc);
1260+
},
1261+
EllipsisLoc);
12601262
if (ImmediatelyDeclaredConstraint.isInvalid())
12611263
return true;
12621264

12631265
auto *CL = ConceptReference::Create(Context, /*NNS=*/NS,
12641266
/*TemplateKWLoc=*/SourceLocation{},
12651267
/*ConceptNameInfo=*/NameInfo,
1266-
/*FoundDecl=*/NamedConcept,
1268+
/*FoundDecl=*/FoundDecl,
12671269
/*NamedConcept=*/NamedConcept,
12681270
/*ArgsWritten=*/ArgsAsWritten);
12691271
ConstrainedParameter->setTypeConstraint(CL,
@@ -1293,8 +1295,9 @@ bool Sema::AttachTypeConstraint(AutoTypeLoc TL,
12931295
return true;
12941296
ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint(
12951297
*this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(),
1296-
TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(),
1297-
BuildDecltypeType(Ref), OrigConstrainedParm->getLocation(),
1298+
TL.getNamedConcept(), /*FoundDecl=*/TL.getFoundDecl(), TL.getLAngleLoc(),
1299+
TL.getRAngleLoc(), BuildDecltypeType(Ref),
1300+
OrigConstrainedParm->getLocation(),
12981301
[&](TemplateArgumentListInfo &ConstraintArgs) {
12991302
for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I)
13001303
ConstraintArgs.addArgument(TL.getArgLoc(I));
@@ -5415,7 +5418,7 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
54155418

54165419
if (R.getAsSingle<ConceptDecl>()) {
54175420
return CheckConceptTemplateId(SS, TemplateKWLoc, R.getLookupNameInfo(),
5418-
R.getFoundDecl(),
5421+
R.getRepresentativeDecl(),
54195422
R.getAsSingle<ConceptDecl>(), TemplateArgs);
54205423
}
54215424

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2970,7 +2970,8 @@ bool Sema::SubstTypeConstraint(
29702970
}
29712971
return AttachTypeConstraint(
29722972
TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
2973-
TC->getNamedConcept(), &InstArgs, Inst,
2973+
TC->getNamedConcept(),
2974+
/*FoundDecl=*/TC->getConceptReference()->getFoundDecl(), &InstArgs, Inst,
29742975
Inst->isParameterPack()
29752976
? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
29762977
->getEllipsisLoc()

clang/lib/Sema/SemaType.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3499,7 +3499,7 @@ InventTemplateParameter(TypeProcessingState &state, QualType T,
34993499
if (!Invalid) {
35003500
S.AttachTypeConstraint(
35013501
AutoLoc.getNestedNameSpecifierLoc(), AutoLoc.getConceptNameInfo(),
3502-
AutoLoc.getNamedConcept(),
3502+
AutoLoc.getNamedConcept(), /*FoundDecl=*/AutoLoc.getFoundDecl(),
35033503
AutoLoc.hasExplicitTemplateArgs() ? &TAL : nullptr,
35043504
InventedTemplateParam, D.getEllipsisLoc());
35053505
}
@@ -3525,11 +3525,17 @@ InventTemplateParameter(TypeProcessingState &state, QualType T,
35253525
}
35263526
}
35273527
if (!Invalid) {
3528+
UsingShadowDecl *USD =
3529+
TemplateId->Template.get().getAsUsingShadowDecl();
3530+
auto *CD =
3531+
cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl());
35283532
S.AttachTypeConstraint(
35293533
D.getDeclSpec().getTypeSpecScope().getWithLocInContext(S.Context),
35303534
DeclarationNameInfo(DeclarationName(TemplateId->Name),
35313535
TemplateId->TemplateNameLoc),
3532-
cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl()),
3536+
CD,
3537+
/*FoundDecl=*/
3538+
USD ? cast<NamedDecl>(USD) : CD,
35333539
TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr,
35343540
InventedTemplateParam, D.getEllipsisLoc());
35353541
}
@@ -6423,9 +6429,12 @@ namespace {
64236429
DeclarationNameInfo DNI = DeclarationNameInfo(
64246430
TL.getTypePtr()->getTypeConstraintConcept()->getDeclName(),
64256431
TemplateId->TemplateNameLoc);
6432+
auto TN = TemplateId->Template.get();
64266433
auto *CR = ConceptReference::Create(
64276434
Context, NNS, TemplateId->TemplateKWLoc, DNI,
6428-
/*FoundDecl=*/nullptr,
6435+
/*FoundDecl=*/TN.getKind() == TemplateName::NameKind::UsingTemplate
6436+
? cast<NamedDecl>(TN.getAsUsingShadowDecl())
6437+
: cast_if_present<NamedDecl>(TN.getAsTemplateDecl()),
64296438
/*NamedDecl=*/TL.getTypePtr()->getTypeConstraintConcept(),
64306439
ASTTemplateArgumentListInfo::Create(Context, TemplateArgsInfo));
64316440
TL.setConceptReference(CR);

clang/test/AST/ast-dump-concepts.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,53 @@ struct Foo {
5757
template <variadic_concept<int>... Ts>
5858
Foo();
5959
};
60+
61+
namespace GH82628 {
62+
namespace ns {
63+
64+
template <typename T>
65+
concept C = true;
66+
67+
} // namespace ns
68+
69+
using ns::C;
70+
71+
// CHECK: ConceptDecl {{.*}} Foo
72+
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} typename depth 0 index 0 T
73+
// CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} UsingShadow {{.*}} 'C'
74+
template <typename T>
75+
concept Foo = C<T>;
76+
77+
// CHECK: TemplateTypeParmDecl {{.*}} Concept {{.*}} 'C' (UsingShadow {{.*}} 'C')
78+
template <C T>
79+
constexpr bool FooVar = false;
80+
81+
// CHECK: ConceptSpecializationExpr {{.*}} UsingShadow {{.*}} 'C'
82+
template <typename T> requires C<T>
83+
constexpr bool FooVar2 = true;
84+
85+
// CHECK: SimpleRequirement
86+
// CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} UsingShadow {{.*}} 'C'
87+
template <typename T> requires requires (T) { C<T>; }
88+
constexpr bool FooVar3 = true;
89+
90+
// CHECK: NonTypeTemplateParmDecl
91+
// CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} UsingShadow {{.*}} 'C'
92+
template <C auto T>
93+
constexpr bool FooVar4 = bool(T());
94+
95+
// CHECK: FunctionTemplateDecl
96+
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} Concept {{.*}} 'C' (UsingShadow {{.*}} 'C') depth 0 index 0 ... T
97+
// CHECK: NonTypeTemplateParmDecl {{.*}} depth 0 index 1 U
98+
// CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} UsingShadow {{.*}} 'C'
99+
// CHECK: |-TemplateTypeParmDecl {{.*}} Concept {{.*}} 'C' (UsingShadow {{.*}} 'C') depth 0 index 2 V:auto
100+
101+
template <C... T, C auto U>
102+
auto FooFunc(C auto V) -> C decltype(auto) {
103+
// FIXME: TypeLocs inside of the function body cannot be dumped via -ast-dump for now.
104+
// See clang-tools-extra/clangd/unittests/SelectionTests.cpp:SelectionTest.UsingConcepts for their checkings.
105+
C auto W = V;
106+
return W;
107+
}
108+
109+
}

0 commit comments

Comments
 (0)