Skip to content

Commit b7c9226

Browse files
author
Erich Keane
committed
GH58368: Correct concept checking in a lambda defined in concept
As that bug reports, the problem here is that the lambda's 'context-decl' was not set to the concept, and the lambda picked up template arguments from the concept. SO, we failed to get the correct template arguments in SemaTemplateInstantiate. However, a Concept Specialization is NOT a decl, its an expression, so we weren't able to put the concept in the decl tree like we needed. This patch introduces a ConceptSpecializationDecl, which is the smallest type possible to use for this purpose, containing only the template arguments. The net memory impliciation of this is turning a trailing-objects into a pointer to a type with trailing-objects, so it should be minor. As future work, we may consider giving this type more responsibility, or figuring out how to better merge duplicates, but as this is just a template-argument collection at the moment, there isn't much value to it. Differential Revision: https://reviews.llvm.org/D136451
1 parent d84e4f0 commit b7c9226

25 files changed

+260
-100
lines changed

clang/include/clang/AST/ASTNodeTraverser.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,14 @@ class ASTNodeTraverser
623623
Visit(D->getConstraintExpr());
624624
}
625625

626+
void VisitImplicitConceptSpecializationDecl(
627+
const ImplicitConceptSpecializationDecl *CSD) {
628+
for (const TemplateArgument &Arg : CSD->getTemplateArguments())
629+
Visit(Arg);
630+
}
631+
626632
void VisitConceptSpecializationExpr(const ConceptSpecializationExpr *CSE) {
633+
Visit(CSE->getSpecializationDecl());
627634
if (CSE->hasExplicitTemplateArgs())
628635
for (const auto &ArgLoc : CSE->getTemplateArgsAsWritten()->arguments())
629636
dumpTemplateArgumentLoc(ArgLoc);

clang/include/clang/AST/DeclTemplate.h

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3259,7 +3259,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
32593259
static bool classofKind(Kind K) { return K == VarTemplate; }
32603260
};
32613261

3262-
/// Declaration of a C++2a concept.
3262+
/// Declaration of a C++20 concept.
32633263
class ConceptDecl : public TemplateDecl, public Mergeable<ConceptDecl> {
32643264
protected:
32653265
Expr *ConstraintExpr;
@@ -3304,6 +3304,40 @@ class ConceptDecl : public TemplateDecl, public Mergeable<ConceptDecl> {
33043304
friend class ASTDeclWriter;
33053305
};
33063306

3307+
// An implementation detail of ConceptSpecialicationExpr that holds the template
3308+
// arguments, so we can later use this to reconstitute the template arguments
3309+
// during constraint checking.
3310+
class ImplicitConceptSpecializationDecl final
3311+
: public Decl,
3312+
private llvm::TrailingObjects<ImplicitConceptSpecializationDecl,
3313+
TemplateArgument> {
3314+
unsigned NumTemplateArgs;
3315+
3316+
ImplicitConceptSpecializationDecl(DeclContext *DC, SourceLocation SL,
3317+
ArrayRef<TemplateArgument> ConvertedArgs);
3318+
ImplicitConceptSpecializationDecl(EmptyShell Empty, unsigned NumTemplateArgs);
3319+
3320+
public:
3321+
static ImplicitConceptSpecializationDecl *
3322+
Create(const ASTContext &C, DeclContext *DC, SourceLocation SL,
3323+
ArrayRef<TemplateArgument> ConvertedArgs);
3324+
static ImplicitConceptSpecializationDecl *
3325+
CreateDeserialized(const ASTContext &C, unsigned ID,
3326+
unsigned NumTemplateArgs);
3327+
3328+
ArrayRef<TemplateArgument> getTemplateArguments() const {
3329+
return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(),
3330+
NumTemplateArgs);
3331+
}
3332+
void setTemplateArguments(ArrayRef<TemplateArgument> Converted);
3333+
3334+
static bool classofKind(Kind K) { return K == ImplicitConceptSpecialization; }
3335+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
3336+
3337+
friend TrailingObjects;
3338+
friend class ASTDeclReader;
3339+
};
3340+
33073341
/// A template parameter object.
33083342
///
33093343
/// Template parameter objects represent values of class type used as template

clang/include/clang/AST/ExprConcepts.h

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,17 @@ class ASTStmtWriter;
3737
///
3838
/// According to C++2a [expr.prim.id]p3 an id-expression that denotes the
3939
/// specialization of a concept results in a prvalue of type bool.
40-
class ConceptSpecializationExpr final : public Expr, public ConceptReference,
41-
private llvm::TrailingObjects<ConceptSpecializationExpr,
42-
TemplateArgument> {
40+
class ConceptSpecializationExpr final : public Expr, public ConceptReference {
41+
friend class ASTReader;
4342
friend class ASTStmtReader;
44-
friend TrailingObjects;
43+
4544
public:
4645
using SubstitutionDiagnostic = std::pair<SourceLocation, std::string>;
4746

4847
protected:
49-
/// \brief The number of template arguments in the tail-allocated list of
50-
/// converted template arguments.
51-
unsigned NumTemplateArgs;
48+
/// \brief The Implicit Concept Specialization Decl, which holds the template
49+
/// arguments for this specialization.
50+
ImplicitConceptSpecializationDecl *SpecDecl;
5251

5352
/// \brief Information about the satisfaction of the named concept with the
5453
/// given arguments. If this expression is value dependent, this is to be
@@ -60,60 +59,55 @@ class ConceptSpecializationExpr final : public Expr, public ConceptReference,
6059
DeclarationNameInfo ConceptNameInfo,
6160
NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
6261
const ASTTemplateArgumentListInfo *ArgsAsWritten,
63-
ArrayRef<TemplateArgument> ConvertedArgs,
62+
ImplicitConceptSpecializationDecl *SpecDecl,
6463
const ConstraintSatisfaction *Satisfaction);
6564

6665
ConceptSpecializationExpr(const ASTContext &C, ConceptDecl *NamedConcept,
67-
ArrayRef<TemplateArgument> ConvertedArgs,
66+
ImplicitConceptSpecializationDecl *SpecDecl,
6867
const ConstraintSatisfaction *Satisfaction,
6968
bool Dependent,
7069
bool ContainsUnexpandedParameterPack);
71-
72-
ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs);
70+
ConceptSpecializationExpr(EmptyShell Empty);
7371

7472
public:
75-
7673
static ConceptSpecializationExpr *
7774
Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
7875
SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
7976
NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
8077
const ASTTemplateArgumentListInfo *ArgsAsWritten,
81-
ArrayRef<TemplateArgument> ConvertedArgs,
78+
ImplicitConceptSpecializationDecl *SpecDecl,
8279
const ConstraintSatisfaction *Satisfaction);
8380

8481
static ConceptSpecializationExpr *
8582
Create(const ASTContext &C, ConceptDecl *NamedConcept,
86-
ArrayRef<TemplateArgument> ConvertedArgs,
87-
const ConstraintSatisfaction *Satisfaction,
88-
bool Dependent,
83+
ImplicitConceptSpecializationDecl *SpecDecl,
84+
const ConstraintSatisfaction *Satisfaction, bool Dependent,
8985
bool ContainsUnexpandedParameterPack);
9086

91-
static ConceptSpecializationExpr *
92-
Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs);
93-
9487
ArrayRef<TemplateArgument> getTemplateArguments() const {
95-
return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(),
96-
NumTemplateArgs);
88+
return SpecDecl->getTemplateArguments();
9789
}
9890

99-
/// \brief Set new template arguments for this concept specialization.
100-
void setTemplateArguments(ArrayRef<TemplateArgument> Converted);
91+
const ImplicitConceptSpecializationDecl *getSpecializationDecl() const {
92+
assert(SpecDecl && "Template Argument Decl not initialized");
93+
return SpecDecl;
94+
}
10195

10296
/// \brief Whether or not the concept with the given arguments was satisfied
10397
/// when the expression was created.
10498
/// The expression must not be dependent.
10599
bool isSatisfied() const {
106-
assert(!isValueDependent()
107-
&& "isSatisfied called on a dependent ConceptSpecializationExpr");
100+
assert(!isValueDependent() &&
101+
"isSatisfied called on a dependent ConceptSpecializationExpr");
108102
return Satisfaction->IsSatisfied;
109103
}
110104

111105
/// \brief Get elaborated satisfaction info about the template arguments'
112106
/// satisfaction of the named concept.
113107
/// The expression must not be dependent.
114108
const ASTConstraintSatisfaction &getSatisfaction() const {
115-
assert(!isValueDependent()
116-
&& "getSatisfaction called on dependent ConceptSpecializationExpr");
109+
assert(!isValueDependent() &&
110+
"getSatisfaction called on dependent ConceptSpecializationExpr");
117111
return *Satisfaction;
118112
}
119113

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2304,6 +2304,11 @@ DEF_TRAVERSE_DECL(ParmVarDecl, {
23042304

23052305
DEF_TRAVERSE_DECL(RequiresExprBodyDecl, {})
23062306

2307+
DEF_TRAVERSE_DECL(ImplicitConceptSpecializationDecl, {
2308+
TRY_TO(TraverseTemplateArguments(D->getTemplateArguments().data(),
2309+
D->getTemplateArguments().size()));
2310+
})
2311+
23072312
#undef DEF_TRAVERSE_DECL
23082313

23092314
// ----------------- Stmt traversal -----------------

clang/include/clang/Basic/DeclNodes.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ def Named : DeclNode<Decl, "named declarations", 1>;
9090
def ObjCImplementation : DeclNode<ObjCImpl>;
9191
def ObjCProperty : DeclNode<Named, "Objective-C properties">;
9292
def ObjCCompatibleAlias : DeclNode<Named>;
93+
def ImplicitConceptSpecialization : DeclNode<Decl>;
9394
def LinkageSpec : DeclNode<Decl>, DeclContext;
9495
def Export : DeclNode<Decl>, DeclContext;
9596
def ObjCPropertyImpl : DeclNode<Decl>;

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1514,7 +1514,10 @@ enum DeclCode {
15141514
/// A HLSLBufferDecl record.
15151515
DECL_HLSL_BUFFER,
15161516

1517-
DECL_LAST = DECL_HLSL_BUFFER
1517+
/// An ImplicitConceptSpecializationDecl record.
1518+
DECL_IMPLICIT_CONCEPT_SPECIALIZATION,
1519+
1520+
DECL_LAST = DECL_IMPLICIT_CONCEPT_SPECIALIZATION
15181521
};
15191522

15201523
/// Record codes for each kind of statement or expression.

clang/lib/AST/ASTContext.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -761,9 +761,13 @@ canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC,
761761
NewConverted.push_back(ConstrainedType);
762762
llvm::append_range(NewConverted, OldConverted.drop_front(1));
763763
}
764+
auto *CSD = ImplicitConceptSpecializationDecl::Create(
765+
C, CSE->getNamedConcept()->getDeclContext(),
766+
CSE->getNamedConcept()->getLocation(), NewConverted);
767+
764768
Expr *NewIDC = ConceptSpecializationExpr::Create(
765-
C, CSE->getNamedConcept(), NewConverted, nullptr,
766-
CSE->isInstantiationDependent(), CSE->containsUnexpandedParameterPack());
769+
C, CSE->getNamedConcept(), CSD, nullptr, CSE->isInstantiationDependent(),
770+
CSE->containsUnexpandedParameterPack());
767771

768772
if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))
769773
NewIDC = new (C) CXXFoldExpr(

clang/lib/AST/DeclBase.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
874874
case Empty:
875875
case LifetimeExtendedTemporary:
876876
case RequiresExprBody:
877+
case ImplicitConceptSpecialization:
877878
// Never looked up by name.
878879
return 0;
879880
}

clang/lib/AST/DeclTemplate.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,44 @@ ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C,
10521052
return Result;
10531053
}
10541054

1055+
//===----------------------------------------------------------------------===//
1056+
// ImplicitConceptSpecializationDecl Implementation
1057+
//===----------------------------------------------------------------------===//
1058+
ImplicitConceptSpecializationDecl::ImplicitConceptSpecializationDecl(
1059+
DeclContext *DC, SourceLocation SL,
1060+
ArrayRef<TemplateArgument> ConvertedArgs)
1061+
: Decl(ImplicitConceptSpecialization, DC, SL),
1062+
NumTemplateArgs(ConvertedArgs.size()) {
1063+
setTemplateArguments(ConvertedArgs);
1064+
}
1065+
1066+
ImplicitConceptSpecializationDecl::ImplicitConceptSpecializationDecl(
1067+
EmptyShell Empty, unsigned NumTemplateArgs)
1068+
: Decl(ImplicitConceptSpecialization, Empty),
1069+
NumTemplateArgs(NumTemplateArgs) {}
1070+
1071+
ImplicitConceptSpecializationDecl *ImplicitConceptSpecializationDecl::Create(
1072+
const ASTContext &C, DeclContext *DC, SourceLocation SL,
1073+
ArrayRef<TemplateArgument> ConvertedArgs) {
1074+
return new (C, DC,
1075+
additionalSizeToAlloc<TemplateArgument>(ConvertedArgs.size()))
1076+
ImplicitConceptSpecializationDecl(DC, SL, ConvertedArgs);
1077+
}
1078+
1079+
ImplicitConceptSpecializationDecl *
1080+
ImplicitConceptSpecializationDecl::CreateDeserialized(
1081+
const ASTContext &C, unsigned ID, unsigned NumTemplateArgs) {
1082+
return new (C, ID, additionalSizeToAlloc<TemplateArgument>(NumTemplateArgs))
1083+
ImplicitConceptSpecializationDecl(EmptyShell{}, NumTemplateArgs);
1084+
}
1085+
1086+
void ImplicitConceptSpecializationDecl::setTemplateArguments(
1087+
ArrayRef<TemplateArgument> Converted) {
1088+
assert(Converted.size() == NumTemplateArgs);
1089+
std::uninitialized_copy(Converted.begin(), Converted.end(),
1090+
getTrailingObjects<TemplateArgument>());
1091+
}
1092+
10551093
//===----------------------------------------------------------------------===//
10561094
// ClassTemplatePartialSpecializationDecl Implementation
10571095
//===----------------------------------------------------------------------===//

clang/lib/AST/ExprConcepts.cpp

Lines changed: 24 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,15 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(
3535
SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
3636
NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
3737
const ASTTemplateArgumentListInfo *ArgsAsWritten,
38-
ArrayRef<TemplateArgument> ConvertedArgs,
38+
ImplicitConceptSpecializationDecl *SpecDecl,
3939
const ConstraintSatisfaction *Satisfaction)
4040
: Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
4141
ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl,
4242
NamedConcept, ArgsAsWritten),
43-
NumTemplateArgs(ConvertedArgs.size()),
43+
SpecDecl(SpecDecl),
4444
Satisfaction(Satisfaction
4545
? ASTConstraintSatisfaction::Create(C, *Satisfaction)
4646
: nullptr) {
47-
setTemplateArguments(ConvertedArgs);
4847
setDependence(computeDependence(this, /*ValueDependent=*/!Satisfaction));
4948

5049
// Currently guaranteed by the fact concepts can only be at namespace-scope.
@@ -56,50 +55,34 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(
5655
"should not be value-dependent");
5756
}
5857

59-
ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
60-
unsigned NumTemplateArgs)
61-
: Expr(ConceptSpecializationExprClass, Empty),
62-
NumTemplateArgs(NumTemplateArgs) {}
58+
ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty)
59+
: Expr(ConceptSpecializationExprClass, Empty) {}
6360

64-
void ConceptSpecializationExpr::setTemplateArguments(
65-
ArrayRef<TemplateArgument> Converted) {
66-
assert(Converted.size() == NumTemplateArgs);
67-
std::uninitialized_copy(Converted.begin(), Converted.end(),
68-
getTrailingObjects<TemplateArgument>());
69-
}
70-
71-
ConceptSpecializationExpr *
72-
ConceptSpecializationExpr::Create(const ASTContext &C,
73-
NestedNameSpecifierLoc NNS,
74-
SourceLocation TemplateKWLoc,
75-
DeclarationNameInfo ConceptNameInfo,
76-
NamedDecl *FoundDecl,
77-
ConceptDecl *NamedConcept,
78-
const ASTTemplateArgumentListInfo *ArgsAsWritten,
79-
ArrayRef<TemplateArgument> ConvertedArgs,
80-
const ConstraintSatisfaction *Satisfaction) {
81-
void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
82-
ConvertedArgs.size()));
83-
return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc,
84-
ConceptNameInfo, FoundDecl,
85-
NamedConcept, ArgsAsWritten,
86-
ConvertedArgs, Satisfaction);
61+
ConceptSpecializationExpr *ConceptSpecializationExpr::Create(
62+
const ASTContext &C, NestedNameSpecifierLoc NNS,
63+
SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
64+
NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
65+
const ASTTemplateArgumentListInfo *ArgsAsWritten,
66+
ImplicitConceptSpecializationDecl *SpecDecl,
67+
const ConstraintSatisfaction *Satisfaction) {
68+
return new (C) ConceptSpecializationExpr(
69+
C, NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
70+
ArgsAsWritten, SpecDecl, Satisfaction);
8771
}
8872

8973
ConceptSpecializationExpr::ConceptSpecializationExpr(
9074
const ASTContext &C, ConceptDecl *NamedConcept,
91-
ArrayRef<TemplateArgument> ConvertedArgs,
75+
ImplicitConceptSpecializationDecl *SpecDecl,
9276
const ConstraintSatisfaction *Satisfaction, bool Dependent,
9377
bool ContainsUnexpandedParameterPack)
9478
: Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
9579
ConceptReference(NestedNameSpecifierLoc(), SourceLocation(),
9680
DeclarationNameInfo(), NamedConcept, NamedConcept,
9781
nullptr),
98-
NumTemplateArgs(ConvertedArgs.size()),
82+
SpecDecl(SpecDecl),
9983
Satisfaction(Satisfaction
10084
? ASTConstraintSatisfaction::Create(C, *Satisfaction)
10185
: nullptr) {
102-
setTemplateArguments(ConvertedArgs);
10386
ExprDependence D = ExprDependence::None;
10487
if (!Satisfaction)
10588
D |= ExprDependence::Value;
@@ -110,26 +93,14 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(
11093
setDependence(D);
11194
}
11295

113-
ConceptSpecializationExpr *
114-
ConceptSpecializationExpr::Create(const ASTContext &C,
115-
ConceptDecl *NamedConcept,
116-
ArrayRef<TemplateArgument> ConvertedArgs,
117-
const ConstraintSatisfaction *Satisfaction,
118-
bool Dependent,
119-
bool ContainsUnexpandedParameterPack) {
120-
void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
121-
ConvertedArgs.size()));
122-
return new (Buffer) ConceptSpecializationExpr(
123-
C, NamedConcept, ConvertedArgs, Satisfaction, Dependent,
124-
ContainsUnexpandedParameterPack);
125-
}
126-
127-
ConceptSpecializationExpr *
128-
ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty,
129-
unsigned NumTemplateArgs) {
130-
void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
131-
NumTemplateArgs));
132-
return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs);
96+
ConceptSpecializationExpr *ConceptSpecializationExpr::Create(
97+
const ASTContext &C, ConceptDecl *NamedConcept,
98+
ImplicitConceptSpecializationDecl *SpecDecl,
99+
const ConstraintSatisfaction *Satisfaction, bool Dependent,
100+
bool ContainsUnexpandedParameterPack) {
101+
return new (C)
102+
ConceptSpecializationExpr(C, NamedConcept, SpecDecl, Satisfaction,
103+
Dependent, ContainsUnexpandedParameterPack);
133104
}
134105

135106
const TypeConstraint *

0 commit comments

Comments
 (0)