Skip to content

Commit bb164f3

Browse files
committed
[clang] support pack expansions for trailing requires clauses
This fixes a crash when evaluating constraints from trailing requires clauses, when these are part of a generic lambda which is expanded.
1 parent 1b3a8e3 commit bb164f3

31 files changed

+191
-137
lines changed

clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ computeReferencedDecls(const clang::Expr *Expr) {
100100
TraverseLambdaCapture(LExpr, &Capture, Initializer);
101101
}
102102

103-
if (clang::Expr *const RequiresClause =
104-
LExpr->getTrailingRequiresClause()) {
105-
TraverseStmt(RequiresClause);
103+
if (const clang::Expr *RequiresClause =
104+
LExpr->getTrailingRequiresClause().ConstraintExpr) {
105+
TraverseStmt(const_cast<clang::Expr *>(RequiresClause));
106106
}
107107

108108
for (auto *const TemplateParam : LExpr->getExplicitTemplateParameters())

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,8 @@ Bug Fixes to C++ Support
352352
- Improved fix for an issue with pack expansions of type constraints, where this
353353
now also works if the constraint has non-type or template template parameters.
354354
(#GH131798)
355+
- Fix crash when evaluating trailing requires clause of generic lambdas which are part of
356+
a pack expansion.
355357
- Fixes matching of nested template template parameters. (#GH130362)
356358
- Correctly diagnoses template template paramters which have a pack parameter
357359
not in the last position.

clang/include/clang/AST/ASTNodeTraverser.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -534,8 +534,8 @@ class ASTNodeTraverser
534534
for (const auto *Parameter : D->parameters())
535535
Visit(Parameter);
536536

537-
if (const Expr *TRC = D->getTrailingRequiresClause())
538-
Visit(TRC);
537+
if (const AssociatedConstraint &TRC = D->getTrailingRequiresClause())
538+
Visit(TRC.ConstraintExpr);
539539

540540
if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isDefaulted())
541541
return;

clang/include/clang/AST/Decl.h

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,17 @@ enum class ImplicitParamKind;
8181
// Holds a constraint expression along with a pack expansion index, if
8282
// expanded.
8383
struct AssociatedConstraint {
84-
const Expr *ConstraintExpr;
85-
int ArgumentPackSubstitutionIndex;
84+
const Expr *ConstraintExpr = nullptr;
85+
int ArgumentPackSubstitutionIndex = -1;
86+
87+
constexpr AssociatedConstraint() = default;
8688

8789
AssociatedConstraint(const Expr *ConstraintExpr,
8890
int ArgumentPackSubstitutionIndex)
8991
: ConstraintExpr(ConstraintExpr),
9092
ArgumentPackSubstitutionIndex(ArgumentPackSubstitutionIndex) {}
93+
94+
explicit operator bool() const { return ConstraintExpr != nullptr; }
9195
};
9296

9397
/// The top declaration context.
@@ -754,7 +758,7 @@ class DeclaratorDecl : public ValueDecl {
754758
// and constrained function decls.
755759
struct ExtInfo : public QualifierInfo {
756760
TypeSourceInfo *TInfo = nullptr;
757-
Expr *TrailingRequiresClause = nullptr;
761+
AssociatedConstraint TrailingRequiresClause;
758762
};
759763

760764
llvm::PointerUnion<TypeSourceInfo *, ExtInfo *> DeclInfo;
@@ -823,17 +827,12 @@ class DeclaratorDecl : public ValueDecl {
823827
/// \brief Get the constraint-expression introduced by the trailing
824828
/// requires-clause in the function/member declaration, or null if no
825829
/// requires-clause was provided.
826-
Expr *getTrailingRequiresClause() {
827-
return hasExtInfo() ? getExtInfo()->TrailingRequiresClause
828-
: nullptr;
829-
}
830-
831-
const Expr *getTrailingRequiresClause() const {
832-
return hasExtInfo() ? getExtInfo()->TrailingRequiresClause
833-
: nullptr;
830+
const AssociatedConstraint &getTrailingRequiresClause() const {
831+
static constexpr AssociatedConstraint Null;
832+
return hasExtInfo() ? getExtInfo()->TrailingRequiresClause : Null;
834833
}
835834

836-
void setTrailingRequiresClause(Expr *TrailingRequiresClause);
835+
void setTrailingRequiresClause(const AssociatedConstraint &AC);
837836

838837
unsigned getNumTemplateParameterLists() const {
839838
return hasExtInfo() ? getExtInfo()->NumTemplParamLists : 0;
@@ -2102,7 +2101,7 @@ class FunctionDecl : public DeclaratorDecl,
21022101
const DeclarationNameInfo &NameInfo, QualType T,
21032102
TypeSourceInfo *TInfo, StorageClass S, bool UsesFPIntrin,
21042103
bool isInlineSpecified, ConstexprSpecKind ConstexprKind,
2105-
Expr *TrailingRequiresClause = nullptr);
2104+
const AssociatedConstraint &TrailingRequiresClause);
21062105

21072106
using redeclarable_base = Redeclarable<FunctionDecl>;
21082107

@@ -2138,7 +2137,7 @@ class FunctionDecl : public DeclaratorDecl,
21382137
TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin = false,
21392138
bool isInlineSpecified = false, bool hasWrittenPrototype = true,
21402139
ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified,
2141-
Expr *TrailingRequiresClause = nullptr) {
2140+
const AssociatedConstraint &TrailingRequiresClause = {}) {
21422141
DeclarationNameInfo NameInfo(N, NLoc);
21432142
return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo, SC,
21442143
UsesFPIntrin, isInlineSpecified,
@@ -2151,7 +2150,7 @@ class FunctionDecl : public DeclaratorDecl,
21512150
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
21522151
StorageClass SC, bool UsesFPIntrin, bool isInlineSpecified,
21532152
bool hasWrittenPrototype, ConstexprSpecKind ConstexprKind,
2154-
Expr *TrailingRequiresClause);
2153+
const AssociatedConstraint &TrailingRequiresClause);
21552154

21562155
static FunctionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
21572156

@@ -2644,9 +2643,10 @@ class FunctionDecl : public DeclaratorDecl,
26442643
/// Use this instead of getTrailingRequiresClause for concepts APIs that
26452644
/// accept an ArrayRef of constraint expressions.
26462645
void
2647-
getAssociatedConstraints(SmallVectorImpl<AssociatedConstraint> &AC) const {
2648-
if (auto *TRC = getTrailingRequiresClause())
2649-
AC.emplace_back(TRC, /*ArgumentPackSubstitutionIndex=*/-1);
2646+
getAssociatedConstraints(SmallVectorImpl<AssociatedConstraint> &ACs) const {
2647+
if (const AssociatedConstraint &AC = getTrailingRequiresClause();
2648+
AC.ConstraintExpr)
2649+
ACs.emplace_back(AC);
26502650
}
26512651

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

clang/include/clang/AST/DeclCXX.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1974,7 +1974,7 @@ class CXXDeductionGuideDecl : public FunctionDecl {
19741974
const DeclarationNameInfo &NameInfo, QualType T,
19751975
TypeSourceInfo *TInfo, SourceLocation EndLocation,
19761976
CXXConstructorDecl *Ctor, DeductionCandidate Kind,
1977-
Expr *TrailingRequiresClause,
1977+
const AssociatedConstraint &TrailingRequiresClause,
19781978
const CXXDeductionGuideDecl *GeneratedFrom,
19791979
SourceDeductionGuideKind SourceKind)
19801980
: FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
@@ -2007,7 +2007,7 @@ class CXXDeductionGuideDecl : public FunctionDecl {
20072007
TypeSourceInfo *TInfo, SourceLocation EndLocation,
20082008
CXXConstructorDecl *Ctor = nullptr,
20092009
DeductionCandidate Kind = DeductionCandidate::Normal,
2010-
Expr *TrailingRequiresClause = nullptr,
2010+
const AssociatedConstraint &TrailingRequiresClause = {},
20112011
const CXXDeductionGuideDecl *SourceDG = nullptr,
20122012
SourceDeductionGuideKind SK = SourceDeductionGuideKind::None);
20132013

@@ -2115,7 +2115,7 @@ class CXXMethodDecl : public FunctionDecl {
21152115
QualType T, TypeSourceInfo *TInfo, StorageClass SC,
21162116
bool UsesFPIntrin, bool isInline,
21172117
ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
2118-
Expr *TrailingRequiresClause = nullptr)
2118+
const AssociatedConstraint &TrailingRequiresClause = {})
21192119
: FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin,
21202120
isInline, ConstexprKind, TrailingRequiresClause) {
21212121
if (EndLocation.isValid())
@@ -2128,7 +2128,7 @@ class CXXMethodDecl : public FunctionDecl {
21282128
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
21292129
StorageClass SC, bool UsesFPIntrin, bool isInline,
21302130
ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
2131-
Expr *TrailingRequiresClause = nullptr);
2131+
const AssociatedConstraint &TrailingRequiresClause = {});
21322132

21332133
static CXXMethodDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
21342134

@@ -2596,7 +2596,7 @@ class CXXConstructorDecl final
25962596
bool UsesFPIntrin, bool isInline,
25972597
bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
25982598
InheritedConstructor Inherited,
2599-
Expr *TrailingRequiresClause);
2599+
const AssociatedConstraint &TrailingRequiresClause);
26002600

26012601
void anchor() override;
26022602

@@ -2639,7 +2639,7 @@ class CXXConstructorDecl final
26392639
ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline,
26402640
bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
26412641
InheritedConstructor Inherited = InheritedConstructor(),
2642-
Expr *TrailingRequiresClause = nullptr);
2642+
const AssociatedConstraint &TrailingRequiresClause = {});
26432643

26442644
void setExplicitSpecifier(ExplicitSpecifier ES) {
26452645
assert((!ES.getExpr() ||
@@ -2858,7 +2858,7 @@ class CXXDestructorDecl : public CXXMethodDecl {
28582858
const DeclarationNameInfo &NameInfo, QualType T,
28592859
TypeSourceInfo *TInfo, bool UsesFPIntrin, bool isInline,
28602860
bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
2861-
Expr *TrailingRequiresClause = nullptr)
2861+
const AssociatedConstraint &TrailingRequiresClause = {})
28622862
: CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo,
28632863
SC_None, UsesFPIntrin, isInline, ConstexprKind,
28642864
SourceLocation(), TrailingRequiresClause) {
@@ -2873,7 +2873,7 @@ class CXXDestructorDecl : public CXXMethodDecl {
28732873
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
28742874
bool UsesFPIntrin, bool isInline, bool isImplicitlyDeclared,
28752875
ConstexprSpecKind ConstexprKind,
2876-
Expr *TrailingRequiresClause = nullptr);
2876+
const AssociatedConstraint &TrailingRequiresClause = {});
28772877
static CXXDestructorDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
28782878

28792879
void setOperatorDelete(FunctionDecl *OD, Expr *ThisArg);
@@ -2919,7 +2919,7 @@ class CXXConversionDecl : public CXXMethodDecl {
29192919
TypeSourceInfo *TInfo, bool UsesFPIntrin, bool isInline,
29202920
ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind,
29212921
SourceLocation EndLocation,
2922-
Expr *TrailingRequiresClause = nullptr)
2922+
const AssociatedConstraint &TrailingRequiresClause = {})
29232923
: CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
29242924
SC_None, UsesFPIntrin, isInline, ConstexprKind,
29252925
EndLocation, TrailingRequiresClause),
@@ -2937,7 +2937,7 @@ class CXXConversionDecl : public CXXMethodDecl {
29372937
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
29382938
bool UsesFPIntrin, bool isInline, ExplicitSpecifier ES,
29392939
ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
2940-
Expr *TrailingRequiresClause = nullptr);
2940+
const AssociatedConstraint &TrailingRequiresClause = {});
29412941
static CXXConversionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
29422942

29432943
ExplicitSpecifier getExplicitSpecifier() {

clang/include/clang/AST/ExprCXX.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2129,7 +2129,7 @@ class LambdaExpr final : public Expr,
21292129
ArrayRef<NamedDecl *> getExplicitTemplateParameters() const;
21302130

21312131
/// Get the trailing requires clause, if any.
2132-
Expr *getTrailingRequiresClause() const;
2132+
const AssociatedConstraint &getTrailingRequiresClause() const;
21332133

21342134
/// Whether this is a generic lambda.
21352135
bool isGenericLambda() const { return getTemplateParameterList(); }

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2254,8 +2254,10 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
22542254
}
22552255

22562256
// Visit the trailing requires clause, if any.
2257-
if (Expr *TrailingRequiresClause = D->getTrailingRequiresClause()) {
2258-
TRY_TO(TraverseStmt(TrailingRequiresClause));
2257+
if (const AssociatedConstraint &TrailingRequiresClause =
2258+
D->getTrailingRequiresClause()) {
2259+
TRY_TO(TraverseStmt(
2260+
const_cast<Expr *>(TrailingRequiresClause.ConstraintExpr)));
22592261
}
22602262

22612263
if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
@@ -2769,7 +2771,8 @@ DEF_TRAVERSE_STMT(LambdaExpr, {
27692771

27702772
if (S->hasExplicitResultType())
27712773
TRY_TO(TraverseTypeLoc(Proto.getReturnLoc()));
2772-
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getTrailingRequiresClause());
2774+
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(
2775+
const_cast<Expr *>(S->getTrailingRequiresClause().ConstraintExpr));
27732776

27742777
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody());
27752778
}

clang/include/clang/Sema/Sema.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8865,12 +8865,14 @@ class Sema final : public SemaBase {
88658865
CXXMethodDecl *CallOperator, CXXRecordDecl *Class,
88668866
TemplateParameterList *TemplateParams);
88678867

8868-
void CompleteLambdaCallOperator(
8869-
CXXMethodDecl *Method, SourceLocation LambdaLoc,
8870-
SourceLocation CallOperatorLoc, Expr *TrailingRequiresClause,
8871-
TypeSourceInfo *MethodTyInfo, ConstexprSpecKind ConstexprKind,
8872-
StorageClass SC, ArrayRef<ParmVarDecl *> Params,
8873-
bool HasExplicitResultType);
8868+
void
8869+
CompleteLambdaCallOperator(CXXMethodDecl *Method, SourceLocation LambdaLoc,
8870+
SourceLocation CallOperatorLoc,
8871+
const AssociatedConstraint &TrailingRequiresClause,
8872+
TypeSourceInfo *MethodTyInfo,
8873+
ConstexprSpecKind ConstexprKind, StorageClass SC,
8874+
ArrayRef<ParmVarDecl *> Params,
8875+
bool HasExplicitResultType);
88748876

88758877
/// Returns true if the explicit object parameter was invalid.
88768878
bool DiagnoseInvalidExplicitObjectParameterInLambda(CXXMethodDecl *Method,

clang/lib/AST/ASTContext.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7378,8 +7378,11 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const {
73787378
return false;
73797379
}
73807380

7381-
if (!isSameConstraintExpr(FuncX->getTrailingRequiresClause(),
7382-
FuncY->getTrailingRequiresClause()))
7381+
AssociatedConstraint ACX = FuncX->getTrailingRequiresClause(),
7382+
ACY = FuncY->getTrailingRequiresClause();
7383+
if (ACX.ArgumentPackSubstitutionIndex != ACY.ArgumentPackSubstitutionIndex)
7384+
return false;
7385+
if (!isSameConstraintExpr(ACX.ConstraintExpr, ACY.ConstraintExpr))
73837386
return false;
73847387

73857388
auto GetTypeAsWritten = [](const FunctionDecl *FD) {

clang/lib/AST/ASTImporter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3923,8 +3923,9 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
39233923
auto ToEndLoc = importChecked(Err, D->getEndLoc());
39243924
auto ToDefaultLoc = importChecked(Err, D->getDefaultLoc());
39253925
auto ToQualifierLoc = importChecked(Err, D->getQualifierLoc());
3926-
auto TrailingRequiresClause =
3927-
importChecked(Err, D->getTrailingRequiresClause());
3926+
AssociatedConstraint TrailingRequiresClause = D->getTrailingRequiresClause();
3927+
TrailingRequiresClause.ConstraintExpr =
3928+
importChecked(Err, TrailingRequiresClause.ConstraintExpr);
39283929
if (Err)
39293930
return std::move(Err);
39303931

clang/lib/AST/Decl.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2010,8 +2010,8 @@ void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
20102010
}
20112011
}
20122012

2013-
void DeclaratorDecl::setTrailingRequiresClause(Expr *TrailingRequiresClause) {
2014-
assert(TrailingRequiresClause);
2013+
void DeclaratorDecl::setTrailingRequiresClause(const AssociatedConstraint &AC) {
2014+
assert(AC.ConstraintExpr);
20152015
// Make sure the extended decl info is allocated.
20162016
if (!hasExtInfo()) {
20172017
// Save (non-extended) type source info pointer.
@@ -2022,7 +2022,7 @@ void DeclaratorDecl::setTrailingRequiresClause(Expr *TrailingRequiresClause) {
20222022
getExtInfo()->TInfo = savedTInfo;
20232023
}
20242024
// Set requires clause info.
2025-
getExtInfo()->TrailingRequiresClause = TrailingRequiresClause;
2025+
getExtInfo()->TrailingRequiresClause = AC;
20262026
}
20272027

20282028
void DeclaratorDecl::setTemplateParameterListsInfo(
@@ -3048,7 +3048,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
30483048
TypeSourceInfo *TInfo, StorageClass S,
30493049
bool UsesFPIntrin, bool isInlineSpecified,
30503050
ConstexprSpecKind ConstexprKind,
3051-
Expr *TrailingRequiresClause)
3051+
const AssociatedConstraint &TrailingRequiresClause)
30523052
: DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo,
30533053
StartLoc),
30543054
DeclContext(DK), redeclarable_base(C), Body(), ODRHash(0),
@@ -3083,7 +3083,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
30833083
static_cast<unsigned char>(DeductionCandidate::Normal);
30843084
FunctionDeclBits.HasODRHash = false;
30853085
FunctionDeclBits.FriendConstraintRefersToEnclosingTemplate = false;
3086-
if (TrailingRequiresClause)
3086+
if (TrailingRequiresClause.ConstraintExpr)
30873087
setTrailingRequiresClause(TrailingRequiresClause);
30883088
}
30893089

@@ -3572,7 +3572,7 @@ bool FunctionDecl::isMemberLikeConstrainedFriend() const {
35723572
// If these friends don't have constraints, they aren't constrained, and
35733573
// thus don't fall under temp.friend p9. Else the simple presence of a
35743574
// constraint makes them unique.
3575-
return getTrailingRequiresClause();
3575+
return bool(getTrailingRequiresClause());
35763576
}
35773577

35783578
return FriendConstraintRefersToEnclosingTemplate();
@@ -5454,7 +5454,7 @@ FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
54545454
TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin,
54555455
bool isInlineSpecified, bool hasWrittenPrototype,
54565456
ConstexprSpecKind ConstexprKind,
5457-
Expr *TrailingRequiresClause) {
5457+
const AssociatedConstraint &TrailingRequiresClause) {
54585458
FunctionDecl *New = new (C, DC) FunctionDecl(
54595459
Function, C, DC, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin,
54605460
isInlineSpecified, ConstexprKind, TrailingRequiresClause);
@@ -5465,7 +5465,7 @@ FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
54655465
FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
54665466
return new (C, ID) FunctionDecl(
54675467
Function, C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(),
5468-
nullptr, SC_None, false, false, ConstexprSpecKind::Unspecified, nullptr);
5468+
nullptr, SC_None, false, false, ConstexprSpecKind::Unspecified, {});
54695469
}
54705470

54715471
BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {

0 commit comments

Comments
 (0)