Skip to content

Commit c83d9be

Browse files
committed
[Concept] Fix incorrect check for containsUnexpandedParameterPack in CSE
We previously checked for containsUnexpandedParameterPack in CSEs by observing the property in the converted arguments of the CSE. This may not work if the argument is an expanded type-alias that contains a pack-expansion (see added test). Check the as-written arguments when determining containsUnexpandedParameterPack and isInstantiationDependent.
1 parent 34e6552 commit c83d9be

File tree

4 files changed

+78
-21
lines changed

4 files changed

+78
-21
lines changed

clang/include/clang/AST/ExprConcepts.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ class ConceptSpecializationExpr final : public Expr, public ConceptReference,
6363
ArrayRef<TemplateArgument> ConvertedArgs,
6464
const ConstraintSatisfaction *Satisfaction);
6565

66+
ConceptSpecializationExpr(const ASTContext &C, ConceptDecl *NamedConcept,
67+
ArrayRef<TemplateArgument> ConvertedArgs,
68+
const ConstraintSatisfaction *Satisfaction,
69+
bool Dependent,
70+
bool ContainsUnexpandedParameterPack);
71+
6672
ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs);
6773

6874
public:
@@ -75,6 +81,13 @@ class ConceptSpecializationExpr final : public Expr, public ConceptReference,
7581
ArrayRef<TemplateArgument> ConvertedArgs,
7682
const ConstraintSatisfaction *Satisfaction);
7783

84+
static ConceptSpecializationExpr *
85+
Create(const ASTContext &C, ConceptDecl *NamedConcept,
86+
ArrayRef<TemplateArgument> ConvertedArgs,
87+
const ConstraintSatisfaction *Satisfaction,
88+
bool Dependent,
89+
bool ContainsUnexpandedParameterPack);
90+
7891
static ConceptSpecializationExpr *
7992
Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs);
8093

clang/lib/AST/ASTContext.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -731,12 +731,8 @@ canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC,
731731
NewConverted.push_back(Arg);
732732
}
733733
Expr *NewIDC = ConceptSpecializationExpr::Create(
734-
C, NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(),
735-
CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(),
736-
CSE->getNamedConcept(),
737-
// Actually canonicalizing a TemplateArgumentLoc is difficult so we
738-
// simply omit the ArgsAsWritten
739-
/*ArgsAsWritten=*/nullptr, NewConverted, nullptr);
734+
C, CSE->getNamedConcept(), NewConverted, nullptr,
735+
CSE->isInstantiationDependent(), CSE->containsUnexpandedParameterPack());
740736

741737
if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))
742738
NewIDC = new (C) CXXFoldExpr(OrigFold->getType(), SourceLocation(), NewIDC,

clang/lib/AST/ExprConcepts.cpp

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,24 +46,12 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(const ASTContext &C,
4646
ASTConstraintSatisfaction::Create(C, *Satisfaction) :
4747
nullptr) {
4848
setTemplateArguments(ConvertedArgs);
49-
}
50-
51-
ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
52-
unsigned NumTemplateArgs)
53-
: Expr(ConceptSpecializationExprClass, Empty), ConceptReference(),
54-
NumTemplateArgs(NumTemplateArgs) { }
55-
56-
void ConceptSpecializationExpr::setTemplateArguments(
57-
ArrayRef<TemplateArgument> Converted) {
58-
assert(Converted.size() == NumTemplateArgs);
59-
std::uninitialized_copy(Converted.begin(), Converted.end(),
60-
getTrailingObjects<TemplateArgument>());
6149
bool IsInstantiationDependent = false;
6250
bool ContainsUnexpandedParameterPack = false;
63-
for (const TemplateArgument& Arg : Converted) {
64-
if (Arg.isInstantiationDependent())
51+
for (const TemplateArgumentLoc& ArgLoc : ArgsAsWritten->arguments()) {
52+
if (ArgLoc.getArgument().isInstantiationDependent())
6553
IsInstantiationDependent = true;
66-
if (Arg.containsUnexpandedParameterPack())
54+
if (ArgLoc.getArgument().containsUnexpandedParameterPack())
6755
ContainsUnexpandedParameterPack = true;
6856
if (ContainsUnexpandedParameterPack && IsInstantiationDependent)
6957
break;
@@ -80,6 +68,18 @@ void ConceptSpecializationExpr::setTemplateArguments(
8068
"should not be value-dependent");
8169
}
8270

71+
ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
72+
unsigned NumTemplateArgs)
73+
: Expr(ConceptSpecializationExprClass, Empty), ConceptReference(),
74+
NumTemplateArgs(NumTemplateArgs) { }
75+
76+
void ConceptSpecializationExpr::setTemplateArguments(
77+
ArrayRef<TemplateArgument> Converted) {
78+
assert(Converted.size() == NumTemplateArgs);
79+
std::uninitialized_copy(Converted.begin(), Converted.end(),
80+
getTrailingObjects<TemplateArgument>());
81+
}
82+
8383
ConceptSpecializationExpr *
8484
ConceptSpecializationExpr::Create(const ASTContext &C,
8585
NestedNameSpecifierLoc NNS,
@@ -98,6 +98,39 @@ ConceptSpecializationExpr::Create(const ASTContext &C,
9898
ConvertedArgs, Satisfaction);
9999
}
100100

101+
ConceptSpecializationExpr::ConceptSpecializationExpr(
102+
const ASTContext &C, ConceptDecl *NamedConcept,
103+
ArrayRef<TemplateArgument> ConvertedArgs,
104+
const ConstraintSatisfaction *Satisfaction, bool Dependent,
105+
bool ContainsUnexpandedParameterPack)
106+
: Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary,
107+
/*TypeDependent=*/false,
108+
/*ValueDependent=*/!Satisfaction, Dependent,
109+
ContainsUnexpandedParameterPack),
110+
ConceptReference(NestedNameSpecifierLoc(), SourceLocation(),
111+
DeclarationNameInfo(), NamedConcept,
112+
NamedConcept, nullptr),
113+
NumTemplateArgs(ConvertedArgs.size()),
114+
Satisfaction(Satisfaction ?
115+
ASTConstraintSatisfaction::Create(C, *Satisfaction) :
116+
nullptr) {
117+
setTemplateArguments(ConvertedArgs);
118+
}
119+
120+
ConceptSpecializationExpr *
121+
ConceptSpecializationExpr::Create(const ASTContext &C,
122+
ConceptDecl *NamedConcept,
123+
ArrayRef<TemplateArgument> ConvertedArgs,
124+
const ConstraintSatisfaction *Satisfaction,
125+
bool Dependent,
126+
bool ContainsUnexpandedParameterPack) {
127+
void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
128+
ConvertedArgs.size()));
129+
return new (Buffer) ConceptSpecializationExpr(
130+
C, NamedConcept, ConvertedArgs, Satisfaction, Dependent,
131+
ContainsUnexpandedParameterPack);
132+
}
133+
101134
ConceptSpecializationExpr *
102135
ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty,
103136
unsigned NumTemplateArgs) {

clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,18 @@ concept C8 = sizeof(T) > sizeof(U);
183183
template<typename... T>
184184
constexpr bool B8 = C8<T...>;
185185
// expected-error@-1{{pack expansion used as argument for non-pack parameter of concept}}
186+
187+
188+
// Make sure we correctly check for containsUnexpandedParameterPack
189+
190+
template<typename T>
191+
concept C9 = true;
192+
193+
template <typename Fn, typename... Args>
194+
using invoke = typename Fn::template invoke<Args...>;
195+
196+
template <typename C, typename... L>
197+
// The converted argument here will not containsUnexpandedParameterPack, but the
198+
// as-written one will.
199+
requires (C9<invoke<C, L>> &&...)
200+
struct S { };

0 commit comments

Comments
 (0)