diff --git a/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp @@ -96,8 +96,9 @@ unsigned ArgNum = 0; const auto *FunctorParentType = FunctorParentLoc.getType()->castAs(); - for (; ArgNum < FunctorParentType->getNumArgs(); ++ArgNum) { - const TemplateArgument &Arg = FunctorParentType->getArg(ArgNum); + for (; ArgNum < FunctorParentType->getSpecifiedArguments().size(); ++ArgNum) { + const TemplateArgument &Arg = + FunctorParentType->getSpecifiedArguments()[ArgNum]; if (Arg.getKind() != TemplateArgument::Type) continue; QualType ParentArgType = Arg.getAsType(); @@ -107,7 +108,7 @@ break; } // Functor is a default template argument. - if (ArgNum == FunctorParentType->getNumArgs()) + if (ArgNum == FunctorParentType->getSpecifiedArguments().size()) return; TemplateArgumentLoc FunctorLoc = FunctorParentLoc.getArgLoc(ArgNum); auto FunctorTypeLoc = getInnerTypeLocAs( diff --git a/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp b/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp --- a/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp +++ b/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp @@ -183,8 +183,10 @@ if (Template->getAsCXXRecordDecl()->getName() != "complex") return true; - const auto *Builtin = - Template->getArg(0).getAsType().getTypePtr()->getAs(); + const auto *Builtin = Template->getSpecifiedArguments()[0] + .getAsType() + .getTypePtr() + ->getAs(); if (Builtin && !isMPITypeMatching(ComplexCXXMatches, Builtin->getKind(), MPIDatatype)) { diff --git a/clang-tools-extra/clangd/HeuristicResolver.cpp b/clang-tools-extra/clangd/HeuristicResolver.cpp --- a/clang-tools-extra/clangd/HeuristicResolver.cpp +++ b/clang-tools-extra/clangd/HeuristicResolver.cpp @@ -80,9 +80,9 @@ auto *TST = T->getAs(); if (!TST) return nullptr; - if (TST->getNumArgs() == 0) + if (TST->getSpecifiedArguments().size() == 0) return nullptr; - const TemplateArgument &FirstArg = TST->getArg(0); + const TemplateArgument &FirstArg = TST->getSpecifiedArguments()[0]; if (FirstArg.getKind() != TemplateArgument::Type) return nullptr; return FirstArg.getAsType().getTypePtrOrNull(); 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 @@ -1628,22 +1628,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; @@ -1658,10 +1660,9 @@ const IdentifierInfo *Name, QualType Canon = QualType()) const; - QualType getDependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, - const IdentifierInfo *Name, - const TemplateArgumentListInfo &Args) const; + QualType getDependentTemplateSpecializationType( + ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, + const IdentifierInfo *Name, ArrayRef Args) const; QualType getDependentTemplateSpecializationType( ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, ArrayRef Args) const; @@ -2706,6 +2707,13 @@ TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg) const; + /// Retrieve the "canonical" template argument list. + /// + /// Returns true if any arguments were non-canonical. + bool getCanonicalTemplateArguments( + ArrayRef OrigArgs, + SmallVectorImpl &CanonArgs) 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/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -395,7 +395,7 @@ Visit(T->getArgumentPack()); } void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { - for (const auto &Arg : *T) + for (const auto &Arg : T->getSpecifiedArguments()) Visit(Arg); } void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { 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 @@ -276,8 +276,7 @@ /// /// \returns false if the visitation was terminated early, true otherwise. // FIXME: take a TemplateArgumentLoc* (or TemplateArgumentListInfo) instead. - bool TraverseTemplateArguments(const TemplateArgument *Args, - unsigned NumArgs); + bool TraverseTemplateArguments(ArrayRef Args); /// Recursively visit a base specifier. This can be overridden by a /// subclass. @@ -873,8 +872,7 @@ return getDerived().TraverseStmt(Arg.getAsExpr()); case TemplateArgument::Pack: - return getDerived().TraverseTemplateArguments(Arg.pack_begin(), - Arg.pack_size()); + return getDerived().TraverseTemplateArguments(Arg.pack_elements()); } return true; @@ -914,8 +912,7 @@ return getDerived().TraverseStmt(ArgLoc.getSourceExpression()); case TemplateArgument::Pack: - return getDerived().TraverseTemplateArguments(Arg.pack_begin(), - Arg.pack_size()); + return getDerived().TraverseTemplateArguments(Arg.pack_elements()); } return true; @@ -923,10 +920,9 @@ template bool RecursiveASTVisitor::TraverseTemplateArguments( - const TemplateArgument *Args, unsigned NumArgs) { - for (unsigned I = 0; I != NumArgs; ++I) { - TRY_TO(TraverseTemplateArgument(Args[I])); - } + ArrayRef Args) { + for (const TemplateArgument &Arg : Args) + TRY_TO(TraverseTemplateArgument(Arg)); return true; } @@ -1083,7 +1079,7 @@ DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); if (T->isConstrained()) { - TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs())); + TRY_TO(TraverseTemplateArguments(T->getTypeConstraintArguments())); } }) DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, { @@ -1103,7 +1099,10 @@ DEF_TRAVERSE_TYPE(TemplateSpecializationType, { TRY_TO(TraverseTemplateName(T->getTemplateName())); - TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs())); + if (T->isCanonicalUnqualified()) + TRY_TO(TraverseTemplateArguments(T->getConvertedArguments())); + else + TRY_TO(TraverseTemplateArguments(T->getSpecifiedArguments())); }) DEF_TRAVERSE_TYPE(InjectedClassNameType, {}) @@ -1131,7 +1130,7 @@ DEF_TRAVERSE_TYPE(DependentTemplateSpecializationType, { TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); - TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs())); + TRY_TO(TraverseTemplateArguments(T->template_arguments())); }) DEF_TRAVERSE_TYPE(PackExpansionType, { TRY_TO(TraverseType(T->getPattern())); }) diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -572,6 +572,12 @@ SourceLocation RAngleLoc) : LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {} + TemplateArgumentListInfo(TemplateArgumentListInfo &&) = default; + TemplateArgumentListInfo &operator=(TemplateArgumentListInfo &&) = default; + TemplateArgumentListInfo(const TemplateArgumentListInfo &) = default; + TemplateArgumentListInfo & + operator=(const TemplateArgumentListInfo &) = default; + // This can leak if used in an AST node, use ASTTemplateArgumentListInfo // instead. void *operator new(size_t bytes, ASTContext &C) = delete; @@ -588,9 +594,8 @@ return Arguments.data(); } - llvm::ArrayRef arguments() const { - return Arguments; - } + llvm::ArrayRef arguments() const { return Arguments; } + llvm::MutableArrayRef arguments() { return Arguments; } const TemplateArgumentLoc &operator[](unsigned I) const { return Arguments[I]; @@ -698,22 +703,6 @@ const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, const TemplateArgument &Arg); -inline TemplateSpecializationType::iterator - TemplateSpecializationType::end() const { - return getArgs() + getNumArgs(); -} - -inline DependentTemplateSpecializationType::iterator - DependentTemplateSpecializationType::end() const { - return getArgs() + getNumArgs(); -} - -inline const TemplateArgument & - TemplateSpecializationType::getArg(unsigned Idx) const { - assert(Idx < getNumArgs() && "Template argument out of range"); - return getArgs()[Idx]; -} - inline const TemplateArgument & DependentTemplateSpecializationType::getArg(unsigned Idx) const { assert(Idx < getNumArgs() && "Template argument out of range"); 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 @@ -1856,10 +1856,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 { @@ -2405,6 +2404,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 @@ -5336,10 +5347,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. @@ -5385,38 +5396,19 @@ /// \endcode bool isTypeAlias() const { return TemplateSpecializationTypeBits.TypeAlias; } - /// Get the aliased type, if this is a specialization of a type alias - /// template. - QualType getAliasedType() const { - assert(isTypeAlias() && "not a type alias template specialization"); - return *reinterpret_cast(end()); - } - - using iterator = const TemplateArgument *; - - iterator begin() const { return getArgs(); } - iterator end() const; // defined inline in TemplateBase.h - /// Retrieve the name of the template that we are specializing. TemplateName getTemplateName() const { return Template; } - /// Retrieve the template arguments. - const TemplateArgument *getArgs() const { - return reinterpret_cast(this + 1); + ArrayRef getSpecifiedArguments() const { + return {reinterpret_cast(this + 1), + TemplateSpecializationTypeBits.NumSpecifiedArgs}; } - /// Retrieve the number of template arguments. - unsigned getNumArgs() const { - return TemplateSpecializationTypeBits.NumArgs; - } + ArrayRef getConvertedArguments() const; - /// Retrieve a specific template argument as a type. - /// \pre \c isArgType(Arg) - const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h - - ArrayRef template_arguments() const { - return {getArgs(), getNumArgs()}; - } + /// Get the aliased type, if this is a specialization of a type alias + /// template. + QualType getAliasedType() const; bool isSugared() const { return !isDependentType() || isCurrentInstantiation() || isTypeAlias(); @@ -5427,14 +5419,14 @@ } void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { - Profile(ID, Template, template_arguments(), Ctx); - if (isTypeAlias()) - getAliasedType().Profile(ID); + Profile(ID, Template, getSpecifiedArguments(), getConvertedArguments(), + isSugared() ? desugar() : QualType(), 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/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -1634,7 +1634,7 @@ } unsigned getNumArgs() const { - return getTypePtr()->getNumArgs(); + return getTypePtr()->getSpecifiedArguments().size(); } void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) { @@ -1646,7 +1646,8 @@ } TemplateArgumentLoc getArgLoc(unsigned i) const { - return TemplateArgumentLoc(getTypePtr()->getArg(i), getArgLocInfo(i)); + return TemplateArgumentLoc(getTypePtr()->getSpecifiedArguments()[i], + getArgLocInfo(i)); } SourceLocation getTemplateNameLoc() const { @@ -1681,12 +1682,12 @@ setTemplateNameLoc(Loc); setLAngleLoc(Loc); setRAngleLoc(Loc); - initializeArgLocs(Context, getNumArgs(), getTypePtr()->getArgs(), + initializeArgLocs(Context, getTypePtr()->getSpecifiedArguments(), getArgInfos(), Loc); } - static void initializeArgLocs(ASTContext &Context, unsigned NumArgs, - const TemplateArgument *Args, + static void initializeArgLocs(ASTContext &Context, + ArrayRef Args, TemplateArgumentLocInfo *ArgInfos, SourceLocation Loc); 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 @@ -652,29 +652,27 @@ def : Property<"templateName", TemplateName> { let Read = [{ node->getTemplateName() }]; } - def : Property<"templateArguments", Array> { - let Read = [{ node->template_arguments() }]; + def : Property<"specifiedArguments", Array> { + let Read = [{ node->getSpecifiedArguments() }]; } - 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/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -1942,7 +1942,7 @@ inline ArrayRef getTemplateSpecializationArgs(const TemplateSpecializationType &T) { - return llvm::makeArrayRef(T.getArgs(), T.getNumArgs()); + return T.getSpecifiedArguments(); } inline ArrayRef 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 @@ -3004,23 +3004,6 @@ return getObjCLayout(D->getClassInterface(), D); } -static bool -getCanonicalTemplateArguments(const ASTContext &C, - ArrayRef OrigArgs, - SmallVectorImpl &CanonArgs) { - bool AnyNonCanonArgs = false; - unsigned NumArgs = OrigArgs.size(); - CanonArgs.resize(NumArgs); - for (unsigned I = 0; I != NumArgs; ++I) { - const TemplateArgument &OrigArg = OrigArgs[I]; - TemplateArgument &CanonArg = CanonArgs[I]; - CanonArg = C.getCanonicalTemplateArgument(OrigArg); - if (!CanonArg.structurallyEquals(OrigArg)) - AnyNonCanonArgs = true; - } - return AnyNonCanonArgs; -} - //===----------------------------------------------------------------------===// // Type creation/memoization methods //===----------------------------------------------------------------------===// @@ -4847,7 +4830,7 @@ SmallVector Args(ArgPack.pack_size()); TemplateArgument CanonArgPack = ArgPack; bool AnyNonCanonArgs = - getCanonicalTemplateArguments(*this, ArgPack.pack_elements(), Args); + getCanonicalTemplateArguments(ArgPack.pack_elements(), Args); if (AnyNonCanonArgs) CanonArgPack = TemplateArgument::CreatePackCopy(*this, Args); if (!AssociatedDecl->isCanonicalDecl() || AnyNonCanonArgs) { @@ -4899,41 +4882,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!"); +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()); - SmallVector ArgVec; - ArgVec.reserve(Args.size()); - for (const TemplateArgumentLoc &Arg : Args) - ArgVec.push_back(Arg.getArgument()); - - return getTemplateSpecializationType(Template, ArgVec, Underlying); + return getTemplateSpecializationType(Template, SpecifiedArgVec, + SugaredConvertedArgs, + CanonicalConvertedArgs, Underlying); } #ifndef NDEBUG @@ -4946,83 +4929,106 @@ } #endif -QualType -ASTContext::getTemplateSpecializationType(TemplateName Template, - ArrayRef Args, - 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 ASTContext::getCanonicalTemplateArguments( + ArrayRef OrigArgs, + SmallVectorImpl &CanonArgs) const { + bool AnyNonCanonArgs = false; + unsigned NumArgs = OrigArgs.size(); + CanonArgs.resize(NumArgs); + for (unsigned I = 0; I != NumArgs; ++I) { + TemplateArgument OrigArg = OrigArgs[I]; + TemplateArgument &CanonArg = CanonArgs[I]; + CanonArg = getCanonicalTemplateArgument(OrigArg); + if (!CanonArg.structurallyEquals(OrigArg)) + AnyNonCanonArgs = true; } - - // 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); + return AnyNonCanonArgs; } -QualType ASTContext::getCanonicalTemplateSpecializationType( - TemplateName Template, ArrayRef Args) const { +QualType ASTContext::getTemplateSpecializationType( + TemplateName Template, ArrayRef SpecifiedArgs, + ArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Underlying) const { assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); + 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; + } + } + } + } else { + assert(SugaredConvertedArgs.size() != 0); + } + // Look through qualified template names. if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) - Template = TemplateName(QTN->getUnderlyingTemplate()); - - // Build the canonical template specialization type. - TemplateName CanonTemplate = getCanonicalTemplateName(Template); - SmallVector CanonArgs; - ::getCanonicalTemplateArguments(*this, Args, CanonArgs); + 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) { + AnyNonCanonArgs = + getCanonicalTemplateArguments(SugaredConvertedArgs, CanonArgsVec); + 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); } @@ -5117,12 +5123,9 @@ return QualType(T, 0); } -QualType -ASTContext::getDependentTemplateSpecializationType( - ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, - const IdentifierInfo *Name, - const TemplateArgumentListInfo &Args) const { +QualType ASTContext::getDependentTemplateSpecializationType( + ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, + const IdentifierInfo *Name, ArrayRef Args) const { // TODO: avoid this copy SmallVector ArgCopy; for (unsigned I = 0, E = Args.size(); I != E; ++I) @@ -5155,8 +5158,7 @@ if (Keyword == ETK_None) CanonKeyword = ETK_Typename; SmallVector CanonArgs; - bool AnyNonCanonArgs = - ::getCanonicalTemplateArguments(*this, Args, CanonArgs); + bool AnyNonCanonArgs = getCanonicalTemplateArguments(Args, CanonArgs); QualType Canon; if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) { @@ -5777,7 +5779,7 @@ if (DeducedType.isNull()) { SmallVector CanonArgs; bool AnyNonCanonArgs = - ::getCanonicalTemplateArguments(*this, TypeConstraintArgs, CanonArgs); + getCanonicalTemplateArguments(TypeConstraintArgs, CanonArgs); if (AnyNonCanonArgs) { Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack, TypeConstraintConcept, CanonArgs, true); @@ -7333,8 +7335,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(); } @@ -12719,12 +12720,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->getSpecifiedArguments(), + TY->getSpecifiedArguments()); + 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), @@ -12934,11 +12938,14 @@ TY->getTemplateName()); if (!CTN.getAsVoidPointer()) return QualType(); - SmallVector Args; - if (getCommonTemplateArguments(Ctx, Args, TX->template_arguments(), - TY->template_arguments())) + SmallVector SpecAs; + if (getCommonTemplateArguments(Ctx, SpecAs, TX->getSpecifiedArguments(), + TY->getSpecifiedArguments())) 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 @@ -118,8 +118,7 @@ if (!TST->isTypeAlias()) { bool DesugarArgument = false; SmallVector Args; - for (unsigned I = 0, N = TST->getNumArgs(); I != N; ++I) { - const TemplateArgument &Arg = TST->getArg(I); + for (const TemplateArgument &Arg : TST->getSpecifiedArguments()) { if (Arg.getKind() == TemplateArgument::Type) Args.push_back(desugarForDiagnostic(Context, Arg.getAsType(), DesugarArgument)); @@ -130,7 +129,8 @@ if (DesugarArgument) { ShouldAKA = true; QT = Context.getTemplateSpecializationType( - TST->getTemplateName(), Args, QT); + TST->getTemplateName(), Args, TST->getConvertedArguments(), + /*CanonicalConvertedArguments=*/None, QT); } break; } @@ -986,7 +986,7 @@ if (isEnd()) return; // Set to first template argument. If not a parameter pack, done. - TemplateArgument TA = TST->getArg(0); + TemplateArgument TA = TST->getSpecifiedArguments()[0]; if (TA.getKind() != TemplateArgument::Pack) return; // Start looking into the parameter pack. @@ -1007,7 +1007,7 @@ /// isEnd - Returns true if the iterator is one past the end. bool isEnd() const { assert(TST && "InternalIterator is invalid with a null TST."); - return Index >= TST->getNumArgs(); + return Index >= TST->getSpecifiedArguments().size(); } /// &operator++ - Increment the iterator to the next template argument. @@ -1027,11 +1027,11 @@ // Loop until a template argument is found, or the end is reached. while (true) { // Advance to the next template argument. Break if reached the end. - if (++Index == TST->getNumArgs()) + if (++Index == TST->getSpecifiedArguments().size()) break; // If the TemplateArgument is not a parameter pack, done. - TemplateArgument TA = TST->getArg(Index); + TemplateArgument TA = TST->getSpecifiedArguments()[Index]; if (TA.getKind() != TemplateArgument::Pack) break; @@ -1051,7 +1051,7 @@ assert(TST && "InternalIterator is invalid with a null TST."); assert(!isEnd() && "Index exceeds number of arguments."); if (CurrentTA == EndTA) - return TST->getArg(Index); + return TST->getSpecifiedArguments()[Index]; else return *CurrentTA; } @@ -1135,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 @@ -471,9 +471,8 @@ Error ImportDefinition( ObjCProtocolDecl *From, ObjCProtocolDecl *To, ImportDefinitionKind Kind = IDK_Default); - Error ImportTemplateArguments( - const TemplateArgument *FromArgs, unsigned NumFromArgs, - SmallVectorImpl &ToArgs); + Error ImportTemplateArguments(ArrayRef FromArgs, + SmallVectorImpl &ToArgs); Expected ImportTemplateArgument(const TemplateArgument &From); @@ -791,9 +790,8 @@ return std::move(Err); // Import template arguments. - auto TemplArgs = FTSInfo->TemplateArguments->asArray(); - if (Error Err = ImportTemplateArguments(TemplArgs.data(), TemplArgs.size(), - std::get<1>(Result))) + if (Error Err = ImportTemplateArguments(FTSInfo->TemplateArguments->asArray(), + std::get<1>(Result))) return std::move(Err); return Result; @@ -894,8 +892,7 @@ case TemplateArgument::Pack: { SmallVector ToPack; ToPack.reserve(From.pack_size()); - if (Error Err = ImportTemplateArguments( - From.pack_begin(), From.pack_size(), ToPack)) + if (Error Err = ImportTemplateArguments(From.pack_elements(), ToPack)) return std::move(Err); return TemplateArgument( @@ -1436,9 +1433,7 @@ return ToTypeConstraintConcept.takeError(); SmallVector ToTemplateArgs; - ArrayRef FromTemplateArgs = T->getTypeConstraintArguments(); - if (Error Err = ImportTemplateArguments(FromTemplateArgs.data(), - FromTemplateArgs.size(), + if (Error Err = ImportTemplateArguments(T->getTypeConstraintArguments(), ToTemplateArgs)) return std::move(Err); @@ -1557,9 +1552,14 @@ if (!ToTemplateOrErr) return ToTemplateOrErr.takeError(); - SmallVector ToTemplateArgs; - if (Error Err = ImportTemplateArguments( - T->getArgs(), T->getNumArgs(), ToTemplateArgs)) + SmallVector ToSpecifiedArgs; + if (Error Err = + ImportTemplateArguments(T->getSpecifiedArguments(), ToSpecifiedArgs)) + return std::move(Err); + + SmallVector ToConvertedArgs; + if (Error Err = + ImportTemplateArguments(T->getConvertedArguments(), ToConvertedArgs)) return std::move(Err); QualType ToCanonType; @@ -1571,9 +1571,9 @@ else return TyOrErr.takeError(); } - return Importer.getToContext().getTemplateSpecializationType(*ToTemplateOrErr, - ToTemplateArgs, - ToCanonType); + return Importer.getToContext().getTemplateSpecializationType( + *ToTemplateOrErr, ToSpecifiedArgs, ToConvertedArgs, + /*CanonicalConvertedArgs=*/None, ToCanonType); } ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { @@ -1617,8 +1617,7 @@ SmallVector ToPack; ToPack.reserve(T->getNumArgs()); - if (Error Err = ImportTemplateArguments( - T->getArgs(), T->getNumArgs(), ToPack)) + if (Error Err = ImportTemplateArguments(T->template_arguments(), ToPack)) return std::move(Err); return Importer.getToContext().getDependentTemplateSpecializationType( @@ -2189,10 +2188,10 @@ } Error ASTNodeImporter::ImportTemplateArguments( - const TemplateArgument *FromArgs, unsigned NumFromArgs, + ArrayRef FromArgs, SmallVectorImpl &ToArgs) { - for (unsigned I = 0; I != NumFromArgs; ++I) { - if (auto ToOrErr = import(FromArgs[I])) + for (const TemplateArgument &FromArg : FromArgs) { + if (auto ToOrErr = import(FromArg)) ToArgs.push_back(*ToOrErr); else return ToOrErr.takeError(); @@ -3331,7 +3330,7 @@ Optional VisitTemplateSpecializationType(const TemplateSpecializationType *T) { - for (const auto &Arg : T->template_arguments()) + for (const auto &Arg : T->getSpecifiedArguments()) if (checkTemplateArgument(Arg)) return true; // This type is a "sugar" to a record type, it can have a desugared type. @@ -5834,8 +5833,8 @@ // Import template arguments. SmallVector TemplateArgs; - if (Error Err = ImportTemplateArguments( - D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs)) + if (Error Err = + ImportTemplateArguments(D->getTemplateArgs().asArray(), TemplateArgs)) return std::move(Err); // Try to find an existing specialization with these template arguments and // template parameter list. @@ -6156,8 +6155,8 @@ // Import template arguments. SmallVector TemplateArgs; - if (Error Err = ImportTemplateArguments( - D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs)) + if (Error Err = + ImportTemplateArguments(D->getTemplateArgs().asArray(), TemplateArgs)) return std::move(Err); // Try to find an existing specialization with these template arguments. @@ -7813,10 +7812,8 @@ SmallVector ToPartialArguments; if (E->isPartiallySubstituted()) { - if (Error Err = ImportTemplateArguments( - E->getPartialArguments().data(), - E->getPartialArguments().size(), - ToPartialArguments)) + if (Error Err = ImportTemplateArguments(E->getPartialArguments(), + ToPartialArguments)) return std::move(Err); } 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 @@ -526,6 +526,10 @@ return true; } +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + ArrayRef Args1, + ArrayRef Args2); + /// Determine whether two template arguments are equivalent. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const TemplateArgument &Arg1, @@ -568,20 +572,26 @@ Arg2.getAsExpr()); case TemplateArgument::Pack: - if (Arg1.pack_size() != Arg2.pack_size()) - return false; - - for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I) - if (!IsStructurallyEquivalent(Context, Arg1.pack_begin()[I], - Arg2.pack_begin()[I])) - return false; - - return true; + return IsStructurallyEquivalent(Context, Arg1.pack_elements(), + Arg2.pack_elements()); } llvm_unreachable("Invalid template argument kind"); } +/// Determine whether two template argument lists are equivalent. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + ArrayRef Args1, + ArrayRef Args2) { + if (Args1.size() != Args2.size()) + return false; + + for (unsigned I = 0, N = Args1.size(); I != N; ++I) + if (!IsStructurallyEquivalent(Context, Args1[I], Args2[I])) + return false; + return true; +} + /// Determine structural equivalence for the common part of array /// types. static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context, @@ -1011,16 +1021,10 @@ if (Auto1->getTypeConstraintConcept() != Auto2->getTypeConstraintConcept()) return false; - ArrayRef Auto1Args = - Auto1->getTypeConstraintArguments(); - ArrayRef Auto2Args = - Auto2->getTypeConstraintArguments(); - if (Auto1Args.size() != Auto2Args.size()) + if (!IsStructurallyEquivalent(Context, + Auto1->getTypeConstraintArguments(), + Auto2->getTypeConstraintArguments())) return false; - for (unsigned I = 0, N = Auto1Args.size(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, Auto1Args[I], Auto2Args[I])) - return false; - } } break; } @@ -1094,13 +1098,12 @@ if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(), Spec2->getTemplateName())) return false; - if (Spec1->getNumArgs() != Spec2->getNumArgs()) + if (!IsStructurallyEquivalent(Context, Spec1->getSpecifiedArguments(), + Spec2->getSpecifiedArguments())) + return false; + if (!IsStructurallyEquivalent(Context, Spec1->getConvertedArguments(), + Spec2->getConvertedArguments())) return false; - for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, Spec1->getArg(I), - Spec2->getArg(I))) - return false; - } break; } @@ -1151,13 +1154,9 @@ if (!IsStructurallyEquivalent(Spec1->getIdentifier(), Spec2->getIdentifier())) return false; - if (Spec1->getNumArgs() != Spec2->getNumArgs()) + if (!IsStructurallyEquivalent(Context, Spec1->template_arguments(), + Spec2->template_arguments())) return false; - for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, Spec1->getArg(I), - Spec2->getArg(I))) - return false; - } break; } diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -1001,7 +1001,7 @@ if (const auto* TSI = S->getTypeAsWritten()) if (const auto *TST = dyn_cast(TSI->getType())) - Args = TST->template_arguments(); + Args = TST->getSpecifiedArguments(); printTemplateArguments( Args, S->getSpecializedTemplate()->getTemplateParameters()); } 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 @@ -624,9 +624,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 @@ -1244,8 +1244,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->getArgs(), - TST->getNumArgs()); + auto Args = TST->isCanonicalUnqualified() ? TST->getConvertedArguments() + : TST->getSpecifiedArguments(); + mangleTemplateArgs(TST->getTemplateName(), Args.begin(), Args.size()); addSubstitution(QualType(TST, 0)); } } else if (const auto *DTST = @@ -2410,13 +2411,14 @@ break; } } - + auto Args = TST->isCanonicalUnqualified() ? TST->getConvertedArguments() + : TST->getSpecifiedArguments(); // 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->getArgs(), TST->getNumArgs()); + mangleTemplateArgs(TemplateName(), Args.begin(), Args.size()); break; } @@ -3873,8 +3875,10 @@ } void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { + auto Args = T->isCanonicalUnqualified() ? T->getConvertedArguments() + : T->getSpecifiedArguments(); if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) { - mangleTemplateName(TD, T->getArgs(), T->getNumArgs()); + mangleTemplateName(TD, Args.begin(), Args.size()); } else { if (mangleSubstitution(QualType(T, 0))) return; @@ -3884,7 +3888,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->getArgs(), T->getNumArgs()); + mangleTemplateArgs(T->getTemplateName(), Args.begin(), Args.size()); addSubstitution(QualType(T, 0)); } } diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp --- a/clang/lib/AST/NestedNameSpecifier.cpp +++ b/clang/lib/AST/NestedNameSpecifier.cpp @@ -315,7 +315,7 @@ TemplateName::Qualified::None); // Print the template argument list. - printTemplateArgumentList(OS, SpecType->template_arguments(), + printTemplateArgumentList(OS, SpecType->getSpecifiedArguments(), InnerPolicy); } else if (const auto *DepSpecType = dyn_cast(T)) { diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -1015,8 +1015,8 @@ void VisitEnumType(const EnumType *T) { VisitTagType(T); } void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { - ID.AddInteger(T->getNumArgs()); - for (const auto &TA : T->template_arguments()) { + ID.AddInteger(T->getSpecifiedArguments().size()); + for (const auto &TA : T->getSpecifiedArguments()) { Hash.AddTemplateArgument(TA); } Hash.AddTemplateName(T->getTemplateName()); 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 @@ -129,11 +129,9 @@ if (const auto *TST = dyn_cast(TypePtr)) { bool MightHaveChanged = false; SmallVector FQArgs; - for (TemplateSpecializationType::iterator I = TST->begin(), E = TST->end(); - I != E; ++I) { - // Cheap to copy and potentially modified by - // getFullyQualifedTemplateArgument. - TemplateArgument Arg(*I); + // Cheap to copy and potentially modified by + // getFullyQualifedTemplateArgument. + for (TemplateArgument Arg : TST->getSpecifiedArguments()) { MightHaveChanged |= getFullyQualifiedTemplateArgument( Ctx, Arg, WithGlobalNsPrefix); FQArgs.push_back(Arg); @@ -143,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. @@ -175,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()) { @@ -3808,17 +3819,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"); @@ -3828,39 +3842,63 @@ 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(getSpecifiedArguments(), 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 + getNumArgs()) = AliasedType; - } + if (IsAlias) + *reinterpret_cast(const_cast( + getConvertedArguments().end())) = Underlying; } -void -TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, - TemplateName T, - ArrayRef Args, - const ASTContext &Context) { +ArrayRef +TemplateSpecializationType::getConvertedArguments() const { + return {getSpecifiedArguments().end(), + TemplateSpecializationTypeBits.NumConvertedArgs}; +} + +QualType TemplateSpecializationType::getAliasedType() const { + assert(isTypeAlias() && "not a type alias template specialization"); + return *reinterpret_cast(getConvertedArguments().end()); +} + +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/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -568,17 +568,16 @@ setTemplateNameLoc(Loc); setLAngleLoc(Loc); setRAngleLoc(Loc); - TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(), - getTypePtr()->getArgs(), - getArgInfos(), Loc); + TemplateSpecializationTypeLoc::initializeArgLocs( + Context, + ArrayRef(getTypePtr()->getArgs(), getNumArgs()), + getArgInfos(), Loc); } -void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, - unsigned NumArgs, - const TemplateArgument *Args, - TemplateArgumentLocInfo *ArgInfos, - SourceLocation Loc) { - for (unsigned i = 0, e = NumArgs; i != e; ++i) { +void TemplateSpecializationTypeLoc::initializeArgLocs( + ASTContext &Context, ArrayRef Args, + TemplateArgumentLocInfo *ArgInfos, SourceLocation Loc) { + for (unsigned i = 0, e = Args.size(); i != e; ++i) { switch (Args[i].getKind()) { case TemplateArgument::Null: llvm_unreachable("Impossible TemplateArgument"); @@ -635,9 +634,10 @@ setRAngleLoc(Loc); setLAngleLoc(Loc); setRParenLoc(Loc); - TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(), - getTypePtr()->getArgs(), - getArgInfos(), Loc); + TemplateSpecializationTypeLoc::initializeArgLocs( + Context, + ArrayRef(getTypePtr()->getArgs(), getNumArgs()), + getArgInfos(), Loc); setNameLoc(Loc); } 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 @@ -1379,7 +1379,7 @@ if (!Policy.PrintCanonicalTypes && TAW) { const TemplateSpecializationType *TST = cast(TAW->getType()); - Args = TST->template_arguments(); + Args = TST->getSpecifiedArguments(); } else { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); Args = TemplateArgs.asArray(); @@ -1502,7 +1502,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->getSpecifiedArguments(); + printTemplateArgumentList(OS, Args, Policy, TPL); spaceBeforePlaceHolder(OS); } @@ -1985,7 +1988,8 @@ ArrayRef TemplateArgs; if (auto *TTST = T->getAs()) { Template = TTST->getTemplateName(); - TemplateArgs = TTST->template_arguments(); + assert(!TTST->isCanonicalUnqualified()); + TemplateArgs = TTST->getSpecifiedArguments(); } else if (auto *CTSD = dyn_cast_or_null( T->getAsCXXRecordDecl())) { Template = TemplateName(CTSD->getSpecializedTemplate()); @@ -1997,11 +2001,12 @@ if (!isSubstitutedTemplateArgument(Ctx, Template, PTST->getTemplateName(), Args, Depth)) return false; - if (TemplateArgs.size() != PTST->getNumArgs()) + 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->getArg(I), - Args, Depth)) + if (!isSubstitutedTemplateArgument(Ctx, TemplateArgs[I], PArgs[I], Args, + Depth)) return false; return true; } diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1275,7 +1275,8 @@ llvm::raw_svector_ostream OS(NS); Ty->getTemplateName().print(OS, getPrintingPolicy(), TemplateName::Qualified::None); - printTemplateArgumentList(OS, Ty->template_arguments(), getPrintingPolicy()); + printTemplateArgumentList(OS, Ty->getSpecifiedArguments(), + getPrintingPolicy()); SourceLocation Loc = AliasDecl->getLocation(); return DBuilder.createTypedef(Src, OS.str(), getOrCreateFile(Loc), 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 @@ -855,9 +855,9 @@ = T->getAs()) { Out << '>'; VisitTemplateName(Spec->getTemplateName()); - Out << Spec->getNumArgs(); - for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) - VisitTemplateArgument(Spec->getArg(I)); + Out << Spec->getConvertedArguments().size(); + for (const TemplateArgument &Arg : Spec->getConvertedArguments()) + VisitTemplateArgument(Arg); return; } if (const DependentNameType *DNT = T->getAs()) { diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -931,10 +931,9 @@ // Handle a dependent template specialization for which we cannot resolve // the template name. assert(DTN->getQualifier() == SS.getScopeRep()); - QualType T = Context.getDependentTemplateSpecializationType(ETK_None, - DTN->getQualifier(), - DTN->getIdentifier(), - TemplateArgs); + QualType T = Context.getDependentTemplateSpecializationType( + ETK_None, DTN->getQualifier(), DTN->getIdentifier(), + TemplateArgs.arguments()); // Create source-location information for this type. TypeLocBuilder Builder; diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -4659,9 +4659,10 @@ // Note we only handle the sugared types, they closely match what users wrote. // We explicitly choose to not handle ClassTemplateSpecializationDecl. if (auto *Specialization = T->getAs()) { - if (Specialization->getNumArgs() != 1) + if (Specialization->getSpecifiedArguments().size() != 1) return nullptr; - const TemplateArgument &Argument = Specialization->getArg(0); + const TemplateArgument &Argument = + Specialization->getSpecifiedArguments()[0]; if (Argument.getKind() != TemplateArgument::Type) return nullptr; return Argument.getAsType()->getAs(); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11503,7 +11503,7 @@ Ty->getAs()) { Template = dyn_cast_or_null( TST->getTemplateName().getAsTemplateDecl()); - Arguments = TST->getArgs(); + Arguments = TST->getSpecifiedArguments().begin(); } if (!Template) return false; 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 @@ -3500,7 +3500,8 @@ static QualType checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, - const SmallVectorImpl &Converted, + ArrayRef SugaredConverted, + ArrayRef CanonicalConverted, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { ASTContext &Context = SemaRef.getASTContext(); @@ -3519,7 +3520,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)) { @@ -3528,10 +3529,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 @@ -3561,7 +3563,7 @@ // Wrap the template in substitution sugar. TemplateName TN = SemaRef.Context.getSubstTemplateTemplateParm( cast(TPL->getParam(0)), - Converted[0].getAsTemplate()); + SugaredConverted[0].getAsTemplate()); // The first template argument will be reused as the template decl that // our synthetic template arguments will be applied to. @@ -3572,13 +3574,14 @@ // 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 " @@ -3746,28 +3749,26 @@ // assume the template is a type template. Either our assumption is // correct, or the code is ill-formed and will be diagnosed when the // dependent name is substituted. - return Context.getDependentTemplateSpecializationType(ETK_None, - DTN->getQualifier(), - DTN->getIdentifier(), - TemplateArgs); + return Context.getDependentTemplateSpecializationType( + ETK_None, DTN->getQualifier(), DTN->getIdentifier(), + TemplateArgs.arguments()); if (Name.getAsAssumedTemplateName() && 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 @@ -3780,8 +3781,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(); @@ -3839,7 +3843,8 @@ } } else if (auto *BTD = dyn_cast(Template)) { CanonType = checkBuiltinTemplateIdType(*this, BTD, SugaredConverted, - TemplateLoc, TemplateArgs); + CanonicalConverted, TemplateLoc, + TemplateArgs); } else if (Name.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( TemplateArgs, CanonicalConverted)) { @@ -3850,8 +3855,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. @@ -3938,7 +3944,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, @@ -4049,11 +4056,10 @@ translateTemplateArguments(TemplateArgsIn, TemplateArgs); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { - QualType T - = Context.getDependentTemplateSpecializationType(ETK_None, - DTN->getQualifier(), - DTN->getIdentifier(), - TemplateArgs); + assert(SS.getScopeRep() == DTN->getQualifier()); + QualType T = Context.getDependentTemplateSpecializationType( + ETK_None, DTN->getQualifier(), DTN->getIdentifier(), + TemplateArgs.arguments()); // Build type-source information. TypeLocBuilder TLB; DependentTemplateSpecializationTypeLoc SpecTL @@ -4119,10 +4125,10 @@ = TypeWithKeyword::getKeywordForTagTypeKind(TagKind); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { - QualType T = Context.getDependentTemplateSpecializationType(Keyword, - DTN->getQualifier(), - DTN->getIdentifier(), - TemplateArgs); + assert(SS.getScopeRep() == DTN->getQualifier()); + QualType T = Context.getDependentTemplateSpecializationType( + Keyword, DTN->getQualifier(), DTN->getIdentifier(), + TemplateArgs.arguments()); // Build type-source information. TypeLocBuilder TLB; @@ -8572,9 +8578,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()) && @@ -8641,9 +8647,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); } @@ -8720,9 +8726,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); @@ -9889,10 +9895,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. @@ -10632,10 +10637,9 @@ // Construct a dependent template specialization type. assert(DTN && "dependent template has non-dependent name?"); assert(DTN->getQualifier() == SS.getScopeRep()); - QualType T = Context.getDependentTemplateSpecializationType(ETK_Typename, - DTN->getQualifier(), - DTN->getIdentifier(), - TemplateArgs); + QualType T = Context.getDependentTemplateSpecializationType( + ETK_Typename, DTN->getQualifier(), DTN->getIdentifier(), + TemplateArgs.arguments()); // Create source-location information for this type. TypeLocBuilder Builder; 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); } @@ -5399,7 +5397,7 @@ AtLeastAsSpecialized = !FinishTemplateArgumentDeduction( S, P2, /*IsPartialOrdering=*/true, TemplateArgumentList(TemplateArgumentList::OnStack, - TST1->template_arguments()), + TST1->getConvertedArguments()), Deduced, Info); }); return AtLeastAsSpecialized; @@ -5469,11 +5467,12 @@ // Consider this a fix for CWG1432. Similar to the fix for CWG1395. auto *TST1 = T1->castAs(); auto *TST2 = T2->castAs(); - if (TST1->getNumArgs()) { - const TemplateArgument &TA1 = TST1->template_arguments().back(); + if (TST1->getConvertedArguments().size()) { + const TemplateArgument &TA1 = TST1->getConvertedArguments().back(); if (TA1.getKind() == TemplateArgument::Pack) { - assert(TST1->getNumArgs() == TST2->getNumArgs()); - 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(); @@ -5555,9 +5554,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); @@ -5571,13 +5572,18 @@ SmallVector PrimaryArgs; Context.getInjectedTemplateArgs(Primary->getTemplateParameters(), PrimaryArgs); + Context.getCanonicalTemplateArguments(PrimaryArgs, PrimaryArgs); + + SmallVector SpecArgs; + Context.getCanonicalTemplateArguments(Spec->getTemplateArgs().asArray(), + SpecArgs); TemplateName CanonTemplate = Context.getCanonicalTemplateName(TemplateName(Primary)); QualType PrimaryT = Context.getTemplateSpecializationType( - CanonTemplate, PrimaryArgs); + CanonTemplate, ArrayRef(), None, PrimaryArgs); QualType PartialT = Context.getTemplateSpecializationType( - CanonTemplate, Spec->getTemplateArgs().asArray()); + CanonTemplate, ArrayRef(), None, SpecArgs); VarTemplatePartialSpecializationDecl *MaybeSpec = getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info); @@ -5607,6 +5613,7 @@ // template parameters from the respective function template SmallVector AArgs; Context.getInjectedTemplateArgs(A, AArgs); + Context.getCanonicalTemplateArguments(AArgs, 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. @@ -5617,6 +5624,7 @@ SFINAETrap Trap(*this); Context.getInjectedTemplateArgs(P, PArgs); + Context.getCanonicalTemplateArguments(PArgs, PArgs); TemplateArgumentListInfo PArgList(P->getLAngleLoc(), P->getRAngleLoc()); for (unsigned I = 0, N = P->size(); I != N; ++I) { @@ -5642,8 +5650,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 @@ -5936,13 +5946,11 @@ // 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 (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) - MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth, - Used); + for (const TemplateArgument &Arg : Spec->getConvertedArguments()) + MarkUsedTemplateParameters(Ctx, Arg, OnlyDeduced, Depth, Used); break; } 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 @@ -3759,12 +3759,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 @@ -3774,7 +3768,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); @@ -4113,11 +4108,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 @@ -4125,12 +4115,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 @@ -4161,8 +4148,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; @@ -4238,11 +4225,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 @@ -4252,7 +4234,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 @@ -1061,10 +1061,9 @@ // If it's still dependent, make a dependent specialization. if (InstName.getAsDependentTemplateName()) - return SemaRef.Context.getDependentTemplateSpecializationType(Keyword, - QualifierLoc.getNestedNameSpecifier(), - Name, - Args); + return SemaRef.Context.getDependentTemplateSpecializationType( + Keyword, QualifierLoc.getNestedNameSpecifier(), Name, + Args.arguments()); // Otherwise, make an elaborated type wrapping a non-dependent // specialization. @@ -6681,12 +6680,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. @@ -6746,12 +6757,9 @@ // FIXME: maybe don't rebuild if all the template arguments are the same. if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { - QualType Result - = getSema().Context.getDependentTemplateSpecializationType( - TL.getTypePtr()->getKeyword(), - DTN->getQualifier(), - DTN->getIdentifier(), - NewTemplateArgs); + QualType Result = getSema().Context.getDependentTemplateSpecializationType( + TL.getTypePtr()->getKeyword(), DTN->getQualifier(), + DTN->getIdentifier(), NewTemplateArgs.arguments()); DependentTemplateSpecializationTypeLoc NewTL = TLB.push(Result); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -6737,9 +6737,8 @@ TL.setRAngleLoc(readSourceLocation()); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) TL.setArgLocInfo( - i, - Reader.readTemplateArgumentLocInfo( - TL.getTypePtr()->getArg(i).getKind())); + i, Reader.readTemplateArgumentLocInfo( + TL.getTypePtr()->getSpecifiedArguments()[i].getKind())); } void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) { 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 @@ -503,7 +503,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 @@ -19,7 +19,7 @@ // CHECK-NEXT: | |-BuiltinTemplate 0x{{[0-9A-Fa-f]+}} '__make_integer_seq' // 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':'int' // CHECK-NEXT: | |-value: Int 0 // CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} 'int':'int' 0 // CHECK-NEXT: `-RecordType 0x{{[0-9A-Fa-f]+}} 'A' @@ -65,7 +65,7 @@ template