diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1629,22 +1629,24 @@ bool ParameterPack, TemplateTypeParmDecl *ParmDecl = nullptr) const; - QualType getTemplateSpecializationType(TemplateName T, - ArrayRef Args, - QualType Canon = QualType()) const; - - QualType - getCanonicalTemplateSpecializationType(TemplateName T, - ArrayRef Args) const; - - QualType getTemplateSpecializationType(TemplateName T, - ArrayRef Args, - QualType Canon = QualType()) const; - - TypeSourceInfo * - getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc, - const TemplateArgumentListInfo &Args, - QualType Canon = QualType()) const; + QualType getTemplateSpecializationType( + TemplateName T, ArrayRef SpecifiedArgs, + ArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Canon = QualType()) const; + + QualType getTemplateSpecializationType( + TemplateName T, ArrayRef SpecifiedArgs, + ArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Canon = QualType()) const; + + TypeSourceInfo *getTemplateSpecializationTypeInfo( + TemplateName T, SourceLocation TLoc, + const TemplateArgumentListInfo &SpecifiedArgs, + ArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Canon = QualType()) const; QualType getParenType(QualType NamedType) const; @@ -2718,6 +2720,12 @@ TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg) const; + /// Canonicalize the given template argument list. + /// + /// Returns true if any arguments were non-canonical, false otherwise. + bool + canonicalizeTemplateArguments(MutableArrayRef Args) const; + /// Type Query functions. If the type is an instance of the specified class, /// return the Type pointer for the underlying maximally pretty type. This /// is a member of ASTContext because this may need to do some amount of diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1099,7 +1099,10 @@ DEF_TRAVERSE_TYPE(TemplateSpecializationType, { TRY_TO(TraverseTemplateName(T->getTemplateName())); - TRY_TO(TraverseTemplateArguments(T->template_arguments())); + if (T->isCanonicalUnqualified()) + TRY_TO(TraverseTemplateArguments(T->getConvertedArguments())); + else + TRY_TO(TraverseTemplateArguments(T->template_arguments())); }) DEF_TRAVERSE_TYPE(InjectedClassNameType, {}) 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 @@ -1870,10 +1870,9 @@ /// specialization, which is expected to be able to hold at least 1024 /// according to [implimits]. However, as this limit is somewhat easy to /// hit with template metaprogramming we'd prefer to keep it as large - /// as possible. At the moment it has been left as a non-bitfield since - /// this type safely fits in 64 bits as an unsigned, so there is no reason - /// to introduce the performance impact of a bitfield. - unsigned NumArgs; + /// as possible. + unsigned NumSpecifiedArgs : 16; + unsigned NumConvertedArgs : 16; }; class DependentTemplateSpecializationTypeBitfields { @@ -2423,6 +2422,18 @@ /// immediately following this class. template const T *getAs() const; + /// Look through sugar for an instance of TemplateSpecializationType which + /// is not a type alias. + const TemplateSpecializationType * + getAsNonAliasTemplateSpecializationType() const; + + const TemplateSpecializationType * + castAsNonAliasTemplateSpecializationType() const { + auto TST = getAsNonAliasTemplateSpecializationType(); + assert(TST && "not a TemplateSpecializationType"); + return TST; + } + /// Member-template getAsAdjusted. Look through specific kinds /// of sugar (parens, attributes, etc) for an instance of \. /// This is used when you need to walk over sugar nodes that represent some @@ -5365,10 +5376,10 @@ /// replacement must, recursively, be one of these). TemplateName Template; - TemplateSpecializationType(TemplateName T, - ArrayRef Args, - QualType Canon, - QualType Aliased); + TemplateSpecializationType(TemplateName T, bool IsAlias, + ArrayRef SpecifiedArgs, + ArrayRef ConvertedArgs, + QualType Underlying); public: /// Determine whether any of the given template arguments are dependent. @@ -5423,9 +5434,11 @@ ArrayRef template_arguments() const { return {reinterpret_cast(this + 1), - TemplateSpecializationTypeBits.NumArgs}; + TemplateSpecializationTypeBits.NumSpecifiedArgs}; } + ArrayRef getConvertedArguments() const; + bool isSugared() const { return !isDependentType() || isCurrentInstantiation() || isTypeAlias(); } @@ -5436,8 +5449,9 @@ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx); static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, - ArrayRef Args, - const ASTContext &Context); + ArrayRef SpecifiedArgs, + ArrayRef ConvertedArgs, + QualType Underlying, const ASTContext &Context); static bool classof(const Type *T) { return T->getTypeClass() == TemplateSpecialization; 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 @@ -660,29 +660,27 @@ def : Property<"templateName", TemplateName> { let Read = [{ node->getTemplateName() }]; } - def : Property<"templateArguments", Array> { + def : Property<"specifiedArguments", Array> { let Read = [{ node->template_arguments() }]; } - def : Property<"underlyingType", Optional> { + def : Property<"convertedArguments", Array> { + let Read = [{ node->getConvertedArguments() }]; + } + def : Property<"underlyingType", QualType> { let Read = [{ node->isTypeAlias() - ? llvm::Optional(node->getAliasedType()) + ? node->getAliasedType() : node->isCanonicalUnqualified() - ? llvm::None - : llvm::Optional(node->getCanonicalTypeInternal()) + ? QualType() : node->getCanonicalTypeInternal() }]; } def : Creator<[{ - QualType result; - if (!underlyingType) { - result = ctx.getCanonicalTemplateSpecializationType(templateName, - templateArguments); - } else { - result = ctx.getTemplateSpecializationType(templateName, - templateArguments, - *underlyingType); - } + QualType result = ctx.getTemplateSpecializationType(templateName, + specifiedArguments, + convertedArguments, + /*CanonicalConvertedArguments=*/{}, + underlyingType); if (dependent) const_cast(result.getTypePtr()) ->addDependence(TypeDependence::DependentInstantiation); diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -249,6 +249,10 @@ void readTemplateArgumentList(SmallVectorImpl &TemplArgs, bool Canonicalize = false); + /// Read a template argument list. + const TemplateArgumentList * + readTemplateArgumentList(bool Canonicalize = false); + /// Read a UnresolvedSet structure, advancing Idx. void readUnresolvedSet(LazyASTUnresolvedSet &Set); 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 @@ -3049,12 +3049,19 @@ ArrayRef Args, bool &AnyNonCanonArgs) { SmallVector CanonArgs(Args); - for (auto &Arg : CanonArgs) { + AnyNonCanonArgs |= C.canonicalizeTemplateArguments(CanonArgs); + return CanonArgs; +} + +bool ASTContext::canonicalizeTemplateArguments( + MutableArrayRef Args) const { + bool AnyNonCanonArgs = false; + for (auto &Arg : Args) { TemplateArgument OrigArg = Arg; - Arg = C.getCanonicalTemplateArgument(Arg); + Arg = getCanonicalTemplateArgument(Arg); AnyNonCanonArgs |= !Arg.structurallyEquals(OrigArg); } - return CanonArgs; + return AnyNonCanonArgs; } //===----------------------------------------------------------------------===// @@ -4934,41 +4941,41 @@ return QualType(TypeParm, 0); } -TypeSourceInfo * -ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, - SourceLocation NameLoc, - const TemplateArgumentListInfo &Args, - QualType Underlying) const { - assert(!Name.getAsDependentTemplateName() && - "No dependent template names here!"); - QualType TST = - getTemplateSpecializationType(Name, Args.arguments(), Underlying); +TypeSourceInfo *ASTContext::getTemplateSpecializationTypeInfo( + TemplateName Name, SourceLocation NameLoc, + const TemplateArgumentListInfo &SpecifiedArgs, + ArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Underlying) const { + QualType TST = getTemplateSpecializationType( + Name, SpecifiedArgs.arguments(), SugaredConvertedArgs, + CanonicalConvertedArgs, Underlying); TypeSourceInfo *DI = CreateTypeSourceInfo(TST); TemplateSpecializationTypeLoc TL = DI->getTypeLoc().castAs(); TL.setTemplateKeywordLoc(SourceLocation()); TL.setTemplateNameLoc(NameLoc); - TL.setLAngleLoc(Args.getLAngleLoc()); - TL.setRAngleLoc(Args.getRAngleLoc()); + TL.setLAngleLoc(SpecifiedArgs.getLAngleLoc()); + TL.setRAngleLoc(SpecifiedArgs.getRAngleLoc()); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) - TL.setArgLocInfo(i, Args[i].getLocInfo()); + TL.setArgLocInfo(i, SpecifiedArgs[i].getLocInfo()); return DI; } -QualType -ASTContext::getTemplateSpecializationType(TemplateName Template, - ArrayRef Args, - QualType Underlying) const { - assert(!Template.getAsDependentTemplateName() && - "No dependent template names here!"); - - SmallVector ArgVec; - ArgVec.reserve(Args.size()); - for (const TemplateArgumentLoc &Arg : Args) - ArgVec.push_back(Arg.getArgument()); +QualType ASTContext::getTemplateSpecializationType( + TemplateName Template, ArrayRef SpecifiedArgs, + ArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Underlying) const { + SmallVector SpecifiedArgVec; + SpecifiedArgVec.reserve(SpecifiedArgs.size()); + for (const TemplateArgumentLoc &Arg : SpecifiedArgs) + SpecifiedArgVec.push_back(Arg.getArgument()); - return getTemplateSpecializationType(Template, ArgVec, Underlying); + return getTemplateSpecializationType(Template, SpecifiedArgVec, + SugaredConvertedArgs, + CanonicalConvertedArgs, Underlying); } #ifndef NDEBUG @@ -4981,84 +4988,88 @@ } #endif -QualType -ASTContext::getTemplateSpecializationType(TemplateName Template, - ArrayRef Args, - QualType Underlying) const { +QualType ASTContext::getTemplateSpecializationType( + TemplateName Template, ArrayRef SpecifiedArgs, + ArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Underlying) const { assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); - // Look through qualified template names. - if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) - Template = QTN->getUnderlyingTemplate(); - const auto *TD = Template.getAsTemplateDecl(); - bool IsTypeAlias = TD && TD->isTypeAlias(); - QualType CanonType; - if (!Underlying.isNull()) - CanonType = getCanonicalType(Underlying); - else { - // We can get here with an alias template when the specialization contains - // a pack expansion that does not match up with a parameter pack. - assert((!IsTypeAlias || hasAnyPackExpansions(Args)) && - "Caller must compute aliased type"); - IsTypeAlias = false; - CanonType = getCanonicalTemplateSpecializationType(Template, Args); + bool AnyNonCanonArgs = false; + if (CanonicalConvertedArgs.size() != 0) { +#ifndef NDEBUG + for (const TemplateArgument &A : CanonicalConvertedArgs) + assert(A.structurallyEquals(getCanonicalTemplateArgument(A))); +#endif + if (SugaredConvertedArgs.empty()) { + SugaredConvertedArgs = CanonicalConvertedArgs; + } else { + assert(SugaredConvertedArgs.size() == CanonicalConvertedArgs.size()); + for (unsigned I = 0; I < SugaredConvertedArgs.size(); ++I) { + if (!CanonicalConvertedArgs[I].structurallyEquals( + SugaredConvertedArgs[I])) { + AnyNonCanonArgs = true; + break; + } + } + } } - // Allocate the (non-canonical) template specialization type, but don't - // try to unique it: these types typically have location information that - // we don't unique and don't want to lose. - void *Mem = Allocate(sizeof(TemplateSpecializationType) + - sizeof(TemplateArgument) * Args.size() + - (IsTypeAlias? sizeof(QualType) : 0), - TypeAlignment); - auto *Spec - = new (Mem) TemplateSpecializationType(Template, Args, CanonType, - IsTypeAlias ? Underlying : QualType()); - - Types.push_back(Spec); - return QualType(Spec, 0); -} - -QualType ASTContext::getCanonicalTemplateSpecializationType( - TemplateName Template, ArrayRef Args) const { - assert(!Template.getAsDependentTemplateName() && - "No dependent template names here!"); - // Look through qualified template names. if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) - Template = TemplateName(QTN->getUnderlyingTemplate()); - - // Build the canonical template specialization type. - TemplateName CanonTemplate = getCanonicalTemplateName(Template); - bool AnyNonCanonArgs = false; - auto CanonArgs = - ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs); + Template = QTN->getUnderlyingTemplate(); - // Determine whether this canonical template specialization type already - // exists. llvm::FoldingSetNodeID ID; - TemplateSpecializationType::Profile(ID, CanonTemplate, - CanonArgs, *this); + TemplateSpecializationType::Profile(ID, Template, SpecifiedArgs, + SugaredConvertedArgs, Underlying, *this); void *InsertPos = nullptr; - TemplateSpecializationType *Spec - = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); + if (auto *T = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(T, 0); - if (!Spec) { - // Allocate a new canonical template specialization type. - void *Mem = Allocate((sizeof(TemplateSpecializationType) + - sizeof(TemplateArgument) * CanonArgs.size()), - TypeAlignment); - Spec = new (Mem) TemplateSpecializationType(CanonTemplate, - CanonArgs, - QualType(), QualType()); - Types.push_back(Spec); - TemplateSpecializationTypes.InsertNode(Spec, InsertPos); + const auto *TD = Template.getAsTemplateDecl(); + bool IsTypeAlias = TD && TD->isTypeAlias(); + if (Underlying.isNull()) { + // We can get here with an alias template when the specialization + // contains a pack expansion that does not match up with a parameter + // pack. + assert((!IsTypeAlias || hasAnyPackExpansions(CanonicalConvertedArgs)) && + "Caller must compute aliased type"); + IsTypeAlias = false; + TemplateName CanonTemplate = getCanonicalTemplateName(Template); + + SmallVector CanonArgsVec; + if (CanonicalConvertedArgs.size() == 0) { + CanonArgsVec = ::getCanonicalTemplateArguments( + *this, SugaredConvertedArgs, AnyNonCanonArgs); + CanonicalConvertedArgs = CanonArgsVec; + } + + if (AnyNonCanonArgs || !SpecifiedArgs.empty() || + Template.getAsVoidPointer() != CanonTemplate.getAsVoidPointer()) { + Underlying = getTemplateSpecializationType( + CanonTemplate, ArrayRef(), None, + CanonicalConvertedArgs, QualType()); + assert(Underlying->isDependentType() && + "Non-dependent template-id type must have a canonical type"); + [[maybe_unused]] const auto *Found = + TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!Found); + } } - assert(Spec->isDependentType() && - "Non-dependent template-id type must have a canonical type"); + void *Mem = + Allocate(sizeof(TemplateSpecializationType) + + sizeof(TemplateArgument) * + (SpecifiedArgs.size() + SugaredConvertedArgs.size()) + + (IsTypeAlias ? sizeof(QualType) : 0), + TypeAlignment); + auto *Spec = new (Mem) TemplateSpecializationType( + Template, IsTypeAlias, SpecifiedArgs, SugaredConvertedArgs, Underlying); + + Types.push_back(Spec); + TemplateSpecializationTypes.InsertNode(Spec, InsertPos); return QualType(Spec, 0); } @@ -7387,8 +7398,7 @@ void ASTContext::setCFConstantStringType(QualType T) { const auto *TD = T->castAs(); CFConstantStringTypeDecl = cast(TD->getDecl()); - const auto *TagType = - CFConstantStringTypeDecl->getUnderlyingType()->castAs(); + const auto *TagType = TD->castAs(); CFConstantStringTagDecl = TagType->getDecl(); } @@ -12783,12 +12793,15 @@ case Type::TemplateSpecialization: { const auto *TX = cast(X), *TY = cast(Y); - auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(), - TY->template_arguments()); + auto SpecAs = getCommonTemplateArguments(Ctx, TX->template_arguments(), + TY->template_arguments()); + auto ConvAs = getCommonTemplateArguments(Ctx, TX->getConvertedArguments(), + TY->getConvertedArguments()); return Ctx.getTemplateSpecializationType( ::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(), TY->getTemplateName()), - As, X->getCanonicalTypeInternal()); + SpecAs, ConvAs, /*CanonicalConvertedArgs=*/{}, + X->getCanonicalTypeInternal()); } case Type::DependentName: { const auto *NX = cast(X), @@ -12998,11 +13011,14 @@ TY->getTemplateName()); if (!CTN.getAsVoidPointer()) return QualType(); - SmallVector Args; - if (getCommonTemplateArguments(Ctx, Args, TX->template_arguments(), + SmallVector SpecAs; + if (getCommonTemplateArguments(Ctx, SpecAs, TX->template_arguments(), TY->template_arguments())) return QualType(); - return Ctx.getTemplateSpecializationType(CTN, Args, + auto ConvAs = getCommonTemplateArguments(Ctx, TX->getConvertedArguments(), + TY->getConvertedArguments()); + return Ctx.getTemplateSpecializationType(CTN, SpecAs, ConvAs, + /*CanonicalConvertedArgs=*/{}, Ctx.getQualifiedType(Underlying)); } case Type::Typedef: { diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -129,7 +129,8 @@ if (DesugarArgument) { ShouldAKA = true; QT = Context.getTemplateSpecializationType( - TST->getTemplateName(), Args, QT); + TST->getTemplateName(), Args, TST->getConvertedArguments(), + /*CanonicalConvertedArguments=*/None, QT); } break; } @@ -1134,9 +1135,11 @@ return nullptr; Ty = Context.getTemplateSpecializationType( - TemplateName(CTSD->getSpecializedTemplate()), - CTSD->getTemplateArgs().asArray(), - Ty.getLocalUnqualifiedType().getCanonicalType()); + TemplateName(CTSD->getSpecializedTemplate()), + /*SpecifiedArgs=*/CTSD->getTemplateArgs().asArray(), + /*SugaredConvertedArgs=*/CTSD->getTemplateArgs().asArray(), + /*CanonicalConvertedArgs=*/None, + Ty.getLocalUnqualifiedType().getCanonicalType()); return Ty->getAs(); } 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 @@ -1555,6 +1555,11 @@ ImportTemplateArguments(T->template_arguments(), ToTemplateArgs)) return std::move(Err); + SmallVector ToConvertedArgs; + if (Error Err = + ImportTemplateArguments(T->getConvertedArguments(), ToConvertedArgs)) + return std::move(Err); + QualType ToCanonType; if (!T->isCanonicalUnqualified()) { QualType FromCanonType @@ -1564,9 +1569,9 @@ else return TyOrErr.takeError(); } - return Importer.getToContext().getTemplateSpecializationType(*ToTemplateOrErr, - ToTemplateArgs, - ToCanonType); + return Importer.getToContext().getTemplateSpecializationType( + *ToTemplateOrErr, ToTemplateArgs, ToConvertedArgs, + /*CanonicalConvertedArgs=*/None, ToCanonType); } ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -1108,6 +1108,9 @@ if (!IsStructurallyEquivalent(Context, Spec1->template_arguments(), Spec2->template_arguments())) return false; + if (!IsStructurallyEquivalent(Context, Spec1->getConvertedArguments(), + Spec2->getConvertedArguments())) + return false; break; } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -627,9 +627,11 @@ TemplateParameterList *Params = getTemplateParameters(); SmallVector TemplateArgs; Context.getInjectedTemplateArgs(Params, TemplateArgs); - CommonPtr->InjectedClassNameType - = Context.getTemplateSpecializationType(TemplateName(this), - TemplateArgs); + CommonPtr->InjectedClassNameType = Context.getTemplateSpecializationType( + TemplateName(this), + /*SpecifiedArgs=*/TemplateArgs, + /*SugaredConvertedArgs=*/TemplateArgs, + /*CanonicalConvertedArgs=*/None); return CommonPtr->InjectedClassNameType; } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -1240,7 +1240,9 @@ // FIXME: GCC does not appear to mangle the template arguments when // the template in question is a dependent template name. Should we // emulate that badness? - mangleTemplateArgs(TST->getTemplateName(), TST->template_arguments()); + auto Args = TST->isCanonicalUnqualified() ? TST->getConvertedArguments() + : TST->template_arguments(); + mangleTemplateArgs(TST->getTemplateName(), Args); addSubstitution(QualType(TST, 0)); } } else if (const auto *DTST = @@ -2406,13 +2408,14 @@ break; } } - + auto Args = TST->isCanonicalUnqualified() ? TST->getConvertedArguments() + : TST->template_arguments(); // Note: we don't pass in the template name here. We are mangling the // original source-level template arguments, so we shouldn't consider // conversions to the corresponding template parameter. // FIXME: Other compilers mangle partially-resolved template arguments in // unresolved-qualifier-levels. - mangleTemplateArgs(TemplateName(), TST->template_arguments()); + mangleTemplateArgs(TemplateName(), Args); break; } @@ -3869,8 +3872,10 @@ } void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { + auto Args = T->isCanonicalUnqualified() ? T->getConvertedArguments() + : T->template_arguments(); if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) { - mangleTemplateName(TD, T->template_arguments()); + mangleTemplateName(TD, Args); } else { if (mangleSubstitution(QualType(T, 0))) return; @@ -3880,7 +3885,7 @@ // FIXME: GCC does not appear to mangle the template arguments when // the template in question is a dependent template name. Should we // emulate that badness? - mangleTemplateArgs(T->getTemplateName(), T->template_arguments()); + mangleTemplateArgs(T->getTemplateName(), Args); addSubstitution(QualType(T, 0)); } } diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -141,8 +141,8 @@ // allocate new type in the AST. if (MightHaveChanged) { QualType QT = Ctx.getTemplateSpecializationType( - TST->getTemplateName(), FQArgs, - TST->getCanonicalTypeInternal()); + TST->getTemplateName(), FQArgs, TST->getConvertedArguments(), + /*CanonicalConvertedArgs=*/None, TST->getCanonicalTypeInternal()); // getTemplateSpecializationType returns a fully qualified // version of the specialization itself, so no need to qualify // it. @@ -173,7 +173,8 @@ if (MightHaveChanged) { TemplateName TN(TSTDecl->getSpecializedTemplate()); QualType QT = Ctx.getTemplateSpecializationType( - TN, FQArgs, + TN, FQArgs, FQArgs, + /*CanonicalConvertedArgs=*/None, TSTRecord->getCanonicalTypeInternal()); // getTemplateSpecializationType returns a fully qualified // version of the specialization itself, so no need to qualify 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 @@ -1774,6 +1774,17 @@ return nullptr; } +const TemplateSpecializationType * +Type::getAsNonAliasTemplateSpecializationType() const { + for (auto T = this; /**/; /**/) { + const TemplateSpecializationType *TST = + T->getAs(); + if (!TST || !TST->isTypeAlias()) + return TST; + T = TST->desugar().getTypePtr(); + } +} + bool Type::hasAttr(attr::Kind AK) const { const Type *Cur = this; while (const auto *AT = Cur->getAs()) { @@ -3738,17 +3749,20 @@ } TemplateSpecializationType::TemplateSpecializationType( - TemplateName T, ArrayRef Args, QualType Canon, - QualType AliasedType) - : Type(TemplateSpecialization, Canon.isNull() ? QualType(this, 0) : Canon, - (Canon.isNull() + TemplateName T, bool IsAlias, ArrayRef SpecifiedArgs, + ArrayRef ConvertedArgs, QualType Underlying) + : Type(TemplateSpecialization, + Underlying.isNull() ? QualType(this, 0) + : Underlying.getCanonicalType(), + (Underlying.isNull() ? TypeDependence::DependentInstantiation - : toSemanticDependence(Canon->getDependence())) | + : toSemanticDependence(Underlying->getDependence())) | (toTypeDependence(T.getDependence()) & TypeDependence::UnexpandedPack)), Template(T) { - TemplateSpecializationTypeBits.NumArgs = Args.size(); - TemplateSpecializationTypeBits.TypeAlias = !AliasedType.isNull(); + TemplateSpecializationTypeBits.NumSpecifiedArgs = SpecifiedArgs.size(); + TemplateSpecializationTypeBits.NumConvertedArgs = ConvertedArgs.size(); + TemplateSpecializationTypeBits.TypeAlias = IsAlias; assert(!T.getAsDependentTemplateName() && "Use DependentTemplateSpecializationType for dependent template-name"); @@ -3758,51 +3772,69 @@ T.getKind() == TemplateName::UsingTemplate) && "Unexpected template name for TemplateSpecializationType"); - auto *TemplateArgs = reinterpret_cast(this + 1); - for (const TemplateArgument &Arg : Args) { - // Update instantiation-dependent, variably-modified, and error bits. - // If the canonical type exists and is non-dependent, the template - // specialization type can be non-dependent even if one of the type - // arguments is. Given: - // template using U = int; - // U is always non-dependent, irrespective of the type T. - // However, U contains an unexpanded parameter pack, even though - // its expansion (and thus its desugared type) doesn't. - addDependence(toTypeDependence(Arg.getDependence()) & - ~TypeDependence::Dependent); - if (Arg.getKind() == TemplateArgument::Type) - addDependence(Arg.getAsType()->getDependence() & - TypeDependence::VariablyModified); - new (TemplateArgs++) TemplateArgument(Arg); - } + auto initArgs = [this](ArrayRef Out, + ArrayRef In) { + auto *Args = const_cast(Out.data()); + for (const TemplateArgument &Arg : In) { + // Update instantiation-dependent, variably-modified, and error bits. + // If the canonical type exists and is non-dependent, the template + // specialization type can be non-dependent even if one of the type + // arguments is. Given: + // template using U = int; + // U is always non-dependent, irrespective of the type T. + // However, U contains an unexpanded parameter pack, even though + // its expansion (and thus its desugared type) doesn't. + addDependence(toTypeDependence(Arg.getDependence()) & + ~TypeDependence::Dependent); + if (Arg.getKind() == TemplateArgument::Type) + addDependence(Arg.getAsType()->getDependence() & + TypeDependence::VariablyModified); + new (Args++) TemplateArgument(Arg); + } + }; + + initArgs(template_arguments(), SpecifiedArgs); + initArgs(getConvertedArguments(), ConvertedArgs); // Store the aliased type if this is a type alias template specialization. - if (isTypeAlias()) { - auto *Begin = reinterpret_cast(this + 1); - *reinterpret_cast(Begin + Args.size()) = AliasedType; - } + if (IsAlias) + *reinterpret_cast(const_cast( + getConvertedArguments().end())) = Underlying; } QualType TemplateSpecializationType::getAliasedType() const { assert(isTypeAlias() && "not a type alias template specialization"); - return *reinterpret_cast(template_arguments().end()); + return *reinterpret_cast(getConvertedArguments().end()); +} + +ArrayRef +TemplateSpecializationType::getConvertedArguments() const { + return {template_arguments().end(), + TemplateSpecializationTypeBits.NumConvertedArgs}; } void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { - Profile(ID, Template, template_arguments(), Ctx); - if (isTypeAlias()) - getAliasedType().Profile(ID); + Profile(ID, Template, template_arguments(), getConvertedArguments(), + isSugared() ? desugar() : QualType(), Ctx); } -void -TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, - TemplateName T, - ArrayRef Args, - const ASTContext &Context) { +void TemplateSpecializationType::Profile( + llvm::FoldingSetNodeID &ID, TemplateName T, + ArrayRef SpecifiedArgs, + ArrayRef ConvertedArgs, QualType Underlying, + const ASTContext &Context) { T.Profile(ID); - for (const TemplateArgument &Arg : Args) + + ID.AddInteger(SpecifiedArgs.size()); + for (const TemplateArgument &Arg : SpecifiedArgs) + Arg.Profile(ID, Context); + + ID.AddInteger(ConvertedArgs.size()); + for (const TemplateArgument &Arg : ConvertedArgs) Arg.Profile(ID, Context); + + Underlying.Profile(ID); } QualType diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1504,7 +1504,10 @@ DefaultTemplateArgsPolicyRAII TemplateArgs(Policy); const TemplateParameterList *TPL = TD ? TD->getTemplateParameters() : nullptr; - printTemplateArgumentList(OS, T->template_arguments(), Policy, TPL); + ArrayRef Args = T->isCanonicalUnqualified() + ? T->getConvertedArguments() + : T->template_arguments(); + printTemplateArgumentList(OS, Args, Policy, TPL); spaceBeforePlaceHolder(OS); } @@ -1988,6 +1991,7 @@ ArrayRef TemplateArgs; if (auto *TTST = T->getAs()) { Template = TTST->getTemplateName(); + assert(!TTST->isCanonicalUnqualified()); TemplateArgs = TTST->template_arguments(); } else if (auto *CTSD = dyn_cast_or_null( T->getAsCXXRecordDecl())) { @@ -2000,11 +2004,12 @@ if (!isSubstitutedTemplateArgument(Ctx, Template, PTST->getTemplateName(), Args, Depth)) return false; - if (TemplateArgs.size() != PTST->template_arguments().size()) + ArrayRef PArgs = PTST->getConvertedArguments(); + if (TemplateArgs.size() != PArgs.size()) return false; for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) - if (!isSubstitutedTemplateArgument( - Ctx, TemplateArgs[I], PTST->template_arguments()[I], Args, Depth)) + if (!isSubstitutedTemplateArgument(Ctx, TemplateArgs[I], PArgs[I], Args, + Depth)) return false; return true; } diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp --- a/clang/lib/Index/USRGeneration.cpp +++ b/clang/lib/Index/USRGeneration.cpp @@ -856,8 +856,8 @@ = T->getAs()) { Out << '>'; VisitTemplateName(Spec->getTemplateName()); - Out << Spec->template_arguments().size(); - for (const auto &Arg : Spec->template_arguments()) + Out << Spec->getConvertedArguments().size(); + for (const TemplateArgument &Arg : Spec->getConvertedArguments()) VisitTemplateArgument(Arg); return; } 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 @@ -3578,11 +3578,11 @@ } } -static QualType -checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, - ArrayRef Converted, - SourceLocation TemplateLoc, - TemplateArgumentListInfo &TemplateArgs) { +static QualType checkBuiltinTemplateIdType( + Sema &SemaRef, TemplateName Name, BuiltinTemplateDecl *BTD, + ArrayRef SugaredConverted, + ArrayRef CanonicalConverted, SourceLocation TemplateLoc, + TemplateArgumentListInfo &TemplateArgs) { ASTContext &Context = SemaRef.getASTContext(); switch (BTD->getBuiltinTemplateKind()) { @@ -3590,7 +3590,7 @@ // Specializations of __make_integer_seq are treated like // S. - QualType OrigType = Converted[1].getAsType(); + QualType OrigType = SugaredConverted[1].getAsType(); // C++14 [inteseq.intseq]p1: // T shall be an integer type. if (!OrigType->isDependentType() && !OrigType->isIntegralType(Context)) { @@ -3599,10 +3599,11 @@ return QualType(); } - TemplateArgument NumArgsArg = Converted[2]; + TemplateArgument NumArgsArg = SugaredConverted[2]; if (NumArgsArg.isDependent()) - return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD), - Converted); + return SemaRef.Context.getTemplateSpecializationType( + TemplateName(BTD), TemplateArgs.arguments(), SugaredConverted, + CanonicalConverted); TemplateArgumentListInfo SyntheticTemplateArgs; // The type argument, wrapped in substitution sugar, gets reused as the @@ -3630,21 +3631,26 @@ // The first template argument will be reused as the template decl that // our synthetic template arguments will be applied to. - return SemaRef.CheckTemplateIdType(Converted[0].getAsTemplate(), - TemplateLoc, SyntheticTemplateArgs); + QualType Result = + SemaRef.CheckTemplateIdType(SugaredConverted[0].getAsTemplate(), + TemplateLoc, SyntheticTemplateArgs); + return SemaRef.Context.getTemplateSpecializationType( + Name, TemplateArgs.arguments(), SugaredConverted, CanonicalConverted, + Result); } case BTK__type_pack_element: // Specializations of // __type_pack_element // are treated like T_Index. - assert(Converted.size() == 2 && - "__type_pack_element should be given an index and a parameter pack"); + assert(SugaredConverted.size() == 2 && + "__type_pack_element should be given an index and a parameter pack"); - TemplateArgument IndexArg = Converted[0], Ts = Converted[1]; + TemplateArgument IndexArg = SugaredConverted[0], Ts = SugaredConverted[1]; if (IndexArg.isDependent() || Ts.isDependent()) - return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD), - Converted); + return SemaRef.Context.getTemplateSpecializationType( + TemplateName(BTD), TemplateArgs.arguments(), SugaredConverted, + CanonicalConverted); llvm::APSInt Index = IndexArg.getAsIntegral(); assert(Index >= 0 && "the index used with __type_pack_element should be of " @@ -3658,7 +3664,9 @@ // We simply return the type at index `Index`. int64_t N = Index.getExtValue(); - return Ts.getPackAsArray()[N].getAsType(); + return SemaRef.Context.getTemplateSpecializationType( + Name, TemplateArgs.arguments(), SugaredConverted, CanonicalConverted, + Ts.getPackAsArray()[N].getAsType()); } llvm_unreachable("unexpected BuiltinTemplateDecl!"); } @@ -3819,19 +3827,18 @@ resolveAssumedTemplateNameAsType(/*Scope*/nullptr, Name, TemplateLoc)) return QualType(); - TemplateDecl *Template = Name.getAsTemplateDecl(); - if (!Template || isa(Template) || - isa(Template) || isa(Template)) { - // We might have a substituted template template parameter pack. If so, - // build a template specialization type for it. - if (Name.getAsSubstTemplateTemplateParmPack()) - return Context.getTemplateSpecializationType(Name, - TemplateArgs.arguments()); - - Diag(TemplateLoc, diag::err_template_id_not_a_type) - << Name; - NoteAllFoundTemplates(Name); - return QualType(); + TemplateDecl *Template; + if (const SubstTemplateTemplateParmPackStorage *S = + Name.getAsSubstTemplateTemplateParmPack()) { + Template = S->getParameterPack(); + } else { + Template = Name.getAsTemplateDecl(); + if (!Template || isa(Template) || + isa(Template) || isa(Template)) { + Diag(TemplateLoc, diag::err_template_id_not_a_type) << Name; + NoteAllFoundTemplates(Name); + return QualType(); + } } // Check that the template argument list is well-formed for this @@ -3844,8 +3851,11 @@ QualType CanonType; - if (TypeAliasTemplateDecl *AliasTemplate = - dyn_cast(Template)) { + if (isa(Template)) { + // We might have a substituted template template parameter pack. If so, + // build a template specialization type for it. + } else if (TypeAliasTemplateDecl *AliasTemplate = + dyn_cast(Template)) { // Find the canonical type for this type alias template specialization. TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl(); @@ -3903,8 +3913,9 @@ return QualType(); } } else if (auto *BTD = dyn_cast(Template)) { - CanonType = checkBuiltinTemplateIdType(*this, BTD, SugaredConverted, - TemplateLoc, TemplateArgs); + return checkBuiltinTemplateIdType(*this, Name, BTD, SugaredConverted, + CanonicalConverted, TemplateLoc, + TemplateArgs); } else if (Name.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( TemplateArgs, CanonicalConverted)) { @@ -3915,8 +3926,9 @@ // A have identical types when A is declared as: // // template struct A; - CanonType = Context.getCanonicalTemplateSpecializationType( - Name, CanonicalConverted); + CanonType = Context.getTemplateSpecializationType( + Context.getCanonicalTemplateName(Name), ArrayRef(), + None, CanonicalConverted); // This might work out to be a current instantiation, in which // case the canonical type needs to be the InjectedClassNameType. @@ -4003,7 +4015,8 @@ // specialization, which refers back to the class template // specialization we created or found. return Context.getTemplateSpecializationType(Name, TemplateArgs.arguments(), - CanonType); + SugaredConverted, + CanonicalConverted, CanonType); } void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName, @@ -8694,9 +8707,9 @@ if (isPartialSpecialization) { // Build the canonical type that describes the converted template // arguments of the class template partial specialization. - TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); - CanonType = Context.getTemplateSpecializationType(CanonTemplate, - CanonicalConverted); + CanonType = Context.getTemplateSpecializationType( + Context.getCanonicalTemplateName(Name), ArrayRef(), + None, CanonicalConverted); if (Context.hasSameType(CanonType, ClassTemplate->getInjectedClassNameSpecialization()) && @@ -8763,9 +8776,9 @@ ClassTemplate->AddSpecialization(Specialization, InsertPos); if (CurContext->isDependentContext()) { - TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); - CanonType = Context.getTemplateSpecializationType(CanonTemplate, - CanonicalConverted); + CanonType = Context.getTemplateSpecializationType( + Context.getCanonicalTemplateName(Name), ArrayRef(), + None, CanonicalConverted); } else { CanonType = Context.getTypeDeclType(Specialization); } @@ -8842,9 +8855,9 @@ // actually wrote the specialization, rather than formatting the // name based on the "canonical" representation used to store the // template arguments in the specialization. - TypeSourceInfo *WrittenTy - = Context.getTemplateSpecializationTypeInfo(Name, TemplateNameLoc, - TemplateArgs, CanonType); + TypeSourceInfo *WrittenTy = Context.getTemplateSpecializationTypeInfo( + Name, TemplateNameLoc, TemplateArgs, SugaredConverted, CanonicalConverted, + CanonType); if (TUK != TUK_Friend) { Specialization->setTypeAsWritten(WrittenTy); Specialization->setTemplateKeywordLoc(TemplateKWLoc); @@ -10016,10 +10029,9 @@ // the explicit instantiation, rather than formatting the name based // on the "canonical" representation used to store the template // arguments in the specialization. - TypeSourceInfo *WrittenTy - = Context.getTemplateSpecializationTypeInfo(Name, TemplateNameLoc, - TemplateArgs, - Context.getTypeDeclType(Specialization)); + TypeSourceInfo *WrittenTy = Context.getTemplateSpecializationTypeInfo( + Name, TemplateNameLoc, TemplateArgs, SugaredConverted, CanonicalConverted, + Context.getTypeDeclType(Specialization)); Specialization->setTypeAsWritten(WrittenTy); // Set source locations for keywords. diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -560,16 +560,16 @@ QualType UP = P; if (const auto *IP = P->getAs()) UP = IP->getInjectedSpecializationType(); - // FIXME: Try to preserve type sugar here, which is hard - // because of the unresolved template arguments. - const auto *TP = UP.getCanonicalType()->castAs(); + assert(isa(UP.getCanonicalType())); + const TemplateSpecializationType *TP = + UP->castAsNonAliasTemplateSpecializationType(); TemplateName TNP = TP->getTemplateName(); // If the parameter is an alias template, there is nothing to deduce. if (const auto *TD = TNP.getAsTemplateDecl(); TD && TD->isTypeAlias()) return Sema::TDK_Success; - ArrayRef PResolved = TP->template_arguments(); + ArrayRef PResolved = TP->getConvertedArguments(); QualType UA = A; // Treat an injected-class-name as its underlying template-id. @@ -577,9 +577,7 @@ UA = Injected->getInjectedSpecializationType(); // Check whether the template argument is a dependent template-id. - // FIXME: Should not lose sugar here. - if (const auto *SA = - dyn_cast(UA.getCanonicalType())) { + if (const auto *SA = UA->getAsNonAliasTemplateSpecializationType()) { TemplateName TNA = SA->getTemplateName(); // If the argument is an alias template, there is nothing to deduce. @@ -594,7 +592,7 @@ // argument. Ignore any missing/extra arguments, since they could be // filled in by default arguments. return DeduceTemplateArguments(S, TemplateParams, PResolved, - SA->template_arguments(), Info, Deduced, + SA->getConvertedArguments(), Info, Deduced, /*NumberOfArgumentsMustMatch=*/false); } @@ -5255,11 +5253,11 @@ auto *TST2 = dyn_cast(T2); if (!TST1 || !TST2) continue; - const TemplateArgument &TA1 = TST1->template_arguments().back(); + const TemplateArgument &TA1 = TST1->getConvertedArguments().back(); if (TA1.getKind() == TemplateArgument::Pack) { - assert(TST1->template_arguments().size() == - TST2->template_arguments().size()); - const TemplateArgument &TA2 = TST2->template_arguments().back(); + assert(TST1->getConvertedArguments().size() == + TST2->getConvertedArguments().size()); + const TemplateArgument &TA2 = TST2->getConvertedArguments().back(); assert(TA2.getKind() == TemplateArgument::Pack); unsigned PackSize1 = TA1.pack_size(); unsigned PackSize2 = TA2.pack_size(); @@ -5501,7 +5499,7 @@ AtLeastAsSpecialized = !FinishTemplateArgumentDeduction( S, P2, /*IsPartialOrdering=*/true, TemplateArgumentList(TemplateArgumentList::OnStack, - TST1->template_arguments()), + TST1->getConvertedArguments()), Deduced, Info); }); return AtLeastAsSpecialized; @@ -5623,11 +5621,11 @@ if (!ClangABICompat15) { auto *TST1 = cast(T1); auto *TST2 = cast(T2); - const TemplateArgument &TA1 = TST1->template_arguments().back(); + const TemplateArgument &TA1 = TST1->getConvertedArguments().back(); if (TA1.getKind() == TemplateArgument::Pack) { - assert(TST1->template_arguments().size() == - TST2->template_arguments().size()); - const TemplateArgument &TA2 = TST2->template_arguments().back(); + assert(TST1->getConvertedArguments().size() == + TST2->getConvertedArguments().size()); + const TemplateArgument &TA2 = TST2->getConvertedArguments().back(); assert(TA2.getKind() == TemplateArgument::Pack); unsigned PackSize1 = TA1.pack_size(); unsigned PackSize2 = TA2.pack_size(); @@ -5732,9 +5730,11 @@ TemplateName Name(PS1->getSpecializedTemplate()); TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); QualType PT1 = Context.getTemplateSpecializationType( - CanonTemplate, PS1->getTemplateArgs().asArray()); + CanonTemplate, ArrayRef(), None, + PS1->getTemplateArgs().asArray()); QualType PT2 = Context.getTemplateSpecializationType( - CanonTemplate, PS2->getTemplateArgs().asArray()); + CanonTemplate, ArrayRef(), None, + PS2->getTemplateArgs().asArray()); TemplateDeductionInfo Info(Loc); return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info); @@ -5745,10 +5745,14 @@ VarTemplateDecl *Primary = Spec->getSpecializedTemplate(); TemplateName CanonTemplate = Context.getCanonicalTemplateName(TemplateName(Primary)); - QualType PrimaryT = Context.getTemplateSpecializationType( - CanonTemplate, Primary->getInjectedTemplateArgs()); + QualType PrimaryT = Context + .getTemplateSpecializationType( + CanonTemplate, ArrayRef(), + Primary->getInjectedTemplateArgs(), None) + .getCanonicalType(); QualType PartialT = Context.getTemplateSpecializationType( - CanonTemplate, Spec->getTemplateArgs().asArray()); + CanonTemplate, ArrayRef(), None, + Spec->getTemplateArgs().asArray()); VarTemplatePartialSpecializationDecl *MaybeSpec = getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info); @@ -5778,6 +5782,7 @@ // template parameters from the respective function template SmallVector AArgs; Context.getInjectedTemplateArgs(A, AArgs); + Context.canonicalizeTemplateArguments(AArgs); // Check P's arguments against A's parameter list. This will fill in default // template arguments as needed. AArgs are already correct by construction. @@ -5788,6 +5793,7 @@ SFINAETrap Trap(*this); Context.getInjectedTemplateArgs(P, PArgs); + Context.canonicalizeTemplateArguments(PArgs); TemplateArgumentListInfo PArgList(P->getLAngleLoc(), P->getRAngleLoc()); for (unsigned I = 0, N = P->size(); I != N; ++I) { @@ -5813,8 +5819,10 @@ return false; } - QualType AType = Context.getCanonicalTemplateSpecializationType(X, AArgs); - QualType PType = Context.getCanonicalTemplateSpecializationType(X, PArgs); + QualType AType = Context.getTemplateSpecializationType( + X, ArrayRef(), None, AArgs); + QualType PType = Context.getTemplateSpecializationType( + X, ArrayRef(), None, PArgs); // ... the function template corresponding to P is at least as specialized // as the function template corresponding to A according to the partial @@ -6107,11 +6115,10 @@ // If the template argument list of P contains a pack expansion that is // not the last template argument, the entire template argument list is a // non-deduced context. - if (OnlyDeduced && - hasPackExpansionBeforeEnd(Spec->template_arguments())) + if (OnlyDeduced && hasPackExpansionBeforeEnd(Spec->getConvertedArguments())) break; - for (const auto &Arg : Spec->template_arguments()) + for (const TemplateArgument &Arg : Spec->getConvertedArguments()) MarkUsedTemplateParameters(Ctx, Arg, OnlyDeduced, Depth, Used); break; } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -219,7 +219,7 @@ ->getInjectedSpecializationType(); const auto *InjectedType = cast(Injected); Result.addOuterTemplateArguments(const_cast(Rec), - InjectedType->template_arguments(), + InjectedType->getConvertedArguments(), /*Final=*/false); } } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3815,12 +3815,6 @@ if (SubstQualifier(D, InstD)) return nullptr; - // Build the canonical type that describes the converted template - // arguments of the class template explicit specialization. - QualType CanonType = SemaRef.Context.getTemplateSpecializationType( - TemplateName(InstClassTemplate), CanonicalConverted, - SemaRef.Context.getRecordType(InstD)); - // Build the fully-sugared type for this class template // specialization as the user wrote in the specialization // itself. This means that we'll pretty-print the type retrieved @@ -3830,7 +3824,8 @@ // template arguments in the specialization. TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo( TemplateName(InstClassTemplate), D->getLocation(), InstTemplateArgs, - CanonType); + SugaredConverted, CanonicalConverted, + SemaRef.Context.getRecordType(InstD)); InstD->setAccess(D->getAccess()); InstD->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation); @@ -4165,11 +4160,6 @@ ClassTemplate->findPartialSpecialization(CanonicalConverted, InstParams, InsertPos); - // Build the canonical type that describes the converted template - // arguments of the class template partial specialization. - QualType CanonType = SemaRef.Context.getTemplateSpecializationType( - TemplateName(ClassTemplate), CanonicalConverted); - // Build the fully-sugared type for this class template // specialization as the user wrote in the specialization // itself. This means that we'll pretty-print the type retrieved @@ -4177,12 +4167,9 @@ // actually wrote the specialization, rather than formatting the // name based on the "canonical" representation used to store the // template arguments in the specialization. - TypeSourceInfo *WrittenTy - = SemaRef.Context.getTemplateSpecializationTypeInfo( - TemplateName(ClassTemplate), - PartialSpec->getLocation(), - InstTemplateArgs, - CanonType); + TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo( + TemplateName(ClassTemplate), PartialSpec->getLocation(), InstTemplateArgs, + SugaredConverted, CanonicalConverted); if (PrevDecl) { // We've already seen a partial specialization with the same template @@ -4213,8 +4200,8 @@ ClassTemplatePartialSpecializationDecl::Create( SemaRef.Context, PartialSpec->getTagKind(), Owner, PartialSpec->getBeginLoc(), PartialSpec->getLocation(), InstParams, - ClassTemplate, CanonicalConverted, InstTemplateArgs, CanonType, - nullptr); + ClassTemplate, CanonicalConverted, InstTemplateArgs, + WrittenTy->getType(), nullptr); // Substitute the nested name specifier, if any. if (SubstQualifier(PartialSpec, InstPartialSpec)) return nullptr; @@ -4290,11 +4277,6 @@ VarTemplate->findPartialSpecialization(CanonicalConverted, InstParams, InsertPos); - // Build the canonical type that describes the converted template - // arguments of the variable template partial specialization. - QualType CanonType = SemaRef.Context.getTemplateSpecializationType( - TemplateName(VarTemplate), CanonicalConverted); - // Build the fully-sugared type for this variable template // specialization as the user wrote in the specialization // itself. This means that we'll pretty-print the type retrieved @@ -4304,7 +4286,7 @@ // template arguments in the specialization. TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo( TemplateName(VarTemplate), PartialSpec->getLocation(), InstTemplateArgs, - CanonType); + SugaredConverted, CanonicalConverted); if (PrevDecl) { // We've already seen a partial specialization with the same template 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 @@ -6746,12 +6746,24 @@ TemplateArgumentListInfo NewTemplateArgs; NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); - typedef TemplateArgumentLocContainerIterator - ArgIterator; - if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0), - ArgIterator(TL, TL.getNumArgs()), - NewTemplateArgs)) - return QualType(); + + const auto *T = cast(TL.getType()); + if (T->isCanonicalUnqualified()) { + ArrayRef ConvertedArgs = T->getConvertedArguments(); + using ArgIterator = + TemplateArgumentLocInventIterator; + if (getDerived().TransformTemplateArguments( + ArgIterator(*this, ConvertedArgs.begin()), + ArgIterator(*this, ConvertedArgs.end()), NewTemplateArgs)) + return QualType(); + } else { + using ArgIterator = + TemplateArgumentLocContainerIterator; + if (getDerived().TransformTemplateArguments( + ArgIterator(TL, 0), ArgIterator(TL, TL.getNumArgs()), + NewTemplateArgs)) + return QualType(); + } // FIXME: maybe don't rebuild if all the template arguments are the same. diff --git a/clang/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp b/clang/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp --- a/clang/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp @@ -38,7 +38,7 @@ template struct Outer { template struct Inner; - template struct Inner {}; // expected-note{{previous declaration of class template partial specialization 'Inner' is here}} + template struct Inner {}; // expected-note{{previous declaration of class template partial specialization 'Inner' is here}} template struct Inner {}; // expected-error{{cannot be redeclared}} }; @@ -80,7 +80,7 @@ template struct Foo { template struct Bar; template struct Bar<0, T, Y> {}; - // expected-note-re@-1 {{previous declaration {{.*}} 'Bar<0, int, type-parameter-0-0>' is here}} + // expected-note-re@-1 {{previous declaration {{.*}} 'Bar<0, int, Y>' is here}} template struct Bar<0, U, Y> {}; // expected-error@-1 {{partial specialization 'Bar<0, int, Y>' cannot be redeclared}} }; diff --git a/clang/test/SemaTemplate/deduction.cpp b/clang/test/SemaTemplate/deduction.cpp --- a/clang/test/SemaTemplate/deduction.cpp +++ b/clang/test/SemaTemplate/deduction.cpp @@ -504,7 +504,7 @@ namespace b29946541 { template class A {}; template class C> - void f(C); // expected-note {{failed template argument deduction}} + void f(C); // expected-note {{couldn't infer template argument 'U'}} void g(A a) { f(a); } // expected-error {{no match}} } diff --git a/clang/test/SemaTemplate/make_integer_seq.cpp b/clang/test/SemaTemplate/make_integer_seq.cpp --- a/clang/test/SemaTemplate/make_integer_seq.cpp +++ b/clang/test/SemaTemplate/make_integer_seq.cpp @@ -40,75 +40,53 @@ // CHECK-NEXT: |-TemplateArgument type 'int' // CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int' // CHECK-NEXT: |-TemplateArgument expr -// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} 'int' +// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} 'int' // CHECK-NEXT: | |-value: Int 1 -// CHECK-NEXT: | `-SubstNonTypeTemplateParmExpr 0x{{[0-9A-Fa-f]+}} 'int' -// CHECK-NEXT: | |-NonTypeTemplateParmDecl 0x{{[0-9A-Fa-f]+}} col:24 referenced 'B1' depth 0 index 1 B2 -// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} 'int' 1 +// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} 'int' 1 // CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} 'A' sugar A // CHECK-NEXT: |-TemplateArgument type 'int' // CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int' // CHECK-NEXT: |-TemplateArgument expr -// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} 'int' +// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} 'int' // CHECK-NEXT: | |-value: Int 0 -// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} 'int' 0 +// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} 'int' 0 // CHECK-NEXT: `-RecordType 0x{{[0-9A-Fa-f]+}} 'A' // CHECK-NEXT: `-ClassTemplateSpecialization 0x{{[0-9A-Fa-f]+}} 'A' template