Skip to content

Commit 342cf09

Browse files
committed
[Clang] Fix handling of pack indexing types in constraints of redeclaration
When checking the constraints of a potential redeclaration we inject the template parameter as template argument to compare them. This would make clang: - try to expand these injected parameters (which are treated as packs of size 1) - inject a SubstTemplateTypeParmPackType Why expanding the pack indexing is wasteful, it's recoverable, as it was only partially expanded. However, creating SubstTemplateTypeParmPackType nodes was problematic as, before we can establish that declarations are identical, these nodes won't canonicalize to the same types (at these point they have unrelated associated decl). To avoid these issues, we track whether a set of template arguments are injected template parameters. And if they are skip some substitutions/instantiation. Cleanup pack indexing profiling as a drive-by. Fixes #138255
1 parent 160abfb commit 342cf09

File tree

10 files changed

+171
-62
lines changed

10 files changed

+171
-62
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,7 @@ Bug Fixes to C++ Support
667667
whose type depends on itself. (#GH51347), (#GH55872)
668668
- Improved parser recovery of invalid requirement expressions. In turn, this
669669
fixes crashes from follow-on processing of the invalid requirement. (#GH138820)
670+
- Fixed the handling of pack indexing types in the constraints of a member function redeclaration. (#GH138255)
670671

671672
Bug Fixes to AST Handling
672673
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/AST/ASTContext.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
221221
mutable llvm::ContextualFoldingSet<DependentDecltypeType, ASTContext &>
222222
DependentDecltypeTypes;
223223

224-
mutable llvm::FoldingSet<PackIndexingType> DependentPackIndexingTypes;
224+
mutable llvm::ContextualFoldingSet<PackIndexingType, ASTContext &>
225+
DependentPackIndexingTypes;
225226

226227
mutable llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
227228
mutable llvm::FoldingSet<ObjCTypeParamType> ObjCTypeParamTypes;

clang/include/clang/AST/Type.h

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5976,7 +5976,6 @@ class PackIndexingType final
59765976
private llvm::TrailingObjects<PackIndexingType, QualType> {
59775977
friend TrailingObjects;
59785978

5979-
const ASTContext &Context;
59805979
QualType Pattern;
59815980
Expr *IndexExpr;
59825981

@@ -5987,9 +5986,8 @@ class PackIndexingType final
59875986

59885987
protected:
59895988
friend class ASTContext; // ASTContext creates these.
5990-
PackIndexingType(const ASTContext &Context, QualType Canonical,
5991-
QualType Pattern, Expr *IndexExpr, bool FullySubstituted,
5992-
ArrayRef<QualType> Expansions = {});
5989+
PackIndexingType(QualType Canonical, QualType Pattern, Expr *IndexExpr,
5990+
bool FullySubstituted, ArrayRef<QualType> Expansions = {});
59935991

59945992
public:
59955993
Expr *getIndexExpr() const { return IndexExpr; }
@@ -6024,12 +6022,7 @@ class PackIndexingType final
60246022
return T->getTypeClass() == PackIndexing;
60256023
}
60266024

6027-
void Profile(llvm::FoldingSetNodeID &ID) {
6028-
if (hasSelectedType())
6029-
getSelectedType().Profile(ID);
6030-
else
6031-
Profile(ID, Context, getPattern(), getIndexExpr(), isFullySubstituted());
6032-
}
6025+
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context);
60336026
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
60346027
QualType Pattern, Expr *E, bool FullySubstituted);
60356028

clang/include/clang/Sema/Template.h

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/ADT/SmallVector.h"
2525
#include <cassert>
2626
#include <optional>
27+
#include <tuple>
2728
#include <utility>
2829

2930
namespace clang {
@@ -76,9 +77,18 @@ enum class TemplateSubstitutionKind : char {
7677
class MultiLevelTemplateArgumentList {
7778
/// The template argument list at a certain template depth
7879

80+
enum ListProperties {
81+
/// A 'Final' substitution means that Subst* nodes won't be built
82+
/// for the replacements.
83+
IsFinal = 0x1,
84+
/// Track if the arguments are injected template parameters.
85+
/// Injected template parameters should not be expanded.
86+
ArgumentsAreInjectedTemplateParams = 0x02,
87+
};
88+
7989
using ArgList = ArrayRef<TemplateArgument>;
8090
struct ArgumentListLevel {
81-
llvm::PointerIntPair<Decl *, 1, bool> AssociatedDeclAndFinal;
91+
llvm::PointerIntPair<Decl *, 3, unsigned> AssociatedDeclAndProperties;
8292
ArgList Args;
8393
};
8494
using ContainerType = SmallVector<ArgumentListLevel, 4>;
@@ -161,11 +171,19 @@ enum class TemplateSubstitutionKind : char {
161171
/// A template-like entity which owns the whole pattern being substituted.
162172
/// This will usually own a set of template parameters, or in some
163173
/// cases might even be a template parameter itself.
164-
std::pair<Decl *, bool> getAssociatedDecl(unsigned Depth) const {
174+
std::tuple<Decl *, bool, bool> getAssociatedDecl(unsigned Depth) const {
175+
assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
176+
auto AD = TemplateArgumentLists[getNumLevels() - Depth - 1]
177+
.AssociatedDeclAndProperties;
178+
return {AD.getPointer(), AD.getInt() & IsFinal,
179+
AD.getInt() & ArgumentsAreInjectedTemplateParams};
180+
}
181+
182+
bool ArgumentsAreInjectedParameters(unsigned Depth) const {
165183
assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
166184
auto AD = TemplateArgumentLists[getNumLevels() - Depth - 1]
167-
.AssociatedDeclAndFinal;
168-
return {AD.getPointer(), AD.getInt()};
185+
.AssociatedDeclAndProperties;
186+
return AD.getInt() & ArgumentsAreInjectedTemplateParams;
169187
}
170188

171189
/// Determine whether there is a non-NULL template argument at the
@@ -207,14 +225,15 @@ enum class TemplateSubstitutionKind : char {
207225
/// list.
208226
/// A 'Final' substitution means that Subst* nodes won't be built
209227
/// for the replacements.
210-
void addOuterTemplateArguments(Decl *AssociatedDecl, ArgList Args,
211-
bool Final) {
228+
void
229+
addOuterTemplateArguments(Decl *AssociatedDecl, ArgList Args, bool Final,
230+
bool ArgumentsAreInjectedTemplateParams = false) {
212231
assert(!NumRetainedOuterLevels &&
213232
"substituted args outside retained args?");
214233
assert(getKind() == TemplateSubstitutionKind::Specialization);
215234
TemplateArgumentLists.push_back(
216235
{{AssociatedDecl ? AssociatedDecl->getCanonicalDecl() : nullptr,
217-
Final},
236+
getProperties(Final, ArgumentsAreInjectedTemplateParams)},
218237
Args});
219238
}
220239

@@ -239,15 +258,17 @@ enum class TemplateSubstitutionKind : char {
239258
"Replacing in an empty list?");
240259

241260
if (!TemplateArgumentLists.empty()) {
242-
assert((TemplateArgumentLists[0].AssociatedDeclAndFinal.getPointer() ||
243-
TemplateArgumentLists[0].AssociatedDeclAndFinal.getPointer() ==
261+
assert((TemplateArgumentLists[0]
262+
.AssociatedDeclAndProperties.getPointer() ||
263+
TemplateArgumentLists[0]
264+
.AssociatedDeclAndProperties.getPointer() ==
244265
AssociatedDecl) &&
245266
"Trying to change incorrect declaration?");
246267
TemplateArgumentLists[0].Args = Args;
247268
} else {
248269
--NumRetainedOuterLevels;
249270
TemplateArgumentLists.push_back(
250-
{{AssociatedDecl, /*Final=*/false}, Args});
271+
{{AssociatedDecl, /*Properties=*/0}, Args});
251272
}
252273
}
253274

@@ -292,6 +313,16 @@ enum class TemplateSubstitutionKind : char {
292313
llvm::errs() << "\n";
293314
}
294315
}
316+
317+
static unsigned getProperties(bool IsFinal, bool IsInjected) {
318+
unsigned Props = 0;
319+
if (IsFinal)
320+
Props |= MultiLevelTemplateArgumentList::IsFinal;
321+
if (IsInjected)
322+
Props |=
323+
MultiLevelTemplateArgumentList::ArgumentsAreInjectedTemplateParams;
324+
return Props;
325+
}
295326
};
296327

297328
/// The context in which partial ordering of function templates occurs.

clang/lib/AST/ASTContext.cpp

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,7 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
940940
DependentSizedMatrixTypes(this_()),
941941
FunctionProtoTypes(this_(), FunctionProtoTypesLog2InitSize),
942942
DependentTypeOfExprTypes(this_()), DependentDecltypeTypes(this_()),
943-
TemplateSpecializationTypes(this_()),
943+
DependentPackIndexingTypes(this_()), TemplateSpecializationTypes(this_()),
944944
DependentTemplateSpecializationTypes(this_()),
945945
DependentBitIntTypes(this_()), SubstTemplateTemplateParmPacks(this_()),
946946
DeducedTemplates(this_()), ArrayParameterTypes(this_()),
@@ -6433,34 +6433,29 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
64336433
ArrayRef<QualType> Expansions,
64346434
UnsignedOrNone Index) const {
64356435
QualType Canonical;
6436-
if (FullySubstituted && Index) {
6436+
if (FullySubstituted && Index)
64376437
Canonical = getCanonicalType(Expansions[*Index]);
6438-
} else {
6439-
llvm::FoldingSetNodeID ID;
6440-
PackIndexingType::Profile(ID, *this, Pattern.getCanonicalType(), IndexExpr,
6441-
FullySubstituted);
6442-
void *InsertPos = nullptr;
6443-
PackIndexingType *Canon =
6444-
DependentPackIndexingTypes.FindNodeOrInsertPos(ID, InsertPos);
6445-
if (!Canon) {
6446-
void *Mem = Allocate(
6447-
PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
6448-
TypeAlignment);
6449-
Canon = new (Mem)
6450-
PackIndexingType(*this, QualType(), Pattern.getCanonicalType(),
6451-
IndexExpr, FullySubstituted, Expansions);
6452-
DependentPackIndexingTypes.InsertNode(Canon, InsertPos);
6453-
}
6454-
Canonical = QualType(Canon, 0);
6455-
}
6438+
else if (!Pattern.isCanonical())
6439+
Canonical = getPackIndexingType(Pattern.getCanonicalType(), IndexExpr,
6440+
FullySubstituted, Expansions, Index);
6441+
6442+
llvm::FoldingSetNodeID ID;
6443+
PackIndexingType::Profile(ID, *this, Pattern, IndexExpr, FullySubstituted);
6444+
void *InsertPos = nullptr;
6445+
PackIndexingType *Canon =
6446+
DependentPackIndexingTypes.FindNodeOrInsertPos(ID, InsertPos);
6447+
if (Canon)
6448+
return QualType(Canon, 0);
64566449

64576450
void *Mem =
64586451
Allocate(PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
64596452
TypeAlignment);
6460-
auto *T = new (Mem) PackIndexingType(*this, Canonical, Pattern, IndexExpr,
6461-
FullySubstituted, Expansions);
6462-
Types.push_back(T);
6463-
return QualType(T, 0);
6453+
6454+
Canon = new (Mem) PackIndexingType(Canonical, Pattern, IndexExpr,
6455+
FullySubstituted, Expansions);
6456+
DependentPackIndexingTypes.InsertNode(Canon, InsertPos);
6457+
Types.push_back(Canon);
6458+
return QualType(Canon, 0);
64646459
}
64656460

64666461
/// getUnaryTransformationType - We don't unique these, since the memory

clang/lib/AST/Type.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4126,14 +4126,14 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,
41264126
E->Profile(ID, Context, true);
41274127
}
41284128

4129-
PackIndexingType::PackIndexingType(const ASTContext &Context,
4130-
QualType Canonical, QualType Pattern,
4129+
PackIndexingType::PackIndexingType(QualType Canonical, QualType Pattern,
41314130
Expr *IndexExpr, bool FullySubstituted,
41324131
ArrayRef<QualType> Expansions)
41334132
: Type(PackIndexing, Canonical,
41344133
computeDependence(Pattern, IndexExpr, Expansions)),
4135-
Context(Context), Pattern(Pattern), IndexExpr(IndexExpr),
4136-
Size(Expansions.size()), FullySubstituted(FullySubstituted) {
4134+
Pattern(Pattern), IndexExpr(IndexExpr), Size(Expansions.size()),
4135+
FullySubstituted(FullySubstituted) {
4136+
41374137
llvm::uninitialized_copy(Expansions, getTrailingObjects<QualType>());
41384138
}
41394139

@@ -4174,6 +4174,14 @@ PackIndexingType::computeDependence(QualType Pattern, Expr *IndexExpr,
41744174
return TD;
41754175
}
41764176

4177+
void PackIndexingType::Profile(llvm::FoldingSetNodeID &ID,
4178+
const ASTContext &Context) {
4179+
if (hasSelectedType() && isFullySubstituted())
4180+
getSelectedType().Profile(ID);
4181+
else
4182+
Profile(ID, Context, getPattern(), getIndexExpr(), isFullySubstituted());
4183+
}
4184+
41774185
void PackIndexingType::Profile(llvm::FoldingSetNodeID &ID,
41784186
const ASTContext &Context, QualType Pattern,
41794187
Expr *E, bool FullySubstituted) {

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ Response HandleFunctionTemplateDecl(Sema &SemaRef,
338338
const_cast<FunctionTemplateDecl *>(FTD),
339339
const_cast<FunctionTemplateDecl *>(FTD)->getInjectedTemplateArgs(
340340
SemaRef.Context),
341-
/*Final=*/false);
341+
/*Final=*/false, /*InjectedTemplateParams=*/true);
342342

343343
NestedNameSpecifier *NNS = FTD->getTemplatedDecl()->getQualifier();
344344

@@ -363,18 +363,20 @@ Response HandleFunctionTemplateDecl(Sema &SemaRef,
363363
// This meets the contract in
364364
// TreeTransform::TryExpandParameterPacks that the template arguments
365365
// for unexpanded parameters should be of a Pack kind.
366+
bool Injected = false;
366367
if (TSTy->isCurrentInstantiation()) {
367368
auto *RD = TSTy->getCanonicalTypeInternal()->getAsCXXRecordDecl();
368-
if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate())
369+
if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) {
369370
Arguments = CTD->getInjectedTemplateArgs(SemaRef.Context);
370-
else if (auto *Specialization =
371-
dyn_cast<ClassTemplateSpecializationDecl>(RD))
371+
Injected = true;
372+
} else if (auto *Specialization =
373+
dyn_cast<ClassTemplateSpecializationDecl>(RD))
372374
Arguments =
373375
Specialization->getTemplateInstantiationArgs().asArray();
374376
}
375377
Result.addOuterTemplateArguments(
376378
TSTy->getTemplateName().getAsTemplateDecl(), Arguments,
377-
/*Final=*/false);
379+
/*Final=*/false, /*InjectedTemplateParams=*/Injected);
378380
}
379381
}
380382

@@ -399,7 +401,7 @@ Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec,
399401
Result.addOuterTemplateArguments(
400402
const_cast<CXXRecordDecl *>(Rec),
401403
ClassTemplate->getInjectedTemplateArgs(SemaRef.Context),
402-
/*Final=*/false);
404+
/*Final=*/false, /*InjectedTemplateParams=*/true);
403405
}
404406

405407
if (const MemberSpecializationInfo *MSInfo =
@@ -1902,7 +1904,9 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
19021904

19031905
TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition());
19041906

1905-
if (TTP->isParameterPack()) {
1907+
if (TemplateArgs.ArgumentsAreInjectedParameters(TTP->getDepth())) {
1908+
Arg = getTemplateArgumentPackPatternForRewrite(Arg);
1909+
} else if (TTP->isParameterPack()) {
19061910
assert(Arg.getKind() == TemplateArgument::Pack &&
19071911
"Missing argument pack");
19081912
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
@@ -2060,14 +2064,17 @@ TemplateName TemplateInstantiator::TransformTemplateName(
20602064
return Arg.getAsTemplate();
20612065
}
20622066

2063-
auto [AssociatedDecl, Final] =
2067+
auto [AssociatedDecl, Final, ArgumentsAreInjectedTemplateParams] =
20642068
TemplateArgs.getAssociatedDecl(TTP->getDepth());
20652069
UnsignedOrNone PackIndex = std::nullopt;
20662070
if (TTP->isParameterPack()) {
20672071
assert(Arg.getKind() == TemplateArgument::Pack &&
20682072
"Missing argument pack");
20692073

2070-
if (!getSema().ArgPackSubstIndex) {
2074+
if (ArgumentsAreInjectedTemplateParams)
2075+
Arg = getTemplateArgumentPackPatternForRewrite(Arg);
2076+
2077+
else if (!getSema().ArgPackSubstIndex) {
20712078
// We have the template argument pack to substitute, but we're not
20722079
// actually expanding the enclosing pack expansion yet. So, just
20732080
// keep the entire argument pack.
@@ -2139,7 +2146,7 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
21392146
return Arg.getAsExpr();
21402147
}
21412148

2142-
auto [AssociatedDecl, Final] =
2149+
auto [AssociatedDecl, Final, ArgumentsAreInjectedTemplateParams] =
21432150
TemplateArgs.getAssociatedDecl(NTTP->getDepth());
21442151
UnsignedOrNone PackIndex = std::nullopt;
21452152
if (NTTP->isParameterPack()) {
@@ -2592,14 +2599,22 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
25922599
return NewT;
25932600
}
25942601

2595-
auto [AssociatedDecl, Final] =
2602+
auto [AssociatedDecl, Final, ArgumentsAreInjectedTemplateParams] =
25962603
TemplateArgs.getAssociatedDecl(T->getDepth());
25972604
UnsignedOrNone PackIndex = std::nullopt;
25982605
if (T->isParameterPack()) {
25992606
assert(Arg.getKind() == TemplateArgument::Pack &&
26002607
"Missing argument pack");
26012608

26022609
if (!getSema().ArgPackSubstIndex) {
2610+
2611+
if (ArgumentsAreInjectedTemplateParams) {
2612+
TemplateTypeParmTypeLoc NewTL =
2613+
TLB.push<TemplateTypeParmTypeLoc>(TL.getType());
2614+
NewTL.setNameLoc(TL.getNameLoc());
2615+
return TL.getType();
2616+
}
2617+
26032618
// We have the template argument pack, but we're not expanding the
26042619
// enclosing pack expansion yet. Just save the template argument
26052620
// pack for later substitution.

clang/lib/Sema/SemaTemplateVariadic.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,13 @@ bool Sema::CheckParameterPacksForExpansion(
823823
continue;
824824
}
825825

826+
// Template arguments that are injected template parameters
827+
// Cannot be expanded, even if they constitute a pack expansion.
828+
if (TemplateArgs.ArgumentsAreInjectedParameters(Depth)) {
829+
ShouldExpand = false;
830+
continue;
831+
}
832+
826833
// Determine the size of the argument pack.
827834
ArrayRef<TemplateArgument> Pack =
828835
TemplateArgs(Depth, Index).getPackAsArray();

clang/lib/Sema/TreeTransform.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6884,7 +6884,7 @@ TreeTransform<Derived>::TransformPackIndexingType(TypeLocBuilder &TLB,
68846884
assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
68856885
// Determine whether the set of unexpanded parameter packs can and should
68866886
// be expanded.
6887-
bool ShouldExpand = true;
6887+
bool ShouldExpand = false;
68886888
bool RetainExpansion = false;
68896889
UnsignedOrNone NumExpansions = std::nullopt;
68906890
if (getDerived().TryExpandParameterPacks(TL.getEllipsisLoc(), SourceRange(),

0 commit comments

Comments
 (0)