Skip to content

Commit 24e912a

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 - 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 24e912a

File tree

10 files changed

+175
-69
lines changed

10 files changed

+175
-69
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: 40 additions & 12 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,17 @@ 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.
82+
IsFinal = 0x1,
83+
/// Track if the arguments are injected template parameters.
84+
/// Injected template parameters should not be expanded.
85+
ArgumentsAreInjectedTemplateParams = 0x02,
86+
};
87+
7988
using ArgList = ArrayRef<TemplateArgument>;
8089
struct ArgumentListLevel {
81-
llvm::PointerIntPair<Decl *, 1, bool> AssociatedDeclAndFinal;
90+
llvm::PointerIntPair<Decl *, 3, unsigned> AssociatedDeclAndProperties;
8291
ArgList Args;
8392
};
8493
using ContainerType = SmallVector<ArgumentListLevel, 4>;
@@ -161,11 +170,19 @@ enum class TemplateSubstitutionKind : char {
161170
/// A template-like entity which owns the whole pattern being substituted.
162171
/// This will usually own a set of template parameters, or in some
163172
/// cases might even be a template parameter itself.
164-
std::pair<Decl *, bool> getAssociatedDecl(unsigned Depth) const {
173+
std::tuple<Decl *, bool, bool> getAssociatedDecl(unsigned Depth) const {
174+
assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
175+
auto AD = TemplateArgumentLists[getNumLevels() - Depth - 1]
176+
.AssociatedDeclAndProperties;
177+
return {AD.getPointer(), AD.getInt() & IsFinal,
178+
AD.getInt() & ArgumentsAreInjectedTemplateParams};
179+
}
180+
181+
bool ArgumentsAreInjectedParameters(unsigned Depth) const {
165182
assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
166183
auto AD = TemplateArgumentLists[getNumLevels() - Depth - 1]
167-
.AssociatedDeclAndFinal;
168-
return {AD.getPointer(), AD.getInt()};
184+
.AssociatedDeclAndProperties;
185+
return AD.getInt() & ArgumentsAreInjectedTemplateParams;
169186
}
170187

171188
/// Determine whether there is a non-NULL template argument at the
@@ -205,16 +222,15 @@ enum class TemplateSubstitutionKind : char {
205222

206223
/// Add a new outmost level to the multi-level template argument
207224
/// list.
208-
/// A 'Final' substitution means that Subst* nodes won't be built
209-
/// for the replacements.
210-
void addOuterTemplateArguments(Decl *AssociatedDecl, ArgList Args,
211-
bool Final) {
225+
void
226+
addOuterTemplateArguments(Decl *AssociatedDecl, ArgList Args, bool Final,
227+
bool ArgumentsAreInjectedTemplateParams = false) {
212228
assert(!NumRetainedOuterLevels &&
213229
"substituted args outside retained args?");
214230
assert(getKind() == TemplateSubstitutionKind::Specialization);
215231
TemplateArgumentLists.push_back(
216232
{{AssociatedDecl ? AssociatedDecl->getCanonicalDecl() : nullptr,
217-
Final},
233+
getProperties(Final, ArgumentsAreInjectedTemplateParams)},
218234
Args});
219235
}
220236

@@ -239,15 +255,17 @@ enum class TemplateSubstitutionKind : char {
239255
"Replacing in an empty list?");
240256

241257
if (!TemplateArgumentLists.empty()) {
242-
assert((TemplateArgumentLists[0].AssociatedDeclAndFinal.getPointer() ||
243-
TemplateArgumentLists[0].AssociatedDeclAndFinal.getPointer() ==
258+
assert((TemplateArgumentLists[0]
259+
.AssociatedDeclAndProperties.getPointer() ||
260+
TemplateArgumentLists[0]
261+
.AssociatedDeclAndProperties.getPointer() ==
244262
AssociatedDecl) &&
245263
"Trying to change incorrect declaration?");
246264
TemplateArgumentLists[0].Args = Args;
247265
} else {
248266
--NumRetainedOuterLevels;
249267
TemplateArgumentLists.push_back(
250-
{{AssociatedDecl, /*Final=*/false}, Args});
268+
{{AssociatedDecl, /*Properties=*/0}, Args});
251269
}
252270
}
253271

@@ -292,6 +310,16 @@ enum class TemplateSubstitutionKind : char {
292310
llvm::errs() << "\n";
293311
}
294312
}
313+
314+
static unsigned getProperties(bool IsFinal, bool IsInjected) {
315+
unsigned Props = 0;
316+
if (IsFinal)
317+
Props |= MultiLevelTemplateArgumentList::IsFinal;
318+
if (IsInjected)
319+
Props |=
320+
MultiLevelTemplateArgumentList::ArgumentsAreInjectedTemplateParams;
321+
return Props;
322+
}
295323
};
296324

297325
/// 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: 31 additions & 16 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 =
@@ -1476,8 +1478,8 @@ namespace {
14761478
}
14771479
}
14781480

1479-
TemplateArgument
1480-
getTemplateArgumentPackPatternForRewrite(const TemplateArgument &TA) {
1481+
TemplateArgument getTemplateArgumentorUnsubstitutedExpansionPattern(
1482+
const TemplateArgument &TA) {
14811483
if (TA.getKind() != TemplateArgument::Pack)
14821484
return TA;
14831485
if (SemaRef.ArgPackSubstIndex)
@@ -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 = getTemplateArgumentorUnsubstitutedExpansionPattern(Arg);
1909+
} else if (TTP->isParameterPack()) {
19061910
assert(Arg.getKind() == TemplateArgument::Pack &&
19071911
"Missing argument pack");
19081912
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
@@ -2054,20 +2058,23 @@ TemplateName TemplateInstantiator::TransformTemplateName(
20542058
if (TemplateArgs.isRewrite()) {
20552059
// We're rewriting the template parameter as a reference to another
20562060
// template parameter.
2057-
Arg = getTemplateArgumentPackPatternForRewrite(Arg);
2061+
Arg = getTemplateArgumentorUnsubstitutedExpansionPattern(Arg);
20582062
assert(Arg.getKind() == TemplateArgument::Template &&
20592063
"unexpected nontype template argument kind in template rewrite");
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 = getTemplateArgumentorUnsubstitutedExpansionPattern(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.
@@ -2131,15 +2138,15 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
21312138
if (TemplateArgs.isRewrite()) {
21322139
// We're rewriting the template parameter as a reference to another
21332140
// template parameter.
2134-
Arg = getTemplateArgumentPackPatternForRewrite(Arg);
2141+
Arg = getTemplateArgumentorUnsubstitutedExpansionPattern(Arg);
21352142
assert(Arg.getKind() == TemplateArgument::Expression &&
21362143
"unexpected nontype template argument kind in template rewrite");
21372144
// FIXME: This can lead to the same subexpression appearing multiple times
21382145
// in a complete expression.
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()) {
@@ -2584,22 +2591,30 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
25842591
if (TemplateArgs.isRewrite()) {
25852592
// We're rewriting the template parameter as a reference to another
25862593
// template parameter.
2587-
Arg = getTemplateArgumentPackPatternForRewrite(Arg);
2594+
Arg = getTemplateArgumentorUnsubstitutedExpansionPattern(Arg);
25882595
assert(Arg.getKind() == TemplateArgument::Type &&
25892596
"unexpected nontype template argument kind in template rewrite");
25902597
QualType NewT = Arg.getAsType();
25912598
TLB.pushTrivial(SemaRef.Context, NewT, TL.getNameLoc());
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.

0 commit comments

Comments
 (0)