diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1798,6 +1798,8 @@ unsigned : NumTypeBits; + unsigned HasNonCanonicalUnderlyingType : 1; + /// 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. @@ -4985,8 +4987,12 @@ /// been replaced with these. They are used solely to record that a /// type was originally written as a template type parameter; /// therefore they are never canonical. -class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode { +class SubstTemplateTypeParmType final + : public Type, + public llvm::FoldingSetNode, + private llvm::TrailingObjects { friend class ASTContext; + friend class llvm::TrailingObjects; // The original type parameter. const TemplateTypeParmType *Replaced; @@ -5003,7 +5009,9 @@ /// Gets the type that was substituted for the template /// parameter. QualType getReplacementType() const { - return getCanonicalTypeInternal(); + return SubstTemplateTypeParmTypeBits.HasNonCanonicalUnderlyingType + ? *getTrailingObjects() + : getCanonicalTypeInternal(); } Optional getPackIndex() const { @@ -5023,7 +5031,7 @@ const TemplateTypeParmType *Replaced, QualType Replacement, Optional PackIndex) { ID.AddPointer(Replaced); - ID.AddPointer(Replacement.getAsOpaquePtr()); + Replacement.Profile(ID); ID.AddInteger(PackIndex ? *PackIndex - 1 : 0); } diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -739,10 +739,9 @@ } def : Creator<[{ - // The call to getCanonicalType here existed in ASTReader.cpp, too. return ctx.getSubstTemplateTypeParmType( cast(replacedParameter), - ctx.getCanonicalType(replacementType), PackIndex); + replacementType, PackIndex); }]>; } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4764,9 +4764,6 @@ ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, QualType Replacement, Optional PackIndex) const { - assert(Replacement.isCanonical() - && "replacement types must always be canonical"); - llvm::FoldingSetNodeID ID; SubstTemplateTypeParmType::Profile(ID, Parm, Replacement, PackIndex); void *InsertPos = nullptr; @@ -4774,8 +4771,11 @@ = SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); if (!SubstParm) { - SubstParm = new (*this, TypeAlignment) - SubstTemplateTypeParmType(Parm, Replacement, PackIndex); + void *Mem = Allocate(SubstTemplateTypeParmType::totalSizeToAlloc( + !Replacement.isCanonical()), + TypeAlignment); + SubstParm = + new (Mem) SubstTemplateTypeParmType(Parm, Replacement, PackIndex); Types.push_back(SubstParm); SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos); } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1530,8 +1530,7 @@ return ToReplacementTypeOrErr.takeError(); return Importer.getToContext().getSubstTemplateTypeParmType( - *ReplacedOrErr, ToReplacementTypeOrErr->getCanonicalType(), - T->getPackIndex()); + *ReplacedOrErr, *ToReplacementTypeOrErr, T->getPackIndex()); } ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType( diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3650,10 +3650,16 @@ } SubstTemplateTypeParmType::SubstTemplateTypeParmType( - const TemplateTypeParmType *Param, QualType Canon, + const TemplateTypeParmType *Param, QualType Replacement, Optional PackIndex) - : Type(SubstTemplateTypeParm, Canon, Canon->getDependence()), + : Type(SubstTemplateTypeParm, Replacement.getCanonicalType(), + Replacement->getDependence()), Replaced(Param) { + SubstTemplateTypeParmTypeBits.HasNonCanonicalUnderlyingType = + Replacement != getCanonicalTypeInternal(); + if (SubstTemplateTypeParmTypeBits.HasNonCanonicalUnderlyingType) + *getTrailingObjects() = Replacement; + SubstTemplateTypeParmTypeBits.PackIndex = PackIndex ? *PackIndex + 1 : 0; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3513,8 +3513,7 @@ 0, IndexReplaced, false, cast(TPL->getParam(IndexReplaced))); return SemaRef.Context.getSubstTemplateTypeParmType( - cast(TTP), Replacement.getCanonicalType(), - PackIndexReplaced); + cast(TTP), Replacement, PackIndexReplaced); }; switch (BTD->getBuiltinTemplateKind()) { diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -6408,8 +6408,6 @@ if (Replacement.isNull()) return QualType(); - // Always canonicalize the replacement type. - Replacement = SemaRef.Context.getCanonicalType(Replacement); QualType Result = SemaRef.Context.getSubstTemplateTypeParmType( T->getReplacedParameter(), Replacement, T->getPackIndex()); diff --git a/clang/test/AST/ast-dump-template-decls.cpp b/clang/test/AST/ast-dump-template-decls.cpp --- a/clang/test/AST/ast-dump-template-decls.cpp +++ b/clang/test/AST/ast-dump-template-decls.cpp @@ -162,3 +162,22 @@ // CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar pack_index 0 // CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'U' dependent contains_unexpanded_pack depth 0 index 0 pack } // namespace PR56099 + +namespace subst_default_argument { +template class A {}; +template> class D1, class D2> using D = D1; + +template class E {}; +using test1 = D; +// CHECK: TypeAliasDecl 0x{{[^ ]*}} col:7 test1 'D':'subst_default_argument::E>' +// CHECK: TemplateSpecializationType 0x{{[^ ]*}} 'A' sugar A +// CHECK-NEXT: |-TemplateArgument type 'int':'int' +// CHECK-NEXT: | `-SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar +// CHECK-NEXT: | |-TemplateTypeParmType 0x{{[^ ]*}} 'C1' dependent depth 1 index 0 +// CHECK-NEXT: | | `-TemplateTypeParm 0x{{[^ ]*}} 'C1' +// CHECK-NEXT: | `-SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar +// CHECK-NEXT: | |-TemplateTypeParmType 0x{{[^ ]*}} 'type-parameter-0-1' dependent depth 0 index 1 +// CHECK-NEXT: | `-BuiltinType 0x{{[^ ]*}} 'int' +// CHECK-NEXT: `-RecordType 0x{{[^ ]*}} 'subst_default_argument::A' +// CHECK-NEXT: `-ClassTemplateSpecialization 0x{{[^ ]*}} 'A' +} // namespace subst_default_argument