[clang] 52dce89 - [clang] Fix AST representation of expanded template arguments.
Matheus Izvekov via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 16 16:25:55 PDT 2022
Author: Matheus Izvekov
Date: 2022-09-17T01:24:46+02:00
New Revision: 52dce8900c46d5842a021619537ede598983dfde
URL: https://github.com/llvm/llvm-project/commit/52dce8900c46d5842a021619537ede598983dfde
DIFF: https://github.com/llvm/llvm-project/commit/52dce8900c46d5842a021619537ede598983dfde.diff
LOG: [clang] Fix AST representation of expanded template arguments.
Extend clang's SubstTemplateTypeParm to represent the pack substitution index.
Fixes PR56099.
Signed-off-by: Matheus Izvekov <mizvekov at gmail.com>
Differential Revision: https://reviews.llvm.org/D128113
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/ASTContext.h
clang/include/clang/AST/JSONNodeDumper.h
clang/include/clang/AST/TextNodeDumper.h
clang/include/clang/AST/Type.h
clang/include/clang/AST/TypeProperties.td
clang/lib/AST/ASTContext.cpp
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/ASTStructuralEquivalence.cpp
clang/lib/AST/JSONNodeDumper.cpp
clang/lib/AST/TextNodeDumper.cpp
clang/lib/AST/Type.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/TreeTransform.h
clang/test/AST/ast-dump-template-decls.cpp
clang/test/SemaTemplate/type_pack_element.cpp
clang/unittests/AST/ASTImporterTest.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 1ec21a7b3acec..ccc3204edd2d2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -125,6 +125,9 @@ Bug Fixes
- Fixes to builtin template emulation of regular templates.
`Issue 42102 <https://github.com/llvm/llvm-project/issues/42102>`_
`Issue 51928 <https://github.com/llvm/llvm-project/issues/51928>`_
+- A SubstTemplateTypeParmType can now represent the pack index for a
+ substitution from an expanded pack.
+ `Issue 56099 <https://github.com/llvm/llvm-project/issues/56099>`_
Improvements to Clang's diagnostics
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 14661ecc0c09c..399724159a289 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1617,10 +1617,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
QualType Wrapped);
QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced,
- QualType Replacement) const;
- QualType getSubstTemplateTypeParmPackType(
- const TemplateTypeParmType *Replaced,
- const TemplateArgument &ArgPack);
+ QualType Replacement,
+ Optional<unsigned> PackIndex) const;
+ QualType
+ getSubstTemplateTypeParmPackType(const TemplateTypeParmType *Replaced,
+ const TemplateArgument &ArgPack);
QualType
getTemplateTypeParmType(unsigned Depth, unsigned Index,
diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h
index a5575d7fd441e..3597903695797 100644
--- a/clang/include/clang/AST/JSONNodeDumper.h
+++ b/clang/include/clang/AST/JSONNodeDumper.h
@@ -220,6 +220,7 @@ class JSONNodeDumper
void VisitUnaryTransformType(const UnaryTransformType *UTT);
void VisitTagType(const TagType *TT);
void VisitTemplateTypeParmType(const TemplateTypeParmType *TTPT);
+ void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *STTPT);
void VisitAutoType(const AutoType *AT);
void VisitTemplateSpecializationType(const TemplateSpecializationType *TST);
void VisitInjectedClassNameType(const InjectedClassNameType *ICNT);
diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h
index 2e4bcdd27a8ab..e6853b12ae7e5 100644
--- a/clang/include/clang/AST/TextNodeDumper.h
+++ b/clang/include/clang/AST/TextNodeDumper.h
@@ -317,6 +317,7 @@ class TextNodeDumper
void VisitUnaryTransformType(const UnaryTransformType *T);
void VisitTagType(const TagType *T);
void VisitTemplateTypeParmType(const TemplateTypeParmType *T);
+ void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T);
void VisitAutoType(const AutoType *T);
void VisitDeducedTemplateSpecializationType(
const DeducedTemplateSpecializationType *T);
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 5897453280729..9d3aea0a3acda 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1793,6 +1793,19 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
unsigned NumArgs;
};
+ class SubstTemplateTypeParmTypeBitfields {
+ friend class SubstTemplateTypeParmType;
+
+ unsigned : NumTypeBits;
+
+ /// Represents the index within a pack if this represents a substitution
+ /// from a pack expansion. This index starts at the end of the pack and
+ /// increments towards the beginning.
+ /// Positive non-zero number represents the index + 1.
+ /// Zero means this is not substituted from an expansion.
+ unsigned PackIndex : 16;
+ };
+
class SubstTemplateTypeParmPackTypeBitfields {
friend class SubstTemplateTypeParmPackType;
@@ -1874,6 +1887,7 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
TypeWithKeywordBitfields TypeWithKeywordBits;
ElaboratedTypeBitfields ElaboratedTypeBits;
VectorTypeBitfields VectorTypeBits;
+ SubstTemplateTypeParmTypeBitfields SubstTemplateTypeParmTypeBits;
SubstTemplateTypeParmPackTypeBitfields SubstTemplateTypeParmPackTypeBits;
TemplateSpecializationTypeBitfields TemplateSpecializationTypeBits;
DependentTemplateSpecializationTypeBitfields
@@ -4977,9 +4991,8 @@ class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode {
// The original type parameter.
const TemplateTypeParmType *Replaced;
- SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon)
- : Type(SubstTemplateTypeParm, Canon, Canon->getDependence()),
- Replaced(Param) {}
+ SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon,
+ Optional<unsigned> PackIndex);
public:
/// Gets the template parameter that was substituted for.
@@ -4993,18 +5006,25 @@ class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode {
return getCanonicalTypeInternal();
}
+ Optional<unsigned> getPackIndex() const {
+ if (SubstTemplateTypeParmTypeBits.PackIndex == 0)
+ return None;
+ return SubstTemplateTypeParmTypeBits.PackIndex - 1;
+ }
+
bool isSugared() const { return true; }
QualType desugar() const { return getReplacementType(); }
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getReplacedParameter(), getReplacementType());
+ Profile(ID, getReplacedParameter(), getReplacementType(), getPackIndex());
}
static void Profile(llvm::FoldingSetNodeID &ID,
const TemplateTypeParmType *Replaced,
- QualType Replacement) {
+ QualType Replacement, Optional<unsigned> PackIndex) {
ID.AddPointer(Replaced);
ID.AddPointer(Replacement.getAsOpaquePtr());
+ ID.AddInteger(PackIndex ? *PackIndex - 1 : 0);
}
static bool classof(const Type *T) {
diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td
index c46b0bd68cadc..aa8bb79fc4706 100644
--- a/clang/include/clang/AST/TypeProperties.td
+++ b/clang/include/clang/AST/TypeProperties.td
@@ -734,12 +734,15 @@ let Class = SubstTemplateTypeParmType in {
def : Property<"replacementType", QualType> {
let Read = [{ node->getReplacementType() }];
}
+ def : Property<"PackIndex", Optional<UInt32>> {
+ let Read = [{ node->getPackIndex() }];
+ }
def : Creator<[{
// The call to getCanonicalType here existed in ASTReader.cpp, too.
return ctx.getSubstTemplateTypeParmType(
cast<TemplateTypeParmType>(replacedParameter),
- ctx.getCanonicalType(replacementType));
+ ctx.getCanonicalType(replacementType), PackIndex);
}]>;
}
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 5bf03d8f3c3aa..387a782c4b792 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -4754,19 +4754,20 @@ QualType ASTContext::getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
/// Retrieve a substitution-result type.
QualType
ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm,
- QualType Replacement) const {
+ QualType Replacement,
+ Optional<unsigned> PackIndex) const {
assert(Replacement.isCanonical()
&& "replacement types must always be canonical");
llvm::FoldingSetNodeID ID;
- SubstTemplateTypeParmType::Profile(ID, Parm, Replacement);
+ SubstTemplateTypeParmType::Profile(ID, Parm, Replacement, PackIndex);
void *InsertPos = nullptr;
SubstTemplateTypeParmType *SubstParm
= SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
if (!SubstParm) {
SubstParm = new (*this, TypeAlignment)
- SubstTemplateTypeParmType(Parm, Replacement);
+ SubstTemplateTypeParmType(Parm, Replacement, PackIndex);
Types.push_back(SubstParm);
SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos);
}
@@ -12866,9 +12867,11 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
const TemplateTypeParmType *PX = SX->getReplacedParameter();
if (PX != SY->getReplacedParameter())
return QualType();
-
- return Ctx.getSubstTemplateTypeParmType(PX,
- Ctx.getQualifiedType(Underlying));
+ auto PackIndex = SX->getPackIndex();
+ if (PackIndex != SY->getPackIndex())
+ return QualType();
+ return Ctx.getSubstTemplateTypeParmType(
+ PX, Ctx.getQualifiedType(Underlying), PackIndex);
}
case Type::ObjCTypeParam:
// FIXME: Try to merge these.
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index bd78ece6efa98..89132de0686fe 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1530,7 +1530,8 @@ ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmType(
return ToReplacementTypeOrErr.takeError();
return Importer.getToContext().getSubstTemplateTypeParmType(
- *ReplacedOrErr, ToReplacementTypeOrErr->getCanonicalType());
+ *ReplacedOrErr, ToReplacementTypeOrErr->getCanonicalType(),
+ T->getPackIndex());
}
ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType(
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index 8c7a2d5f89756..7e6055d4ffa95 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -1062,6 +1062,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!IsStructurallyEquivalent(Context, Subst1->getReplacementType(),
Subst2->getReplacementType()))
return false;
+ if (Subst1->getPackIndex() != Subst2->getPackIndex())
+ return false;
break;
}
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index a05c1f9208ee6..ae9c85e7542b3 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -683,6 +683,12 @@ void JSONNodeDumper::VisitTemplateTypeParmType(
JOS.attribute("decl", createBareDeclRef(TTPT->getDecl()));
}
+void JSONNodeDumper::VisitSubstTemplateTypeParmType(
+ const SubstTemplateTypeParmType *STTPT) {
+ if (auto PackIndex = STTPT->getPackIndex())
+ JOS.attribute("pack_index", *PackIndex);
+}
+
void JSONNodeDumper::VisitAutoType(const AutoType *AT) {
JOS.attribute("undeduced", !AT->isDeduced());
switch (AT->getKeyword()) {
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 73ba0b6329f1d..f9f149bc883f6 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1570,6 +1570,12 @@ void TextNodeDumper::VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
dumpDeclRef(T->getDecl());
}
+void TextNodeDumper::VisitSubstTemplateTypeParmType(
+ const SubstTemplateTypeParmType *T) {
+ if (auto PackIndex = T->getPackIndex())
+ OS << " pack_index " << *PackIndex;
+}
+
void TextNodeDumper::VisitAutoType(const AutoType *T) {
if (T->isDecltypeAuto())
OS << " decltype(auto)";
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index ec6003fe6559d..fa6d3a04aa965 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -1167,7 +1167,7 @@ struct SimpleTransformVisitor : public TypeVisitor<Derived, QualType> {
return QualType(T, 0);
return Ctx.getSubstTemplateTypeParmType(T->getReplacedParameter(),
- replacementType);
+ replacementType, T->getPackIndex());
}
// FIXME: Non-trivial to implement, but important for C++
@@ -3649,6 +3649,14 @@ IdentifierInfo *TemplateTypeParmType::getIdentifier() const {
return isCanonicalUnqualified() ? nullptr : getDecl()->getIdentifier();
}
+SubstTemplateTypeParmType::SubstTemplateTypeParmType(
+ const TemplateTypeParmType *Param, QualType Canon,
+ Optional<unsigned> PackIndex)
+ : Type(SubstTemplateTypeParm, Canon, Canon->getDependence()),
+ Replaced(Param) {
+ SubstTemplateTypeParmTypeBits.PackIndex = PackIndex ? *PackIndex + 1 : 0;
+}
+
SubstTemplateTypeParmPackType::SubstTemplateTypeParmPackType(
const TemplateTypeParmType *Param, QualType Canon,
const TemplateArgument &ArgPack)
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index b8cf69f7764ff..6e56cccc5ebf6 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -3505,12 +3505,14 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
TemplateParameterList *TPL = BTD->getTemplateParameters();
// Wrap the type in substitution sugar.
- auto getSubstType = [&](unsigned IndexReplaced, QualType Replacement) {
+ auto getSubstType = [&](QualType Replacement, unsigned IndexReplaced,
+ Optional<unsigned> PackIndexReplaced) {
QualType TTP = SemaRef.Context.getTemplateTypeParmType(
0, IndexReplaced, false,
cast<TemplateTypeParmDecl>(TPL->getParam(IndexReplaced)));
return SemaRef.Context.getSubstTemplateTypeParmType(
- cast<TemplateTypeParmType>(TTP), Replacement.getCanonicalType());
+ cast<TemplateTypeParmType>(TTP), Replacement.getCanonicalType(),
+ PackIndexReplaced);
};
switch (BTD->getBuiltinTemplateKind()) {
@@ -3535,7 +3537,7 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
TemplateArgumentListInfo SyntheticTemplateArgs;
// The type argument, wrapped in substitution sugar, gets reused as the
// first template argument in the synthetic template argument list.
- QualType SyntheticType = getSubstType(1, OrigType);
+ QualType SyntheticType = getSubstType(OrigType, 1, None);
SyntheticTemplateArgs.addArgument(
TemplateArgumentLoc(TemplateArgument(SyntheticType),
SemaRef.Context.getTrivialTypeSourceInfo(
@@ -3590,8 +3592,9 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
}
// We simply return the type at index `Index`.
- auto Nth = std::next(Ts.pack_begin(), Index.getExtValue());
- return getSubstType(1, Nth->getAsType());
+ int64_t N = Index.getExtValue();
+ return getSubstType(Ts.getPackAsArray()[N].getAsType(), 1,
+ Ts.pack_size() - 1 - N);
}
llvm_unreachable("unexpected BuiltinTemplateDecl!");
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 6d2498ae74f9f..09f01790a30fb 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1813,6 +1813,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
return NewT;
}
+ Optional<unsigned> PackIndex;
if (T->isParameterPack()) {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
@@ -1829,6 +1830,8 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
return Result;
}
+ // PackIndex starts from last element.
+ PackIndex = Arg.pack_size() - 1 - getSema().ArgumentPackSubstitutionIndex;
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
@@ -1838,8 +1841,8 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
QualType Replacement = Arg.getAsType();
// TODO: only do this uniquing once, at the start of instantiation.
- QualType Result
- = getSema().Context.getSubstTemplateTypeParmType(T, Replacement);
+ QualType Result = getSema().Context.getSubstTemplateTypeParmType(
+ T, Replacement, PackIndex);
SubstTemplateTypeParmTypeLoc NewTL
= TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
@@ -1875,13 +1878,13 @@ TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
return TL.getType();
}
- TemplateArgument Arg = TL.getTypePtr()->getArgumentPack();
- Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
- QualType Result = Arg.getAsType();
-
- Result = getSema().Context.getSubstTemplateTypeParmType(
- TL.getTypePtr()->getReplacedParameter(),
- Result);
+ const SubstTemplateTypeParmPackType *T = TL.getTypePtr();
+ TemplateArgument Pack = T->getArgumentPack();
+ TemplateArgument Arg = getPackSubstitutedTemplateArgument(getSema(), Pack);
+ // PackIndex starts from last element.
+ QualType Result = getSema().Context.getSubstTemplateTypeParmType(
+ T->getReplacedParameter(), Arg.getAsType(),
+ Pack.pack_size() - 1 - getSema().ArgumentPackSubstitutionIndex);
SubstTemplateTypeParmTypeLoc NewTL
= TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 2ebd5f79eabd9..9fde9ce8582d1 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -4852,7 +4852,8 @@ QualType TreeTransform<Derived>::RebuildQualifiedType(QualType T,
Replacement = SemaRef.Context.getQualifiedType(
Replacement.getUnqualifiedType(), Qs);
T = SemaRef.Context.getSubstTemplateTypeParmType(
- SubstTypeParam->getReplacedParameter(), Replacement);
+ SubstTypeParam->getReplacedParameter(), Replacement,
+ SubstTypeParam->getPackIndex());
} else if ((AutoTy = dyn_cast<AutoType>(T)) && AutoTy->isDeduced()) {
// 'auto' types behave the same way as template parameters.
QualType Deduced = AutoTy->getDeducedType();
@@ -6409,9 +6410,8 @@ QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType(
// Always canonicalize the replacement type.
Replacement = SemaRef.Context.getCanonicalType(Replacement);
- QualType Result
- = SemaRef.Context.getSubstTemplateTypeParmType(T->getReplacedParameter(),
- Replacement);
+ QualType Result = SemaRef.Context.getSubstTemplateTypeParmType(
+ T->getReplacedParameter(), Replacement, T->getPackIndex());
// Propagate type-source information.
SubstTemplateTypeParmTypeLoc NewTL
diff --git a/clang/test/AST/ast-dump-template-decls.cpp b/clang/test/AST/ast-dump-template-decls.cpp
index 13050eee7aeda..b994f1fccf158 100644
--- a/clang/test/AST/ast-dump-template-decls.cpp
+++ b/clang/test/AST/ast-dump-template-decls.cpp
@@ -136,13 +136,13 @@ template <typename... Cs> struct foo {
};
using t1 = foo<int, short>::bind<char, float>;
// CHECK: TemplateSpecializationType 0x{{[^ ]*}} 'Y<char, float, int, short>' sugar Y
-// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar
+// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar pack_index 3
// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'Bs' dependent contains_unexpanded_pack depth 0 index 0 pack
-// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar
+// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar pack_index 2
// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'Bs' dependent contains_unexpanded_pack depth 0 index 0 pack
-// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar
+// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar pack_index 1
// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'Bs' dependent contains_unexpanded_pack depth 0 index 0 pack
-// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar
+// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar pack_index 0
// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'Bs' dependent contains_unexpanded_pack depth 0 index 0 pack
template <typename... T> struct D {
@@ -152,13 +152,13 @@ using t2 = D<float, char>::B<int, short>;
// CHECK: TemplateSpecializationType 0x{{[^ ]*}} 'B<int, short>' sugar alias B
// CHECK: FunctionProtoType 0x{{[^ ]*}} 'int (int (*)(float, int), int (*)(char, short))' cdecl
// CHECK: FunctionProtoType 0x{{[^ ]*}} 'int (float, int)' cdecl
-// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar
+// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar pack_index 1
// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'T' dependent contains_unexpanded_pack depth 0 index 0 pack
-// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar
+// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar pack_index 1
// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'U' dependent contains_unexpanded_pack depth 0 index 0 pack
// CHECK: FunctionProtoType 0x{{[^ ]*}} 'int (char, short)' cdecl
-// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar
+// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar pack_index 0
// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'T' dependent contains_unexpanded_pack depth 0 index 0 pack
-// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar
+// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar pack_index 0
// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'U' dependent contains_unexpanded_pack depth 0 index 0 pack
} // namespace PR56099
diff --git a/clang/test/SemaTemplate/type_pack_element.cpp b/clang/test/SemaTemplate/type_pack_element.cpp
index 028bf177f4084..cef0d3e859954 100644
--- a/clang/test/SemaTemplate/type_pack_element.cpp
+++ b/clang/test/SemaTemplate/type_pack_element.cpp
@@ -11,7 +11,7 @@ using test1 = __type_pack_element<0, int>;
// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:35> 'int' 0
// CHECK-NEXT: |-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
-// CHECK-NEXT: `-SubstTemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'int' sugar
+// CHECK-NEXT: `-SubstTemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'int' sugar pack_index 0
// CHECK-NEXT: |-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'auto' dependent depth 0 index 1
// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} ''
// CHECK-NEXT: `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index 86a96305bed11..cb8c0bf5dcd5a 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -4793,6 +4793,44 @@ TEST_P(ASTImporterOptionSpecificTestBase,
ToD2->getDeclContext(), ToD2->getTemplateParameters()->getParam(0)));
}
+TEST_P(ASTImporterOptionSpecificTestBase, ImportSubstTemplateTypeParmType) {
+ constexpr auto Code = R"(
+ template <class A1, class... A2> struct A {
+ using B = A1(A2...);
+ };
+ template struct A<void, char, float, int, short>;
+ )";
+ Decl *FromTU = getTuDecl(Code, Lang_CXX11, "input.cpp");
+ auto *FromClass = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
+ FromTU, classTemplateSpecializationDecl());
+
+ auto testType = [&](ASTContext &Ctx, const char *Name,
+ llvm::Optional<unsigned> PackIndex) {
+ const auto *Subst = selectFirst<SubstTemplateTypeParmType>(
+ "sttp", match(substTemplateTypeParmType(
+ hasReplacementType(hasCanonicalType(asString(Name))))
+ .bind("sttp"),
+ Ctx));
+ const char *ExpectedTemplateParamName = PackIndex ? "A2" : "A1";
+ ASSERT_TRUE(Subst);
+ ASSERT_EQ(Subst->getReplacedParameter()->getIdentifier()->getName(),
+ ExpectedTemplateParamName);
+ ASSERT_EQ(Subst->getPackIndex(), PackIndex);
+ };
+ auto tests = [&](ASTContext &Ctx) {
+ testType(Ctx, "void", None);
+ testType(Ctx, "char", 3);
+ testType(Ctx, "float", 2);
+ testType(Ctx, "int", 1);
+ testType(Ctx, "short", 0);
+ };
+
+ tests(FromTU->getASTContext());
+
+ ClassTemplateSpecializationDecl *ToClass = Import(FromClass, Lang_CXX11);
+ tests(ToClass->getASTContext());
+}
+
const AstTypeMatcher<SubstTemplateTypeParmPackType>
substTemplateTypeParmPackType;
More information about the cfe-commits
mailing list