Skip to content

Commit ad1ca5f

Browse files
authored
[clang] Concepts: support pack expansions for type constraints (llvm#132626)
This reverts an earlier attempt (adb0d8d and 50e5411) to support these expansions, which was limited to type arguments and which subverted the purpose of SubstTemplateTypeParmType. This propagates the ArgumentPackSubstitutionIndex along with the AssociatedConstraint, so that the pack expansion works, without needing any new transforms or otherwise any changes to the template instantiation process. This keeps the tests from the reverted commits, and adds a few more showing the new solution also works for NTTPs. Fixes llvm#131798
1 parent 2f25345 commit ad1ca5f

29 files changed

+236
-304
lines changed

clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ static std::vector<FixItHint> handleReturnType(const FunctionDecl *Function,
356356
if (!TypeText)
357357
return {};
358358

359-
SmallVector<const Expr *, 3> ExistingConstraints;
359+
SmallVector<AssociatedConstraint, 3> ExistingConstraints;
360360
Function->getAssociatedConstraints(ExistingConstraints);
361361
if (!ExistingConstraints.empty()) {
362362
// FIXME - Support adding new constraints to existing ones. Do we need to
@@ -404,7 +404,7 @@ handleTrailingTemplateType(const FunctionTemplateDecl *FunctionTemplate,
404404
if (!ConditionText)
405405
return {};
406406

407-
SmallVector<const Expr *, 3> ExistingConstraints;
407+
SmallVector<AssociatedConstraint, 3> ExistingConstraints;
408408
Function->getAssociatedConstraints(ExistingConstraints);
409409
if (!ExistingConstraints.empty()) {
410410
// FIXME - Support adding new constraints to existing ones. Do we need to

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,9 @@ Bug Fixes to C++ Support
370370
- Clang now uses the parameter location for abbreviated function templates in ``extern "C"``. (#GH46386)
371371
- Clang will emit an error instead of crash when use co_await or co_yield in
372372
C++26 braced-init-list template parameter initialization. (#GH78426)
373+
- Improved fix for an issue with pack expansions of type constraints, where this
374+
now also works if the constraint has non-type or template template parameters.
375+
(#GH131798)
373376
- Fixes matching of nested template template parameters. (#GH130362)
374377
- Correctly diagnoses template template paramters which have a pack parameter
375378
not in the last position.

clang/include/clang/AST/ASTConcept.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,12 +229,15 @@ class TypeConstraint {
229229
/// type-constraint.
230230
Expr *ImmediatelyDeclaredConstraint = nullptr;
231231
ConceptReference *ConceptRef;
232+
int ArgumentPackSubstitutionIndex;
232233

233234
public:
234235
TypeConstraint(ConceptReference *ConceptRef,
235-
Expr *ImmediatelyDeclaredConstraint)
236+
Expr *ImmediatelyDeclaredConstraint,
237+
int ArgumentPackSubstitutionIndex)
236238
: ImmediatelyDeclaredConstraint(ImmediatelyDeclaredConstraint),
237-
ConceptRef(ConceptRef) {}
239+
ConceptRef(ConceptRef),
240+
ArgumentPackSubstitutionIndex(ArgumentPackSubstitutionIndex) {}
238241

239242
/// \brief Get the immediately-declared constraint expression introduced by
240243
/// this type-constraint, that is - the constraint expression that is added to
@@ -245,6 +248,10 @@ class TypeConstraint {
245248

246249
ConceptReference *getConceptReference() const { return ConceptRef; }
247250

251+
int getArgumentPackSubstitutionIndex() const {
252+
return ArgumentPackSubstitutionIndex;
253+
}
254+
248255
// FIXME: Instead of using these concept related functions the callers should
249256
// directly work with the corresponding ConceptReference.
250257
ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); }

clang/include/clang/AST/ASTContext.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,9 +1798,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
17981798
QualType
17991799
getSubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl,
18001800
unsigned Index,
1801-
std::optional<unsigned> PackIndex,
1802-
SubstTemplateTypeParmTypeFlag Flag =
1803-
SubstTemplateTypeParmTypeFlag::None) const;
1801+
std::optional<unsigned> PackIndex) const;
18041802
QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
18051803
unsigned Index, bool Final,
18061804
const TemplateArgument &ArgPack);

clang/include/clang/AST/Decl.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,18 @@ class UnresolvedSetImpl;
7878
class VarTemplateDecl;
7979
enum class ImplicitParamKind;
8080

81+
// Holds a constraint expression along with a pack expansion index, if
82+
// expanded.
83+
struct AssociatedConstraint {
84+
const Expr *ConstraintExpr;
85+
int ArgumentPackSubstitutionIndex;
86+
87+
explicit AssociatedConstraint(const Expr *ConstraintExpr,
88+
int ArgumentPackSubstitutionIndex = -1)
89+
: ConstraintExpr(ConstraintExpr),
90+
ArgumentPackSubstitutionIndex(ArgumentPackSubstitutionIndex) {}
91+
};
92+
8193
/// The top declaration context.
8294
class TranslationUnitDecl : public Decl,
8395
public DeclContext,
@@ -2631,9 +2643,10 @@ class FunctionDecl : public DeclaratorDecl,
26312643
///
26322644
/// Use this instead of getTrailingRequiresClause for concepts APIs that
26332645
/// accept an ArrayRef of constraint expressions.
2634-
void getAssociatedConstraints(SmallVectorImpl<const Expr *> &AC) const {
2646+
void
2647+
getAssociatedConstraints(SmallVectorImpl<AssociatedConstraint> &AC) const {
26352648
if (auto *TRC = getTrailingRequiresClause())
2636-
AC.push_back(TRC);
2649+
AC.emplace_back(TRC);
26372650
}
26382651

26392652
/// Get the message that indicates why this function was deleted.

clang/include/clang/AST/DeclTemplate.h

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,8 @@ class TemplateParameterList final
195195
///
196196
/// The constraints in the resulting list are to be treated as if in a
197197
/// conjunction ("and").
198-
void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const;
198+
void getAssociatedConstraints(
199+
llvm::SmallVectorImpl<AssociatedConstraint> &AC) const;
199200

200201
bool hasAssociatedConstraints() const;
201202

@@ -422,7 +423,8 @@ class TemplateDecl : public NamedDecl {
422423
/// including constraint-expressions derived from the requires-clause,
423424
/// trailing requires-clause (for functions and methods) and constrained
424425
/// template parameters.
425-
void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const;
426+
void getAssociatedConstraints(
427+
llvm::SmallVectorImpl<AssociatedConstraint> &AC) const;
426428

427429
bool hasAssociatedConstraints() const;
428430

@@ -1341,7 +1343,8 @@ class TemplateTypeParmDecl final : public TypeDecl,
13411343
}
13421344

13431345
void setTypeConstraint(ConceptReference *CR,
1344-
Expr *ImmediatelyDeclaredConstraint);
1346+
Expr *ImmediatelyDeclaredConstraint,
1347+
int ArgumentPackSubstitutionIndex);
13451348

13461349
/// Determine whether this template parameter has a type-constraint.
13471350
bool hasTypeConstraint() const {
@@ -1353,9 +1356,11 @@ class TemplateTypeParmDecl final : public TypeDecl,
13531356
///
13541357
/// Use this instead of getTypeConstraint for concepts APIs that
13551358
/// accept an ArrayRef of constraint expressions.
1356-
void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
1359+
void getAssociatedConstraints(
1360+
llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
13571361
if (HasTypeConstraint)
1358-
AC.push_back(getTypeConstraint()->getImmediatelyDeclaredConstraint());
1362+
AC.emplace_back(getTypeConstraint()->getImmediatelyDeclaredConstraint(),
1363+
getTypeConstraint()->getArgumentPackSubstitutionIndex());
13591364
}
13601365

13611366
SourceRange getSourceRange() const override LLVM_READONLY;
@@ -1574,9 +1579,10 @@ class NonTypeTemplateParmDecl final
15741579
///
15751580
/// Use this instead of getPlaceholderImmediatelyDeclaredConstraint for
15761581
/// concepts APIs that accept an ArrayRef of constraint expressions.
1577-
void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
1582+
void getAssociatedConstraints(
1583+
llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
15781584
if (Expr *E = getPlaceholderTypeConstraint())
1579-
AC.push_back(E);
1585+
AC.emplace_back(E);
15801586
}
15811587

15821588
// Implement isa/cast/dyncast/etc.
@@ -2169,7 +2175,8 @@ class ClassTemplatePartialSpecializationDecl
21692175
///
21702176
/// The constraints in the resulting list are to be treated as if in a
21712177
/// conjunction ("and").
2172-
void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
2178+
void getAssociatedConstraints(
2179+
llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
21732180
TemplateParams->getAssociatedConstraints(AC);
21742181
}
21752182

@@ -2943,7 +2950,8 @@ class VarTemplatePartialSpecializationDecl
29432950
///
29442951
/// The constraints in the resulting list are to be treated as if in a
29452952
/// conjunction ("and").
2946-
void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
2953+
void getAssociatedConstraints(
2954+
llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
29472955
TemplateParams->getAssociatedConstraints(AC);
29482956
}
29492957

clang/include/clang/AST/PropertiesBase.td

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ def Selector : PropertyType;
137137
def SourceLocation : PropertyType;
138138
def StmtRef : RefPropertyType<"Stmt"> { let ConstWhenWriting = 1; }
139139
def ExprRef : SubclassPropertyType<"Expr", StmtRef>;
140-
def SubstTemplateTypeParmTypeFlag : EnumPropertyType;
141140
def TemplateArgument : PropertyType;
142141
def TemplateArgumentKind : EnumPropertyType<"TemplateArgument::ArgKind">;
143142
def TemplateName : DefaultValuePropertyType;

clang/include/clang/AST/Type.h

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1786,15 +1786,6 @@ enum class AutoTypeKeyword {
17861786
GNUAutoType
17871787
};
17881788

1789-
enum class SubstTemplateTypeParmTypeFlag {
1790-
None,
1791-
1792-
/// Whether to expand the pack using the stored PackIndex in place. This is
1793-
/// useful for e.g. substituting into an atomic constraint expression, where
1794-
/// that expression is part of an unexpanded pack.
1795-
ExpandPacksInPlace,
1796-
};
1797-
17981789
enum class ArraySizeModifier;
17991790
enum class ElaboratedTypeKeyword;
18001791
enum class VectorKind;
@@ -2164,9 +2155,6 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
21642155
LLVM_PREFERRED_TYPE(bool)
21652156
unsigned HasNonCanonicalUnderlyingType : 1;
21662157

2167-
LLVM_PREFERRED_TYPE(SubstTemplateTypeParmTypeFlag)
2168-
unsigned SubstitutionFlag : 1;
2169-
21702158
// The index of the template parameter this substitution represents.
21712159
unsigned Index : 15;
21722160

@@ -6409,8 +6397,7 @@ class SubstTemplateTypeParmType final
64096397
Decl *AssociatedDecl;
64106398

64116399
SubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl,
6412-
unsigned Index, std::optional<unsigned> PackIndex,
6413-
SubstTemplateTypeParmTypeFlag Flag);
6400+
unsigned Index, std::optional<unsigned> PackIndex);
64146401

64156402
public:
64166403
/// Gets the type that was substituted for the template
@@ -6439,31 +6426,21 @@ class SubstTemplateTypeParmType final
64396426
return SubstTemplateTypeParmTypeBits.PackIndex - 1;
64406427
}
64416428

6442-
SubstTemplateTypeParmTypeFlag getSubstitutionFlag() const {
6443-
return static_cast<SubstTemplateTypeParmTypeFlag>(
6444-
SubstTemplateTypeParmTypeBits.SubstitutionFlag);
6445-
}
6446-
64476429
bool isSugared() const { return true; }
64486430
QualType desugar() const { return getReplacementType(); }
64496431

64506432
void Profile(llvm::FoldingSetNodeID &ID) {
64516433
Profile(ID, getReplacementType(), getAssociatedDecl(), getIndex(),
6452-
getPackIndex(), getSubstitutionFlag());
6434+
getPackIndex());
64536435
}
64546436

64556437
static void Profile(llvm::FoldingSetNodeID &ID, QualType Replacement,
64566438
const Decl *AssociatedDecl, unsigned Index,
6457-
std::optional<unsigned> PackIndex,
6458-
SubstTemplateTypeParmTypeFlag Flag) {
6439+
std::optional<unsigned> PackIndex) {
64596440
Replacement.Profile(ID);
64606441
ID.AddPointer(AssociatedDecl);
64616442
ID.AddInteger(Index);
64626443
ID.AddInteger(PackIndex ? *PackIndex - 1 : 0);
6463-
ID.AddInteger(llvm::to_underlying(Flag));
6464-
assert((Flag != SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace ||
6465-
PackIndex) &&
6466-
"ExpandPacksInPlace needs a valid PackIndex");
64676444
}
64686445

64696446
static bool classof(const Type *T) {

clang/include/clang/AST/TypeProperties.td

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -842,14 +842,11 @@ let Class = SubstTemplateTypeParmType in {
842842
def : Property<"PackIndex", Optional<UInt32>> {
843843
let Read = [{ node->getPackIndex() }];
844844
}
845-
def : Property<"SubstitutionFlag", SubstTemplateTypeParmTypeFlag> {
846-
let Read = [{ node->getSubstitutionFlag() }];
847-
}
848845

849846
// The call to getCanonicalType here existed in ASTReader.cpp, too.
850847
def : Creator<[{
851848
return ctx.getSubstTemplateTypeParmType(
852-
replacementType, associatedDecl, Index, PackIndex, SubstitutionFlag);
849+
replacementType, associatedDecl, Index, PackIndex);
853850
}]>;
854851
}
855852

clang/include/clang/Sema/Sema.h

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11351,7 +11351,6 @@ class Sema final : public SemaBase {
1135111351
ConceptDecl *NamedConcept, NamedDecl *FoundDecl,
1135211352
const TemplateArgumentListInfo *TemplateArgs,
1135311353
TemplateTypeParmDecl *ConstrainedParameter,
11354-
QualType ConstrainedType,
1135511354
SourceLocation EllipsisLoc);
1135611355

1135711356
bool AttachTypeConstraint(AutoTypeLoc TL,
@@ -14552,13 +14551,14 @@ class Sema final : public SemaBase {
1455214551
/// \returns true if an error occurred and satisfaction could not be checked,
1455314552
/// false otherwise.
1455414553
bool CheckConstraintSatisfaction(
14555-
const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
14554+
const NamedDecl *Template,
14555+
ArrayRef<AssociatedConstraint> AssociatedConstraints,
1455614556
const MultiLevelTemplateArgumentList &TemplateArgLists,
1455714557
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
1455814558
llvm::SmallVector<Expr *, 4> Converted;
14559-
return CheckConstraintSatisfaction(Template, ConstraintExprs, Converted,
14560-
TemplateArgLists, TemplateIDRange,
14561-
Satisfaction);
14559+
return CheckConstraintSatisfaction(Template, AssociatedConstraints,
14560+
Converted, TemplateArgLists,
14561+
TemplateIDRange, Satisfaction);
1456214562
}
1456314563

1456414564
/// \brief Check whether the given list of constraint expressions are
@@ -14584,7 +14584,8 @@ class Sema final : public SemaBase {
1458414584
/// \returns true if an error occurred and satisfaction could not be checked,
1458514585
/// false otherwise.
1458614586
bool CheckConstraintSatisfaction(
14587-
const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
14587+
const NamedDecl *Template,
14588+
ArrayRef<AssociatedConstraint> AssociatedConstraints,
1458814589
llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
1458914590
const MultiLevelTemplateArgumentList &TemplateArgList,
1459014591
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction);
@@ -14662,7 +14663,7 @@ class Sema final : public SemaBase {
1466214663

1466314664
const NormalizedConstraint *getNormalizedAssociatedConstraints(
1466414665
const NamedDecl *ConstrainedDecl,
14665-
ArrayRef<const Expr *> AssociatedConstraints);
14666+
ArrayRef<AssociatedConstraint> AssociatedConstraints);
1466614667

1466714668
/// \brief Check whether the given declaration's associated constraints are
1466814669
/// at least as constrained than another declaration's according to the
@@ -14673,17 +14674,18 @@ class Sema final : public SemaBase {
1467314674
///
1467414675
/// \returns true if an error occurred, false otherwise.
1467514676
bool IsAtLeastAsConstrained(const NamedDecl *D1,
14676-
MutableArrayRef<const Expr *> AC1,
14677+
MutableArrayRef<AssociatedConstraint> AC1,
1467714678
const NamedDecl *D2,
14678-
MutableArrayRef<const Expr *> AC2, bool &Result);
14679+
MutableArrayRef<AssociatedConstraint> AC2,
14680+
bool &Result);
1467914681

1468014682
/// If D1 was not at least as constrained as D2, but would've been if a pair
1468114683
/// of atomic constraints involved had been declared in a concept and not
1468214684
/// repeated in two separate places in code.
1468314685
/// \returns true if such a diagnostic was emitted, false otherwise.
1468414686
bool MaybeEmitAmbiguousAtomicConstraintsDiagnostic(
14685-
const NamedDecl *D1, ArrayRef<const Expr *> AC1, const NamedDecl *D2,
14686-
ArrayRef<const Expr *> AC2);
14687+
const NamedDecl *D1, ArrayRef<AssociatedConstraint> AC1,
14688+
const NamedDecl *D2, ArrayRef<AssociatedConstraint> AC2);
1468714689

1468814690
private:
1468914691
/// Caches pairs of template-like decls whose associated constraints were

clang/include/clang/Sema/SemaConcept.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ struct NormalizedConstraint {
114114

115115
private:
116116
static std::optional<NormalizedConstraint>
117-
fromConstraintExprs(Sema &S, const NamedDecl *D, ArrayRef<const Expr *> E);
117+
fromAssociatedConstraints(Sema &S, const NamedDecl *D,
118+
ArrayRef<AssociatedConstraint> ACs);
118119
static std::optional<NormalizedConstraint>
119120
fromConstraintExpr(Sema &S, const NamedDecl *D, const Expr *E);
120121
};
@@ -138,7 +139,7 @@ struct alignas(ConstraintAlignment) FoldExpandedConstraint {
138139

139140
const NormalizedConstraint *getNormalizedAssociatedConstraints(
140141
Sema &S, const NamedDecl *ConstrainedDecl,
141-
ArrayRef<const Expr *> AssociatedConstraints);
142+
ArrayRef<AssociatedConstraint> AssociatedConstraints);
142143

143144
/// \brief SubsumptionChecker establishes subsumption
144145
/// between two set of constraints.
@@ -149,8 +150,10 @@ class SubsumptionChecker {
149150

150151
SubsumptionChecker(Sema &SemaRef, SubsumptionCallable Callable = {});
151152

152-
std::optional<bool> Subsumes(const NamedDecl *DP, ArrayRef<const Expr *> P,
153-
const NamedDecl *DQ, ArrayRef<const Expr *> Q);
153+
std::optional<bool> Subsumes(const NamedDecl *DP,
154+
ArrayRef<AssociatedConstraint> P,
155+
const NamedDecl *DQ,
156+
ArrayRef<AssociatedConstraint> Q);
154157

155158
bool Subsumes(const NormalizedConstraint *P, const NormalizedConstraint *Q);
156159

clang/lib/AST/ASTContext.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5447,11 +5447,10 @@ QualType ASTContext::getHLSLAttributedResourceType(
54475447
/// Retrieve a substitution-result type.
54485448
QualType ASTContext::getSubstTemplateTypeParmType(
54495449
QualType Replacement, Decl *AssociatedDecl, unsigned Index,
5450-
std::optional<unsigned> PackIndex,
5451-
SubstTemplateTypeParmTypeFlag Flag) const {
5450+
std::optional<unsigned> PackIndex) const {
54525451
llvm::FoldingSetNodeID ID;
54535452
SubstTemplateTypeParmType::Profile(ID, Replacement, AssociatedDecl, Index,
5454-
PackIndex, Flag);
5453+
PackIndex);
54555454
void *InsertPos = nullptr;
54565455
SubstTemplateTypeParmType *SubstParm =
54575456
SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -5461,7 +5460,7 @@ QualType ASTContext::getSubstTemplateTypeParmType(
54615460
!Replacement.isCanonical()),
54625461
alignof(SubstTemplateTypeParmType));
54635462
SubstParm = new (Mem) SubstTemplateTypeParmType(Replacement, AssociatedDecl,
5464-
Index, PackIndex, Flag);
5463+
Index, PackIndex);
54655464
Types.push_back(SubstParm);
54665465
SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos);
54675466
}

0 commit comments

Comments
 (0)