diff --git a/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp index 2223a1999f73..a7f4adc8be94 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp @@ -94,9 +94,9 @@ void UseTransparentFunctorsCheck::check( unsigned ArgNum = 0; const auto *FunctorParentType = FunctorParentLoc.getType()->castAs(); - for (; ArgNum < FunctorParentType->template_arguments().size(); ++ArgNum) { + for (; ArgNum < FunctorParentType->getSpecifiedArguments().size(); ++ArgNum) { const TemplateArgument &Arg = - FunctorParentType->template_arguments()[ArgNum]; + FunctorParentType->getSpecifiedArguments()[ArgNum]; if (Arg.getKind() != TemplateArgument::Type) continue; QualType ParentArgType = Arg.getAsType(); @@ -106,7 +106,7 @@ void UseTransparentFunctorsCheck::check( break; } // Functor is a default template argument. - if (ArgNum == FunctorParentType->template_arguments().size()) + 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 index 5abe4f77d659..5384b0fe3c45 100644 --- a/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp +++ b/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp @@ -181,7 +181,7 @@ isCXXComplexTypeMatching(const TemplateSpecializationType *const Template, if (Template->getAsCXXRecordDecl()->getName() != "complex") return true; - const auto *Builtin = Template->template_arguments()[0] + const auto *Builtin = Template->getSpecifiedArguments()[0] .getAsType() .getTypePtr() ->getAs(); diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp index 66b587f00ff4..108f3c7a284b 100644 --- a/clang-tools-extra/clangd/AST.cpp +++ b/clang-tools-extra/clangd/AST.cpp @@ -437,9 +437,15 @@ bool hasReservedScope(const DeclContext &DC) { QualType declaredType(const TypeDecl *D) { ASTContext &Context = D->getASTContext(); if (const auto *CTSD = llvm::dyn_cast(D)) - if (const auto *Args = CTSD->getTemplateArgsAsWritten()) + if (const auto *ArgList = CTSD->getTemplateArgsAsWritten()) { + SmallVector Args(ArgList->arguments().size()); + for (unsigned I = 0, E = Args.size(); I < E; ++I) + Args[I] = ArgList->arguments()[I].getArgument(); return Context.getTemplateSpecializationType( - TemplateName(CTSD->getSpecializedTemplate()), Args->arguments()); + TemplateName(CTSD->getSpecializedTemplate()), Args, + /*SugaredConvertedArgs=*/std::nullopt, + /*CanonicalConvertedArgs=*/std::nullopt); + } return Context.getTypeDeclType(D); } diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 3ff9f308f3a5..9f05042f0512 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1808,22 +1808,24 @@ public: bool ParameterPack, TemplateTypeParmDecl *ParmDecl = nullptr) const; - QualType getTemplateSpecializationType(TemplateName T, - ArrayRef Args, - QualType Canon = QualType()) const; + QualType getTemplateSpecializationType( + TemplateName T, ArrayRef SpecifiedArgs, + ArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Canon = QualType()) const; - QualType - getCanonicalTemplateSpecializationType(TemplateName T, - ArrayRef Args) const; + QualType getTemplateSpecializationType( + TemplateName T, ArrayRef SpecifiedArgs, + ArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Canon = QualType()) const; - QualType getTemplateSpecializationType(TemplateName T, - ArrayRef Args, - QualType Canon = QualType()) const; - - TypeSourceInfo * - getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc, - const TemplateArgumentListInfo &Args, - 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; @@ -2939,6 +2941,12 @@ public: 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/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index 7bb435146f75..3659b6c0205d 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -456,7 +456,7 @@ public: Visit(T->getArgumentPack()); } void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { - for (const auto &Arg : T->template_arguments()) + for (const auto &Arg : T->getSpecifiedArguments()) Visit(Arg); } void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index a8100b642e04..7ba21aa2c1a4 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -610,8 +610,10 @@ public: Profile(llvm::FoldingSetNodeID &ID, ArrayRef TemplateArgs, const ASTContext &Context) { ID.AddInteger(TemplateArgs.size()); + // We allow instantiating deduction guides with non-canonical template + // arguments. for (const TemplateArgument &TemplateArg : TemplateArgs) - TemplateArg.Profile(ID, Context); + TemplateArg.Profile(ID, Context, /*Canonical=*/false); } }; @@ -2090,7 +2092,7 @@ public: const ASTContext &Context) { ID.AddInteger(TemplateArgs.size()); for (const TemplateArgument &TemplateArg : TemplateArgs) - TemplateArg.Profile(ID, Context); + TemplateArg.Profile(ID, Context, /*Canonical=*/true); } static bool classof(const Decl *D) { return classofKind(D->getKind()); } @@ -2864,7 +2866,7 @@ public: const ASTContext &Context) { ID.AddInteger(TemplateArgs.size()); for (const TemplateArgument &TemplateArg : TemplateArgs) - TemplateArg.Profile(ID, Context); + TemplateArg.Profile(ID, Context, /*Canonical=*/true); } static bool classof(const Decl *D) { return classofKind(D->getKind()); } diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 3edc8684d0a1..8838721556c8 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1134,7 +1134,10 @@ DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, { 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->getSpecifiedArguments())); }) DEF_TRAVERSE_TYPE(InjectedClassNameType, {}) diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h index a800a16fc3e7..fc305baff39c 100644 --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -462,7 +462,8 @@ public: void dump() const; /// Used to insert TemplateArguments into FoldingSets. - void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const; + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + bool Canonical) const; }; /// Location information for a TemplateArgument. diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 06d60f618ddc..736acfabc7d2 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2199,10 +2199,9 @@ protected: /// 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 { @@ -2821,6 +2820,18 @@ public: /// 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 @@ -6594,7 +6605,7 @@ public: static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType Deduced, AutoTypeKeyword Keyword, bool IsDependent, ConceptDecl *CD, - ArrayRef Arguments); + ArrayRef Arguments, bool Canonical); static bool classof(const Type *T) { return T->getTypeClass() == Auto; @@ -6672,10 +6683,10 @@ class TemplateSpecializationType : public Type, public llvm::FoldingSetNode { /// 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. @@ -6728,11 +6739,13 @@ public: /// Retrieve the name of the template that we are specializing. TemplateName getTemplateName() const { return Template; } - ArrayRef template_arguments() const { + ArrayRef getSpecifiedArguments() const { return {reinterpret_cast(this + 1), - TemplateSpecializationTypeBits.NumArgs}; + TemplateSpecializationTypeBits.NumSpecifiedArgs}; } + ArrayRef getConvertedArguments() const; + bool isSugared() const { return !isDependentType() || isCurrentInstantiation() || isTypeAlias(); } @@ -6743,8 +6756,10 @@ public: 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, + bool Canonical); static bool classof(const Type *T) { return T->getTypeClass() == TemplateSpecialization; @@ -7099,13 +7114,14 @@ public: QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { - Profile(ID, Context, getKeyword(), Name, template_arguments()); + Profile(ID, Context, getKeyword(), Name, template_arguments(), + isCanonicalUnqualified()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, ElaboratedTypeKeyword Keyword, const DependentTemplateStorage &Name, - ArrayRef Args); + ArrayRef Args, bool IsCanonical); static bool classof(const Type *T) { return T->getTypeClass() == DependentTemplateSpecialization; diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index 92661b8b13fe..b8bf7b198d92 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -1718,7 +1718,7 @@ public: } unsigned getNumArgs() const { - return getTypePtr()->template_arguments().size(); + return getTypePtr()->getSpecifiedArguments().size(); } void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) { @@ -1730,7 +1730,7 @@ public: } TemplateArgumentLoc getArgLoc(unsigned i) const { - return TemplateArgumentLoc(getTypePtr()->template_arguments()[i], + return TemplateArgumentLoc(getTypePtr()->getSpecifiedArguments()[i], getArgLocInfo(i)); } @@ -1766,7 +1766,7 @@ public: setTemplateNameLoc(Loc); setLAngleLoc(Loc); setRAngleLoc(Loc); - initializeArgLocs(Context, getTypePtr()->template_arguments(), + initializeArgLocs(Context, getTypePtr()->getSpecifiedArguments(), getArgInfos(), Loc); } diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index 66d490850678..4b5b0c084bc4 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -743,29 +743,27 @@ let Class = TemplateSpecializationType in { 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() - ? std::optional(node->getAliasedType()) + ? node->getAliasedType() : node->isCanonicalUnqualified() - ? std::nullopt - : std::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 index 55a925bf8690..03cc39421b2b 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -1949,7 +1949,7 @@ getTemplateSpecializationArgs(const VarTemplateSpecializationDecl &D) { inline ArrayRef getTemplateSpecializationArgs(const TemplateSpecializationType &T) { - return T.template_arguments(); + return T.getSpecifiedArguments(); } inline ArrayRef diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 52dc47703912..1635c03eba8c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6983,7 +6983,7 @@ def err_illegal_decl_mempointer_to_void : Error< "'%0' declared as a member pointer to void">; def err_illegal_decl_mempointer_in_nonclass : Error<"%0 does not point into a class">; -def err_reference_to_void : Error<"cannot form a reference to 'void'">; +def err_reference_to_void : Error<"cannot form a reference to %0">; def err_nonfunction_block_type : Error< "block pointer to non-function type is invalid">; def err_return_block_has_expr : Error<"void block should not return a value">; diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h index 648a9c51ae6c..bfc55e42c1f5 100644 --- a/clang/include/clang/Sema/SemaConcept.h +++ b/clang/include/clang/Sema/SemaConcept.h @@ -49,9 +49,9 @@ struct alignas(ConstraintAlignment) AtomicConstraint { for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I) { llvm::FoldingSetNodeID IDA, IDB; C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument()) - .Profile(IDA, C); + .Profile(IDA, C, /*Canonical=*/true); C.getCanonicalTemplateArgument((*Other.ParameterMapping)[I].getArgument()) - .Profile(IDB, C); + .Profile(IDB, C, /*Canonical=*/true); if (IDA != IDB) return false; } diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h index 141804185083..90993687e69a 100644 --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -247,6 +247,10 @@ public: 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/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp index f7ee0fb3ee92..3b8883fa5cbb 100644 --- a/clang/lib/AST/ASTConcept.cpp +++ b/clang/lib/AST/ASTConcept.cpp @@ -80,7 +80,7 @@ void ConstraintSatisfaction::Profile( ID.AddPointer(ConstraintOwner); ID.AddInteger(TemplateArgs.size()); for (auto &Arg : TemplateArgs) - Arg.Profile(ID, C); + Arg.Profile(ID, C, /*Canonical=*/false); } ConceptReference * diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 1b6b3d06ddc1..2b2209431ce7 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3083,14 +3083,28 @@ static auto getCanonicalTemplateArguments(const ASTContext &C, ArrayRef Args, bool &AnyNonCanonArgs) { SmallVector CanonArgs(Args); - for (auto &Arg : CanonArgs) { - TemplateArgument OrigArg = Arg; - Arg = C.getCanonicalTemplateArgument(Arg); - AnyNonCanonArgs |= !Arg.structurallyEquals(OrigArg); - } + AnyNonCanonArgs |= C.canonicalizeTemplateArguments(CanonArgs); return CanonArgs; } +bool ASTContext::canonicalizeTemplateArguments( + MutableArrayRef Args) const { + bool AnyNonCanonArgs = false; + for (auto &Arg : Args) { + TemplateArgument OrigArg = Arg; + Arg = getCanonicalTemplateArgument(Arg); + if (Arg.getKind() == TemplateArgument::Expression) { + llvm::FoldingSetNodeID ID1, ID2; + OrigArg.getAsExpr()->Profile(ID1, *this, /*Canonical=*/false); + Arg.getAsExpr()->Profile(ID2, *this, /*Canonical=*/true); + AnyNonCanonArgs |= ID1 != ID2; + } else { + AnyNonCanonArgs |= !Arg.structurallyEquals(OrigArg); + } + } + return AnyNonCanonArgs; +} + //===----------------------------------------------------------------------===// // Type creation/memoization methods //===----------------------------------------------------------------------===// @@ -5538,41 +5552,41 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, 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 @@ -5585,82 +5599,90 @@ static bool hasAnyPackExpansions(ArrayRef Args) { } #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!"); + SmallVector CanonArgsVec; + TemplateName CanonTemplate = + getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true); + bool NonCanonical = !SpecifiedArgs.empty() || !Underlying.isNull() || + Template != CanonTemplate; + if (CanonicalConvertedArgs.size() != 0) { + if (SugaredConvertedArgs.empty()) { + SugaredConvertedArgs = CanonicalConvertedArgs; + } else if (!NonCanonical) { + for (unsigned I = 0; I < SugaredConvertedArgs.size(); ++I) { + TemplateArgument C = CanonicalConvertedArgs[I]; + TemplateArgument S = SugaredConvertedArgs[I]; + assert(C.getKind() == S.getKind()); + if (C.getKind() == TemplateArgument::Expression) { + llvm::FoldingSetNodeID ID1, ID2; + C.getAsExpr()->Profile(ID1, *this, /*Canonical=*/true); + S.getAsExpr()->Profile(ID2, *this, /*Canonical=*/false); + if (ID1 != ID2) { + NonCanonical = true; + break; + } + } else if (!C.structurallyEquals(S)) { + NonCanonical = true; + break; + } + } + } + } else { + CanonArgsVec = ::getCanonicalTemplateArguments(*this, SugaredConvertedArgs, + NonCanonical); + CanonicalConvertedArgs = CanonArgsVec; + } + assert(SugaredConvertedArgs.size() == CanonicalConvertedArgs.size()); + + llvm::FoldingSetNodeID ID; + TemplateSpecializationType::Profile(ID, Template, SpecifiedArgs, + SugaredConvertedArgs, Underlying, *this, + /*Canonical=*/!NonCanonical); + + void *InsertPos = nullptr; + if (auto *T = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(T, 0); + const auto *TD = Template.getAsTemplateDecl(/*IgnoreDeduced=*/true); 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)) && + 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; - CanonType = getCanonicalTemplateSpecializationType(Template, Args); + + if (NonCanonical) { + Underlying = getTemplateSpecializationType( + CanonTemplate, ArrayRef(), std::nullopt, + 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); + } } - // 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), - alignof(TemplateSpecializationType)); - auto *Spec - = new (Mem) TemplateSpecializationType(Template, Args, CanonType, - IsTypeAlias ? Underlying : QualType()); + void *Mem = + Allocate(sizeof(TemplateSpecializationType) + + sizeof(TemplateArgument) * + (SpecifiedArgs.size() + SugaredConvertedArgs.size()) + + (IsTypeAlias ? sizeof(QualType) : 0), + alignof(TemplateSpecializationType)); + auto *Spec = new (Mem) TemplateSpecializationType( + Template, IsTypeAlias, SpecifiedArgs, SugaredConvertedArgs, Underlying); Types.push_back(Spec); - return QualType(Spec, 0); -} - -QualType ASTContext::getCanonicalTemplateSpecializationType( - TemplateName Template, ArrayRef Args) const { - assert(!Template.getAsDependentTemplateName() && - "No dependent template names here!"); - - // Build the canonical template specialization type. - // Any DeducedTemplateNames are ignored, because the effective name of a TST - // accounts for the TST arguments laid over any default arguments contained in - // its name. - TemplateName CanonTemplate = - getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true); - - bool AnyNonCanonArgs = false; - auto CanonArgs = - ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs); - - // Determine whether this canonical template specialization type already - // exists. - llvm::FoldingSetNodeID ID; - TemplateSpecializationType::Profile(ID, CanonTemplate, - CanonArgs, *this); - - void *InsertPos = nullptr; - TemplateSpecializationType *Spec - = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); - - if (!Spec) { - // Allocate a new canonical template specialization type. - void *Mem = Allocate((sizeof(TemplateSpecializationType) + - sizeof(TemplateArgument) * CanonArgs.size()), - alignof(TemplateSpecializationType)); - Spec = new (Mem) TemplateSpecializationType(CanonTemplate, - CanonArgs, - QualType(), QualType()); - Types.push_back(Spec); - TemplateSpecializationTypes.InsertNode(Spec, InsertPos); - } - - assert(Spec->isDependentType() && - "Non-dependent template-id type must have a canonical type"); + TemplateSpecializationTypes.InsertNode(Spec, InsertPos); return QualType(Spec, 0); } @@ -5773,7 +5795,8 @@ QualType ASTContext::getDependentTemplateSpecializationType( ElaboratedTypeKeyword Keyword, const DependentTemplateStorage &Name, ArrayRef Args, bool IsCanonical) const { llvm::FoldingSetNodeID ID; - DependentTemplateSpecializationType::Profile(ID, *this, Keyword, Name, Args); + DependentTemplateSpecializationType::Profile(ID, *this, Keyword, Name, Args, + IsCanonical); void *InsertPos = nullptr; if (auto *T = DependentTemplateSpecializationTypes.FindNodeOrInsertPos( @@ -6448,7 +6471,7 @@ QualType ASTContext::getAutoTypeInternal( !DeducedType.isNull() && DeducedType->isDependentType(); AutoType::Profile(ID, *this, DeducedType, Keyword, IsDependent || IsDeducedDependent, TypeConstraintConcept, - TypeConstraintArgs); + TypeConstraintArgs, /*Canonical=*/IsCanon); if (auto const AT_iter = AutoTypes.find(ID); AT_iter != AutoTypes.end()) return QualType(AT_iter->getSecond(), 0); @@ -6462,9 +6485,9 @@ QualType ASTContext::getAutoTypeInternal( auto CanonicalConceptArgs = ::getCanonicalTemplateArguments( *this, TypeConstraintArgs, AnyNonCanonArgs); if (CanonicalConcept != TypeConstraintConcept || AnyNonCanonArgs) { - Canon = - getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack, - CanonicalConcept, CanonicalConceptArgs, true); + Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack, + CanonicalConcept, CanonicalConceptArgs, + /*IsCanon=*/true); } } } @@ -7011,7 +7034,7 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name, getCanonicalTemplateArgument(subst->getArgumentPack()); return getSubstTemplateTemplateParmPack( canonArgPack, subst->getAssociatedDecl()->getCanonicalDecl(), - subst->getFinal(), subst->getIndex()); + subst->getIndex(), subst->getFinal()); } case TemplateName::DeducedTemplate: { assert(IgnoreDeduced == false); @@ -8200,8 +8223,7 @@ QualType ASTContext::getObjCSuperType() const { 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(); } @@ -13981,13 +14003,16 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, 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(), /*IgnoreDeduced=*/true), - As, X->getCanonicalTypeInternal()); + SpecAs, ConvAs, /*CanonicalConvertedArgs=*/{}, + X->getCanonicalTypeInternal()); } case Type::Decltype: { const auto *DX = cast(X); @@ -14227,11 +14252,14 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, TY->getTemplateName(), /*IgnoreDeduced=*/true); 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 index b4e7360e126f..4916fb44c7ad 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -117,7 +117,7 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT, if (!TST->isTypeAlias()) { bool DesugarArgument = false; SmallVector Args; - for (const TemplateArgument &Arg : TST->template_arguments()) { + for (const TemplateArgument &Arg : TST->getSpecifiedArguments()) { if (Arg.getKind() == TemplateArgument::Type) Args.push_back(desugarForDiagnostic(Context, Arg.getAsType(), DesugarArgument)); @@ -128,7 +128,8 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT, if (DesugarArgument) { ShouldAKA = true; QT = Context.getTemplateSpecializationType( - TST->getTemplateName(), Args, QT); + TST->getTemplateName(), Args, TST->getConvertedArguments(), + /*CanonicalConvertedArguments=*/std::nullopt, QT); } break; } @@ -985,7 +986,7 @@ class TemplateDiff { if (isEnd()) return; // Set to first template argument. If not a parameter pack, done. - TemplateArgument TA = TST->template_arguments()[0]; + TemplateArgument TA = TST->getSpecifiedArguments()[0]; if (TA.getKind() != TemplateArgument::Pack) return; // Start looking into the parameter pack. @@ -1006,7 +1007,7 @@ class TemplateDiff { /// 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->template_arguments().size(); + return Index >= TST->getSpecifiedArguments().size(); } /// &operator++ - Increment the iterator to the next template argument. @@ -1026,11 +1027,11 @@ class TemplateDiff { // 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->template_arguments().size()) + if (++Index == TST->getSpecifiedArguments().size()) break; // If the TemplateArgument is not a parameter pack, done. - TemplateArgument TA = TST->template_arguments()[Index]; + TemplateArgument TA = TST->getSpecifiedArguments()[Index]; if (TA.getKind() != TemplateArgument::Pack) break; @@ -1050,7 +1051,7 @@ class TemplateDiff { assert(TST && "InternalIterator is invalid with a null TST."); assert(!isEnd() && "Index exceeds number of arguments."); if (CurrentTA == EndTA) - return TST->template_arguments()[Index]; + return TST->getSpecifiedArguments()[Index]; else return *CurrentTA; } @@ -1134,9 +1135,11 @@ class TemplateDiff { 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=*/std::nullopt, + Ty.getLocalUnqualifiedType().getCanonicalType()); return Ty->getAs(); } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 8c91cce22f78..cb3974837569 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1657,7 +1657,12 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType( SmallVector ToTemplateArgs; if (Error Err = - ImportTemplateArguments(T->template_arguments(), ToTemplateArgs)) + ImportTemplateArguments(T->getSpecifiedArguments(), ToTemplateArgs)) + return std::move(Err); + + SmallVector ToConvertedArgs; + if (Error Err = + ImportTemplateArguments(T->getConvertedArguments(), ToConvertedArgs)) return std::move(Err); QualType ToCanonType; @@ -1669,9 +1674,9 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType( else return TyOrErr.takeError(); } - return Importer.getToContext().getTemplateSpecializationType(*ToTemplateOrErr, - ToTemplateArgs, - ToCanonType); + return Importer.getToContext().getTemplateSpecializationType( + *ToTemplateOrErr, ToTemplateArgs, ToConvertedArgs, + /*CanonicalConvertedArgs=*/std::nullopt, ToCanonType); } ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { @@ -3634,7 +3639,7 @@ public: std::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. diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 2c7cb581ccfa..4865b7eae6f4 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -1268,8 +1268,11 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(), Spec2->getTemplateName())) return false; - if (!IsStructurallyEquivalent(Context, Spec1->template_arguments(), - Spec2->template_arguments())) + if (!IsStructurallyEquivalent(Context, Spec1->getSpecifiedArguments(), + Spec2->getSpecifiedArguments())) + 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 index e8e2cad72198..fb76239ae434 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -601,7 +601,7 @@ void ClassTemplatePartialSpecializationDecl::Profile( TemplateParameterList *TPL, const ASTContext &Context) { ID.AddInteger(TemplateArgs.size()); for (const TemplateArgument &TemplateArg : TemplateArgs) - TemplateArg.Profile(ID, Context); + TemplateArg.Profile(ID, Context, /*Canonical=*/true); TPL->Profile(ID, Context); } @@ -671,8 +671,12 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() { ASTContext &Context = getASTContext(); TemplateName Name = Context.getQualifiedTemplateName( /*NNS=*/nullptr, /*TemplateKeyword=*/false, TemplateName(this)); + auto TemplateArgs = getTemplateParameters()->getInjectedTemplateArgs(Context); CommonPtr->InjectedClassNameType = Context.getTemplateSpecializationType( - Name, getTemplateParameters()->getInjectedTemplateArgs(Context)); + Name, + /*SpecifiedArgs=*/TemplateArgs, + /*SugaredConvertedArgs=*/TemplateArgs, + /*CanonicalConvertedArgs=*/std::nullopt); return CommonPtr->InjectedClassNameType; } @@ -1363,7 +1367,7 @@ void VarTemplatePartialSpecializationDecl::Profile( TemplateParameterList *TPL, const ASTContext &Context) { ID.AddInteger(TemplateArgs.size()); for (const TemplateArgument &TemplateArg : TemplateArgs) - TemplateArg.Profile(ID, Context); + TemplateArg.Profile(ID, Context, /*Canonical=*/true); TPL->Profile(ID, Context); } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index fdd84d0bf7c5..471ee5eddb4a 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -1320,7 +1320,9 @@ void CXXNameMangler::manglePrefix(QualType type) { // 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->getSpecifiedArguments(); + mangleTemplateArgs(TST->getTemplateName(), Args); addSubstitution(QualType(TST, 0)); } } else if (const auto *DTST = @@ -2560,13 +2562,14 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, 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->template_arguments()); + mangleTemplateArgs(TemplateName(), Args); break; } @@ -4438,8 +4441,10 @@ void CXXNameMangler::mangleType(const InjectedClassNameType *T) { } void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { + auto Args = T->isCanonicalUnqualified() ? T->getConvertedArguments() + : T->getSpecifiedArguments(); if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) { - mangleTemplateName(TD, T->template_arguments()); + mangleTemplateName(TD, Args); } else { if (mangleSubstitution(QualType(T, 0))) return; @@ -4449,7 +4454,7 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { // 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/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index f8446dfbc685..cf603c239b09 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -1189,8 +1189,8 @@ public: void VisitEnumType(const EnumType *T) { VisitTagType(T); } void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { - ID.AddInteger(T->template_arguments().size()); - 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 index 5c151254c36e..b3c0c64e9cb4 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -129,7 +129,7 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx, SmallVector FQArgs; // Cheap to copy and potentially modified by // getFullyQualifedTemplateArgument. - for (TemplateArgument Arg : TST->template_arguments()) { + for (TemplateArgument Arg : TST->getSpecifiedArguments()) { MightHaveChanged |= getFullyQualifiedTemplateArgument( Ctx, Arg, WithGlobalNsPrefix); FQArgs.push_back(Arg); @@ -139,7 +139,8 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx, // allocate new type in the AST. if (MightHaveChanged) { QualType QT = Ctx.getTemplateSpecializationType( - TST->getTemplateName(), FQArgs, + TST->getTemplateName(), FQArgs, TST->getConvertedArguments(), + /*CanonicalConvertedArgs=*/std::nullopt, TST->getCanonicalTypeInternal()); // getTemplateSpecializationType returns a fully qualified // version of the specialization itself, so no need to qualify @@ -171,7 +172,8 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx, if (MightHaveChanged) { TemplateName TN(TSTDecl->getSpecializedTemplate()); QualType QT = Ctx.getTemplateSpecializationType( - TN, FQArgs, + TN, FQArgs, FQArgs, + /*CanonicalConvertedArgs=*/std::nullopt, TSTRecord->getCanonicalTypeInternal()); // getTemplateSpecializationType returns a fully qualified // version of the specialization itself, so no need to qualify diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp index 0be0a83b7010..891ba2aae71d 100644 --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -378,21 +378,28 @@ QualType TemplateArgument::getNonTypeTemplateArgumentType() const { } void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, - const ASTContext &Context) const { + const ASTContext &Context, + bool Canonical) const { ID.AddInteger(getKind()); switch (getKind()) { case Null: break; case Type: + assert(!Canonical || getAsType().isCanonical()); getAsType().Profile(ID); break; case NullPtr: + assert(!Canonical || getNullPtrType().isCanonical()); getNullPtrType().Profile(ID); break; case Declaration: + if (Canonical) { + assert(getParamTypeForDecl().isCanonical()); + assert(getAsDecl()->isCanonicalDecl()); + } getParamTypeForDecl().Profile(ID); ID.AddPointer(getAsDecl()); break; @@ -401,27 +408,33 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, ID.AddInteger(TemplateArg.NumExpansions.toInternalRepresentation()); [[fallthrough]]; case Template: + if (Canonical) { + TemplateName Name = TemplateName::getFromVoidPointer(TemplateArg.Name); + assert(Context.getCanonicalTemplateName(Name) == Name); + } ID.AddPointer(TemplateArg.Name); break; case Integral: + assert(!Canonical || getIntegralType().isCanonical()); getIntegralType().Profile(ID); getAsIntegral().Profile(ID); break; case StructuralValue: + assert(!Canonical || getStructuralValueType().isCanonical()); getStructuralValueType().Profile(ID); getAsStructuralValue().Profile(ID); break; case Expression: - getAsExpr()->Profile(ID, Context, true); + getAsExpr()->Profile(ID, Context, Canonical); break; case Pack: ID.AddInteger(Args.NumArgs); for (unsigned I = 0; I != Args.NumArgs; ++I) - Args.Args[I].Profile(ID, Context); + Args.Args[I].Profile(ID, Context, Canonical); } } diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp index 4404552f84fb..5d7ecb447404 100644 --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/lib/AST/TemplateName.cpp @@ -54,7 +54,7 @@ void DeducedTemplateStorage::Profile(llvm::FoldingSetNodeID &ID, ID.AddInteger(DefArgs.StartPos); ID.AddInteger(DefArgs.Args.size()); for (const TemplateArgument &Arg : DefArgs.Args) - Arg.Profile(ID, Context); + Arg.Profile(ID, Context, /*Canonical=*/false); } TemplateArgument @@ -118,7 +118,7 @@ void SubstTemplateTemplateParmPackStorage::Profile( llvm::FoldingSetNodeID &ID, ASTContext &Context, const TemplateArgument &ArgPack, Decl *AssociatedDecl, unsigned Index, bool Final) { - ArgPack.Profile(ID, Context); + ArgPack.Profile(ID, Context, /*Canonical=*/false); ID.AddPointer(AssociatedDecl); ID.AddInteger(Index); ID.AddBoolean(Final); diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 879ad1a7eaa8..7d5505291df4 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -1937,6 +1937,17 @@ TagDecl *Type::getAsTagDecl() const { 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()) { @@ -3289,11 +3300,11 @@ DependentTemplateSpecializationType::DependentTemplateSpecializationType( void DependentTemplateSpecializationType::Profile( llvm::FoldingSetNodeID &ID, const ASTContext &Context, ElaboratedTypeKeyword Keyword, const DependentTemplateStorage &Name, - ArrayRef Args) { + ArrayRef Args, bool IsCanonical) { ID.AddInteger(llvm::to_underlying(Keyword)); Name.Profile(ID); for (const TemplateArgument &Arg : Args) - Arg.Profile(ID, Context); + Arg.Profile(ID, Context, IsCanonical); } bool Type::isElaboratedTypeSpecifier() const { @@ -4371,17 +4382,20 @@ bool TemplateSpecializationType::anyInstantiationDependentTemplateArguments( } 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"); @@ -4393,51 +4407,70 @@ TemplateSpecializationType::TemplateSpecializationType( T.getKind() == TemplateName::DeducedTemplate) && "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 + 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 {getSpecifiedArguments().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, getSpecifiedArguments(), getConvertedArguments(), + isSugared() ? desugar() : QualType(), Ctx, isCanonicalUnqualified()); } -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, bool Canonical) { T.Profile(ID); - for (const TemplateArgument &Arg : Args) - Arg.Profile(ID, Context); + + assert(!Canonical || SpecifiedArgs.size() == 0); + ID.AddInteger(SpecifiedArgs.size()); + for (const TemplateArgument &Arg : SpecifiedArgs) + Arg.Profile(ID, Context, /*Canonical=*/false); + + ID.AddInteger(ConvertedArgs.size()); + for (const TemplateArgument &Arg : ConvertedArgs) + Arg.Profile(ID, Context, Canonical); + + Underlying.Profile(ID); } QualType @@ -5247,20 +5280,21 @@ AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, } void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, - QualType Deduced, AutoTypeKeyword Keyword, - bool IsDependent, ConceptDecl *CD, - ArrayRef Arguments) { + QualType Deduced, AutoTypeKeyword Keyword, + bool IsDependent, ConceptDecl *CD, + ArrayRef Arguments, bool Canonical) { ID.AddPointer(Deduced.getAsOpaquePtr()); ID.AddInteger((unsigned)Keyword); ID.AddBoolean(IsDependent); ID.AddPointer(CD); for (const TemplateArgument &Arg : Arguments) - Arg.Profile(ID, Context); + Arg.Profile(ID, Context, Canonical); } void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(), - getTypeConstraintConcept(), getTypeConstraintArguments()); + getTypeConstraintConcept(), getTypeConstraintArguments(), + isCanonicalUnqualified()); } FunctionEffect::Kind FunctionEffect::oppositeKind() const { diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 4ec252e3f89b..d817b1dc6225 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1669,7 +1669,10 @@ void TypePrinter::printTemplateId(const TemplateSpecializationType *T, 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); } @@ -2297,7 +2300,7 @@ static bool isSubstitutedType(ASTContext &Ctx, QualType T, QualType Pattern, ArrayRef TemplateArgs; if (auto *TTST = T->getAs()) { Template = TTST->getTemplateName(); - TemplateArgs = TTST->template_arguments(); + TemplateArgs = TTST->getConvertedArguments(); } else if (auto *CTSD = dyn_cast_or_null( T->getAsCXXRecordDecl())) { Template = TemplateName(CTSD->getSpecializedTemplate()); @@ -2309,11 +2312,12 @@ static bool isSubstitutedType(ASTContext &Ctx, QualType T, QualType Pattern, 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/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index d659243d38d5..df6c26fe832b 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1391,7 +1391,7 @@ GetTemplateArgs(const TemplateDecl *TD, const TemplateSpecializationType *Ty) { // doesn't know the value of any defaulted args, so collect those now // too. SmallVector SpecArgs; - ArrayRef SubstArgs = Ty->template_arguments(); + ArrayRef SubstArgs = Ty->getSpecifiedArguments(); for (const NamedDecl *Param : TD->getTemplateParameters()->asArray()) { // If Param is a parameter pack, pack the remaining arguments. if (Param->isParameterPack()) { @@ -1483,7 +1483,7 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty, return AliasTy; } - printTemplateArgumentList(OS, Ty->template_arguments(), PP, + printTemplateArgumentList(OS, Ty->getSpecifiedArguments(), PP, TD->getTemplateParameters()); return DBuilder.createTypedef(Src, OS.str(), getOrCreateFile(Loc), getLineNumber(Loc), diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp index d7eebcbc3c2f..fcf8f325454c 100644 --- a/clang/lib/ExtractAPI/DeclarationFragments.cpp +++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp @@ -413,7 +413,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType( .append(Str, DeclarationFragments::FragmentKind::TypeIdentifier, USR) .append("<", DeclarationFragments::FragmentKind::Text) .append(getFragmentsForTemplateArguments( - TemplSpecTy->template_arguments(), Context, std::nullopt)) + TemplSpecTy->getSpecifiedArguments(), Context, std::nullopt)) .append(">", DeclarationFragments::FragmentKind::Text); } diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp index 0a5a1bcc7486..0465f25211d2 100644 --- a/clang/lib/Index/USRGeneration.cpp +++ b/clang/lib/Index/USRGeneration.cpp @@ -935,8 +935,8 @@ void USRGenerator::VisitType(QualType T) { = 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/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index f6ee000a58f4..912bbc423bed 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -193,9 +193,9 @@ QualType HeuristicResolverImpl::getPointeeType(QualType T) { auto *TST = T->getAs(); if (!TST) return QualType(); - if (TST->template_arguments().size() == 0) + if (TST->getSpecifiedArguments().size() == 0) return QualType(); - const TemplateArgument &FirstArg = TST->template_arguments()[0]; + const TemplateArgument &FirstArg = TST->getSpecifiedArguments()[0]; if (FirstArg.getKind() != TemplateArgument::Type) return QualType(); return FirstArg.getAsType(); diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index ea7936b0e5b8..e010fd61a34c 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -98,7 +98,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, if (L != TemplateParamLists.end()) { void *Pos = nullptr; PartialSpec = ClassTemplate->findPartialSpecialization( - SpecType->template_arguments(), *L, Pos); + SpecType->getConvertedArguments(), *L, Pos); } } else { PartialSpec = ClassTemplate->findPartialSpecialization(ContextType); diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 44a49a6e3148..b6e796efb83a 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -4911,9 +4911,10 @@ static const FunctionProtoType *TryDeconstructFunctionLike(QualType T) { // 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->template_arguments().size() != 1) + if (Specialization->getSpecifiedArguments().size() != 1) return nullptr; - const TemplateArgument &Argument = Specialization->template_arguments()[0]; + const TemplateArgument &Argument = + Specialization->getSpecifiedArguments()[0]; if (Argument.getKind() != TemplateArgument::Type) return nullptr; return Argument.getAsType()->getAs(); diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 011a6d072d35..6971fbbc6367 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -183,7 +183,8 @@ DiagRecursiveConstraintEval(Sema &S, llvm::FoldingSetNodeID &ID, E->Profile(ID, S.Context, /*Canonical=*/true); for (const auto &List : MLTAL) for (const auto &TemplateArg : List.Args) - TemplateArg.Profile(ID, S.Context); + S.Context.getCanonicalTemplateArgument(TemplateArg) + .Profile(ID, S.Context, /*Canonical=*/true); // Note that we have to do this with our own collection, because there are // times where a constraint-expression check can cause us to need to evaluate @@ -1924,7 +1925,7 @@ auto SubsumptionChecker::find(AtomicConstraint *Ori) -> Literal { for (const TemplateArgumentLoc &TAL : *Mapping) { SemaRef.getASTContext() .getCanonicalTemplateArgument(TAL.getArgument()) - .Profile(ID, SemaRef.getASTContext()); + .Profile(ID, SemaRef.getASTContext(), /*Canonical=*/true); } } auto It = Elems.find(ID); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 07379c687673..346f1e086884 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -12081,7 +12081,7 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) { if (TST) { Template = dyn_cast_or_null( TST->getTemplateName().getAsTemplateDecl()); - Arguments = TST->template_arguments().begin(); + Arguments = TST->getConvertedArguments().begin(); } } if (!Template) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e7f418ae6802..d70e42d86ef1 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -21086,8 +21086,10 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { Diag(Temp->getLocation(), diag::note_referenced_type_template) << IsTypeAliasTemplateDecl; - QualType TST = - Context.getTemplateSpecializationType(TN, ULE->template_arguments()); + QualType TST = Context.getTemplateSpecializationType( + TN, ULE->template_arguments(), + /*SugaredConvertedArgs=*/ArrayRef{}, + /*CanonicalConvertedArgs=*/{}); QualType ET = Context.getElaboratedType(ElaboratedTypeKeyword::None, NNS, TST); return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {}, diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 153f44f8ec67..6a0142d7c8f5 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3227,11 +3227,11 @@ static QualType builtinCommonTypeImpl(Sema &S, TemplateName BaseTemplate, } } -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()) { @@ -3239,7 +3239,7 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, // 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)) { @@ -3248,10 +3248,11 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, 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 @@ -3279,21 +3280,26 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, // 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 " @@ -3307,19 +3313,24 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, // 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()); } case BTK__builtin_common_type: { - assert(Converted.size() == 4); - if (llvm::any_of(Converted, [](auto &C) { return C.isDependent(); })) - return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD), - Converted); + assert(CanonicalConverted.size() == 4); + if (llvm::any_of(CanonicalConverted, + [](auto &C) { return C.isDependent(); })) + return Context.getTemplateSpecializationType( + TemplateName(BTD), TemplateArgs.arguments(), SugaredConverted, + CanonicalConverted); - TemplateName BaseTemplate = Converted[0].getAsTemplate(); - TemplateName HasTypeMember = Converted[1].getAsTemplate(); - QualType HasNoTypeMember = Converted[2].getAsType(); - ArrayRef Ts = Converted[3].getPackAsArray(); + TemplateName BaseTemplate = SugaredConverted[0].getAsTemplate(); + TemplateName HasTypeMember = SugaredConverted[1].getAsTemplate(); + QualType HasNoTypeMember = SugaredConverted[2].getAsType(); + ArrayRef Ts = SugaredConverted[3].getPackAsArray(); + QualType Result = HasNoTypeMember; if (auto CT = builtinCommonTypeImpl(SemaRef, BaseTemplate, TemplateLoc, Ts); !CT.isNull()) { TemplateArgumentListInfo TAs; @@ -3327,9 +3338,11 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, TemplateArgument(CT), SemaRef.Context.getTrivialTypeSourceInfo( CT, TemplateArgs[1].getLocation()))); - return SemaRef.CheckTemplateIdType(HasTypeMember, TemplateLoc, TAs); + Result = SemaRef.CheckTemplateIdType(HasTypeMember, TemplateLoc, TAs); } - return HasNoTypeMember; + return SemaRef.Context.getTemplateSpecializationType( + Name, TemplateArgs.arguments(), SugaredConverted, CanonicalConverted, + Result); } } llvm_unreachable("unexpected BuiltinTemplateDecl!"); @@ -3492,20 +3505,19 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, resolveAssumedTemplateNameAsType(/*Scope=*/nullptr, Name, TemplateLoc)) return QualType(); - auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs(); - - 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; + DefaultArguments DefaultArgs; + if (const SubstTemplateTemplateParmPackStorage *S = + Name.getAsSubstTemplateTemplateParmPack()) { + Template = S->getParameterPack(); + } else { + std::tie(Template, DefaultArgs) = Name.getTemplateDeclAndDefaultArgs(); + 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 @@ -3519,8 +3531,11 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, 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(); @@ -3589,8 +3604,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, return QualType(); } } else if (auto *BTD = dyn_cast(Template)) { - CanonType = checkBuiltinTemplateIdType(*this, BTD, CTAI.SugaredConverted, - TemplateLoc, TemplateArgs); + return checkBuiltinTemplateIdType(*this, Name, BTD, CTAI.SugaredConverted, + CTAI.CanonicalConverted, TemplateLoc, + TemplateArgs); } else if (Name.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( TemplateArgs, CTAI.CanonicalConverted)) { @@ -3601,8 +3617,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // A have identical types when A is declared as: // // template struct A; - CanonType = Context.getCanonicalTemplateSpecializationType( - Name, CTAI.CanonicalConverted); + CanonType = Context.getTemplateSpecializationType( + Context.getCanonicalTemplateName(Name), ArrayRef(), + std::nullopt, CTAI.CanonicalConverted); // This might work out to be a current instantiation, in which // case the canonical type needs to be the InjectedClassNameType. @@ -3688,8 +3705,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // Build the fully-sugared type for this class template // specialization, which refers back to the class template // specialization we created or found. - return Context.getTemplateSpecializationType(Name, TemplateArgs.arguments(), - CanonType); + return Context.getTemplateSpecializationType( + Name, TemplateArgs.arguments(), CTAI.SugaredConverted, + CTAI.CanonicalConverted, CanonType); } void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName, @@ -8473,17 +8491,35 @@ DeclResult Sema::ActOnClassTemplateSpecialization( isPartialSpecialization)) return true; - // The canonical type QualType CanonType; - 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, - CTAI.CanonicalConverted); + if (!isPartialSpecialization) { + // Create a new class template specialization declaration node for + // this explicit specialization or friend declaration. + Specialization = ClassTemplateSpecializationDecl::Create( + Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc, + ClassTemplate, CTAI.CanonicalConverted, CTAI.StrictPackMatch, PrevDecl); + Specialization->setTemplateArgsAsWritten(TemplateArgs); + SetNestedNameSpecifier(*this, Specialization, SS); + if (TemplateParameterLists.size() > 0) { + Specialization->setTemplateParameterListsInfo(Context, + TemplateParameterLists); + } - if (Context.hasSameType(CanonType, - ClassTemplate->getInjectedClassNameSpecialization()) && + if (!PrevDecl) + ClassTemplate->AddSpecialization(Specialization, InsertPos); + + if (!CurContext->isDependentContext()) + CanonType = Context.getTypeDeclType(Specialization); + } + + TypeSourceInfo *WrittenTy = Context.getTemplateSpecializationTypeInfo( + Name, TemplateNameLoc, TemplateArgs, CTAI.SugaredConverted, + CTAI.CanonicalConverted, CanonType); + + if (isPartialSpecialization) { + if (Context.hasSameType( + WrittenTy->getType(), + ClassTemplate->getInjectedClassNameSpecialization()) && (!Context.getLangOpts().CPlusPlus20 || !TemplateParams->hasAssociatedConstraints())) { // C++ [temp.class.spec]p9b3: @@ -8510,7 +8546,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization( ClassTemplatePartialSpecializationDecl *Partial = ClassTemplatePartialSpecializationDecl::Create( Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams, - ClassTemplate, CTAI.CanonicalConverted, CanonType, PrevPartial); + ClassTemplate, CTAI.CanonicalConverted, WrittenTy->getType(), + PrevPartial); Partial->setTemplateArgsAsWritten(TemplateArgs); SetNestedNameSpecifier(*this, Partial, SS); if (TemplateParameterLists.size() > 1 && SS.isSet()) { @@ -8528,29 +8565,6 @@ DeclResult Sema::ActOnClassTemplateSpecialization( PrevPartial->setMemberSpecialization(); CheckTemplatePartialSpecialization(Partial); - } else { - // Create a new class template specialization declaration node for - // this explicit specialization or friend declaration. - Specialization = ClassTemplateSpecializationDecl::Create( - Context, Kind, DC, KWLoc, TemplateNameLoc, ClassTemplate, - CTAI.CanonicalConverted, CTAI.StrictPackMatch, PrevDecl); - Specialization->setTemplateArgsAsWritten(TemplateArgs); - SetNestedNameSpecifier(*this, Specialization, SS); - if (TemplateParameterLists.size() > 0) { - Specialization->setTemplateParameterListsInfo(Context, - TemplateParameterLists); - } - - if (!PrevDecl) - ClassTemplate->AddSpecialization(Specialization, InsertPos); - - if (CurContext->isDependentContext()) { - TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); - CanonType = Context.getTemplateSpecializationType( - CanonTemplate, CTAI.CanonicalConverted); - } else { - CanonType = Context.getTypeDeclType(Specialization); - } } // C++ [temp.expl.spec]p6: @@ -8640,8 +8654,6 @@ DeclResult Sema::ActOnClassTemplateSpecialization( // 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); FriendDecl *Friend = FriendDecl::Create(Context, CurContext, TemplateNameLoc, WrittenTy, diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index ab6e18aee720..bec98dc2bb73 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -615,12 +615,15 @@ static TemplateDeductionResult DeduceTemplateArguments( /// but it may still fail, later, for other reasons. static const TemplateSpecializationType *getLastTemplateSpecType(QualType QT) { + const TemplateSpecializationType *LastTST = nullptr; for (const Type *T = QT.getTypePtr(); /**/; /**/) { const TemplateSpecializationType *TST = T->getAs(); - assert(TST && "Expected a TemplateSpecializationType"); + if (!TST) + return LastTST; if (!TST->isSugared()) return TST; + LastTST = TST; T = TST->desugar().getTypePtr(); } } @@ -643,87 +646,61 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, if (const auto *TD = TNP.getAsTemplateDecl(); TD && TD->isTypeAlias()) return TemplateDeductionResult::Success; - // FIXME: To preserve sugar, the TST needs to carry sugared resolved - // arguments. - ArrayRef PResolved = - TP->getCanonicalTypeInternal() - ->castAs() - ->template_arguments(); + ArrayRef PResolved = TP->getConvertedArguments(); QualType UA = A; - std::optional NNS; // Treat an injected-class-name as its underlying template-id. - if (const auto *Elaborated = A->getAs()) { - NNS = Elaborated->getQualifier(); - } else if (const auto *Injected = A->getAs()) { + if (const auto *Injected = A->getAs()) UA = Injected->getInjectedSpecializationType(); - NNS = nullptr; + + const TemplateSpecializationType *TA = ::getLastTemplateSpecType(UA); + TemplateName TNA; + ArrayRef AResolved; + if (TA) { + TNA = TA->getTemplateName(); + AResolved = TA->getConvertedArguments(); } - - // Check whether the template argument is a dependent template-id. - if (isa(UA.getCanonicalType())) { - const TemplateSpecializationType *SA = ::getLastTemplateSpecType(UA); - TemplateName TNA = SA->getTemplateName(); - + if (auto *SA = dyn_cast_or_null( + A->getAsCXXRecordDecl())) { + if (TA) { + // This could be a type alias to a class template specialization type + // which was desugared. If so, ignore it. + if (TNA.getAsTemplateDecl()->isTypeAlias()) + TA = nullptr; + else + assert(isSameDeclaration(TNA.getAsTemplateDecl(), + SA->getSpecializedTemplate())); + } + if (!TA) { + // If the argument type is a class template specialization, we + // perform template argument deduction using its template + // arguments. + TNA = TemplateName(SA->getSpecializedTemplate()); + AResolved = SA->getTemplateArgs().asArray(); + } + } else if (isa(UA.getCanonicalType())) { // If the argument is an alias template, there is nothing to deduce. if (const auto *TD = TNA.getAsTemplateDecl(); TD && TD->isTypeAlias()) return TemplateDeductionResult::Success; - - // FIXME: To preserve sugar, the TST needs to carry sugared resolved - // arguments. - ArrayRef AResolved = - SA->getCanonicalTypeInternal() - ->castAs() - ->template_arguments(); - - // Perform template argument deduction for the template name. - if (auto Result = DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, - /*DefaultArguments=*/AResolved, - PartialOrdering, Deduced, - HasDeducedAnyParam); - Result != TemplateDeductionResult::Success) - return Result; - - // Perform template argument deduction on each template - // argument. Ignore any missing/extra arguments, since they could be - // filled in by default arguments. - return DeduceTemplateArguments( - S, TemplateParams, PResolved, AResolved, Info, Deduced, - /*NumberOfArgumentsMustMatch=*/false, PartialOrdering, - PackFold::ParameterToArgument, HasDeducedAnyParam); - } - - // If the argument type is a class template specialization, we - // perform template argument deduction using its template - // arguments. - const auto *RA = UA->getAs(); - const auto *SA = - RA ? dyn_cast(RA->getDecl()) : nullptr; - if (!SA) { + } else { Info.FirstArg = TemplateArgument(P); Info.SecondArg = TemplateArgument(A); return TemplateDeductionResult::NonDeducedMismatch; } - TemplateName TNA = TemplateName(SA->getSpecializedTemplate()); - if (NNS) - TNA = S.Context.getQualifiedTemplateName( - *NNS, false, TemplateName(SA->getSpecializedTemplate())); - // Perform template argument deduction for the template name. - if (auto Result = DeduceTemplateArguments( - S, TemplateParams, TNP, TNA, Info, - /*DefaultArguments=*/SA->getTemplateArgs().asArray(), PartialOrdering, - Deduced, HasDeducedAnyParam); + if (auto Result = + DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, + /*DefaultArguments=*/AResolved, + PartialOrdering, Deduced, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; // Perform template argument deduction for the template arguments. - return DeduceTemplateArguments(S, TemplateParams, PResolved, - SA->getTemplateArgs().asArray(), Info, Deduced, - /*NumberOfArgumentsMustMatch=*/true, - PartialOrdering, PackFold::ParameterToArgument, - HasDeducedAnyParam); + return DeduceTemplateArguments( + S, TemplateParams, PResolved, AResolved, Info, Deduced, + /*NumberOfArgumentsMustMatch=*/true, PartialOrdering, + PackFold::ParameterToArgument, HasDeducedAnyParam); } static bool IsPossiblyOpaquelyQualifiedTypeInternal(const Type *T) { @@ -5894,8 +5871,8 @@ static MoreSpecializedTrailingPackTieBreakerResult getMoreSpecializedTrailingPackTieBreaker( const TemplateSpecializationType *TST1, const TemplateSpecializationType *TST2) { - ArrayRef As1 = TST1->template_arguments(), - As2 = TST2->template_arguments(); + ArrayRef As1 = TST1->getConvertedArguments(), + As2 = TST2->getConvertedArguments(); const TemplateArgument &TA1 = As1.back(), &TA2 = As2.back(); bool IsPack = TA1.getKind() == TemplateArgument::Pack; assert(IsPack == (TA2.getKind() == TemplateArgument::Pack)); @@ -6302,8 +6279,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, TemplateDeductionResult Result; S.runWithSufficientStackSpace(Info.getLocation(), [&] { Result = ::FinishTemplateArgumentDeduction( - S, P2, /*IsPartialOrdering=*/true, TST1->template_arguments(), Deduced, - Info); + S, P2, /*IsPartialOrdering=*/true, TST1->getConvertedArguments(), + Deduced, Info); }); if (Result != TemplateDeductionResult::Success) @@ -6347,8 +6324,10 @@ struct TemplateArgumentListAreEqual { // because canonicalization can't do the right thing for dependent // expressions. llvm::FoldingSetNodeID IDA, IDB; - Args1[I].Profile(IDA, Ctx); - Args2[I].Profile(IDB, Ctx); + Ctx.getCanonicalTemplateArgument(Args1[I]).Profile(IDA, Ctx, + /*Canonical=*/true); + Ctx.getCanonicalTemplateArgument(Args2[I]).Profile(IDB, Ctx, + /*Canonical=*/true); if (IDA != IDB) return false; } @@ -6366,10 +6345,10 @@ struct TemplateArgumentListAreEqual { // because canonicalization can't do the right thing for dependent // expressions. llvm::FoldingSetNodeID IDA, IDB; - Args1[I].Profile(IDA, Ctx); - // Unlike the specialization arguments, the injected arguments are not - // always canonical. - Ctx.getCanonicalTemplateArgument(Args2[I]).Profile(IDB, Ctx); + Ctx.getCanonicalTemplateArgument(Args1[I]).Profile(IDA, Ctx, + /*Canonical=*/true); + Ctx.getCanonicalTemplateArgument(Args2[I]).Profile(IDB, Ctx, + /*Canonical=*/true); if (IDA != IDB) return false; } @@ -6512,9 +6491,11 @@ Sema::getMoreSpecializedPartialSpecialization( " the same template."); TemplateName Name(PS1->getSpecializedTemplate()); QualType PT1 = Context.getTemplateSpecializationType( - Name, PS1->getTemplateArgs().asArray()); + Name, ArrayRef(), std::nullopt, + PS1->getTemplateArgs().asArray()); QualType PT2 = Context.getTemplateSpecializationType( - Name, PS2->getTemplateArgs().asArray()); + Name, ArrayRef(), std::nullopt, + PS2->getTemplateArgs().asArray()); TemplateDeductionInfo Info(Loc); return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info); @@ -6525,9 +6506,11 @@ bool Sema::isMoreSpecializedThanPrimary( VarTemplateDecl *Primary = Spec->getSpecializedTemplate(); TemplateName Name(Primary); QualType PrimaryT = Context.getTemplateSpecializationType( - Name, Primary->getInjectedTemplateArgs(Context)); + Name, ArrayRef(), + Primary->getInjectedTemplateArgs(Context), std::nullopt); QualType PartialT = Context.getTemplateSpecializationType( - Name, Spec->getTemplateArgs().asArray()); + Name, ArrayRef(), std::nullopt, + Spec->getTemplateArgs().asArray()); VarTemplatePartialSpecializationDecl *MaybeSpec = getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info); @@ -6989,11 +6972,10 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, // 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/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index b4863cefc3fb..e8c7fb931987 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -959,7 +959,7 @@ getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) { // template // using AliasFoo1 = Foo; // a class/type alias template specialization Template = TST->getTemplateName().getAsTemplateDecl(); - AliasRhsTemplateArgs = TST->template_arguments(); + AliasRhsTemplateArgs = TST->getSpecifiedArguments(); } else if (const auto *RT = RhsType->getAs()) { // Cases where template arguments in the RHS of the alias are not // dependent. e.g. @@ -1045,7 +1045,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, // performing deduction for rest of arguments to align with the C++ // standard. SemaRef.DeduceTemplateArguments( - F->getTemplateParameters(), FReturnType->template_arguments(), + F->getTemplateParameters(), FReturnType->getSpecifiedArguments(), AliasRhsTemplateArgs, TDeduceInfo, DeduceResults, /*NumberOfArgumentsMustMatch=*/false); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index dd493a083d86..68c801098f20 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -345,7 +345,7 @@ Response HandleFunctionTemplateDecl(Sema &SemaRef, while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) { if (NNS->isInstantiationDependent()) { if (const auto *TSTy = Ty->getAs()) { - ArrayRef Arguments = TSTy->template_arguments(); + ArrayRef Arguments = TSTy->getConvertedArguments(); // Prefer template arguments from the injected-class-type if possible. // For example, // ```cpp diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 2d6f2ca67af8..4d8d43fa3723 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4785,17 +4785,18 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( ClassTemplate->findPartialSpecialization(CTAI.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), CTAI.CanonicalConverted); + // Build the type that describes the converted template arguments of the class + // template partial specialization. + TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo( + TemplateName(ClassTemplate), TemplArgInfo->getLAngleLoc(), + InstTemplateArgs, CTAI.SugaredConverted, CTAI.CanonicalConverted); // Create the class template partial specialization declaration. ClassTemplatePartialSpecializationDecl *InstPartialSpec = ClassTemplatePartialSpecializationDecl::Create( SemaRef.Context, PartialSpec->getTagKind(), Owner, PartialSpec->getBeginLoc(), PartialSpec->getLocation(), InstParams, - ClassTemplate, CTAI.CanonicalConverted, CanonType, + ClassTemplate, CTAI.CanonicalConverted, WrittenTy->getType(), /*PrevDecl=*/nullptr); InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 4e7726e25811..e00d394f692b 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1889,7 +1889,7 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, // A declarator that specifies the type "reference to cv void" // is ill-formed. if (T->isVoidType()) { - Diag(Loc, diag::err_reference_to_void); + Diag(Loc, diag::err_reference_to_void) << T; return QualType(); } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 237c5a9ef501..96cef87fcf34 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -7358,12 +7358,24 @@ QualType TreeTransform::TransformTemplateSpecializationType( 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(); + } // This needs to be rebuilt if either the arguments changed, or if the // original template changed. If the template changed, and even if the diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 38697eb83513..969b1f7416dd 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -7305,9 +7305,9 @@ void TypeLocReader::VisitTemplateSpecializationTypeLoc( TL.setLAngleLoc(readSourceLocation()); TL.setRAngleLoc(readSourceLocation()); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) - TL.setArgLocInfo(i, - Reader.readTemplateArgumentLocInfo( - TL.getTypePtr()->template_arguments()[i].getKind())); + TL.setArgLocInfo( + i, Reader.readTemplateArgumentLocInfo( + TL.getTypePtr()->getSpecifiedArguments()[i].getKind())); } void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) { diff --git a/clang/lib/Serialization/TemplateArgumentHasher.cpp b/clang/lib/Serialization/TemplateArgumentHasher.cpp index 3c7177b83ba5..04c8652bfa04 100644 --- a/clang/lib/Serialization/TemplateArgumentHasher.cpp +++ b/clang/lib/Serialization/TemplateArgumentHasher.cpp @@ -361,8 +361,8 @@ public: void VisitEnumType(const EnumType *T) { VisitTagType(T); } void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { - Hash.AddInteger(T->template_arguments().size()); - for (const auto &TA : T->template_arguments()) { + Hash.AddInteger(T->getSpecifiedArguments().size()); + for (const auto &TA : T->getSpecifiedArguments()) { Hash.AddTemplateArgument(TA); } Hash.AddTemplateName(T->getTemplateName()); diff --git a/clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp index a026735bc107..9a1bf303867a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp @@ -95,7 +95,7 @@ getTemplateArgsFromVariant(const Type *VariantType) { if (!TempSpecType) return {}; - return TempSpecType->template_arguments(); + return TempSpecType->getSpecifiedArguments(); } static std::optional diff --git a/clang/test/AST/ast-dump-ctad-alias.cpp b/clang/test/AST/ast-dump-ctad-alias.cpp index f39a4cee518c..4b2a8210cc21 100644 --- a/clang/test/AST/ast-dump-ctad-alias.cpp +++ b/clang/test/AST/ast-dump-ctad-alias.cpp @@ -191,12 +191,8 @@ void foo() { // CHECK-NEXT: | | | | `-TemplateArgument pack '>' // CHECK-NEXT: | | | | `-TemplateArgument type 'Packs' // CHECK-NEXT: | | | | `-TemplateSpecializationType {{.*}} 'Packs' dependent -// CHECK-NEXT: | | | | |-name: 'GH124715::Packs' -// CHECK-NEXT: | | | | | `-ClassTemplateDecl {{.*}} Packs -// CHECK-NEXT: | | | | `-TemplateArgument pack '' -// CHECK-NEXT: | | | | `-TemplateArgument type 'type-parameter-0-1...' -// CHECK-NEXT: | | | | `-PackExpansionType {{.*}} 'type-parameter-0-1...' dependent -// CHECK-NEXT: | | | | `-TemplateTypeParmType {{.*}} 'type-parameter-0-1' dependent contains_unexpanded_pack depth 0 index 1 pack +// CHECK-NEXT: | | | | `-name: 'GH124715::Packs' +// CHECK-NEXT: | | | | `-ClassTemplateDecl {{.*}} Packs // CHECK-NEXT: | | | |-TemplateArgument {{.*}} type 'U':'type-parameter-0-2' // CHECK-NEXT: | | | | `-TemplateTypeParmType {{.*}} 'U' dependent depth 0 index 2 // CHECK-NEXT: | | | | `-TemplateTypeParm {{.*}} 'U' diff --git a/clang/test/CXX/class.derived/class.derived.general/p2.cpp b/clang/test/CXX/class.derived/class.derived.general/p2.cpp index 888d9cd7a939..1423eeabebf5 100644 --- a/clang/test/CXX/class.derived/class.derived.general/p2.cpp +++ b/clang/test/CXX/class.derived/class.derived.general/p2.cpp @@ -63,7 +63,7 @@ namespace CurrentInstantiation { struct A0::B5::C3 : A0, B5 { }; template - struct A0 { // expected-note 2{{definition of 'A0' is not complete until the closing '}'}} + struct A0 { // expected-note 2{{definition of 'A0' is not complete until the closing '}'}} struct B0 : A0 { }; // expected-error {{base class has incomplete type}} template diff --git a/clang/test/CXX/drs/cwg15xx.cpp b/clang/test/CXX/drs/cwg15xx.cpp index 30ec63999ca2..b4788024bb75 100644 --- a/clang/test/CXX/drs/cwg15xx.cpp +++ b/clang/test/CXX/drs/cwg15xx.cpp @@ -38,7 +38,7 @@ namespace cwg1512 { // cwg1512: 4 template void composite_pointer_type_is_ord() { composite_pointer_type_is_base(); - typedef __typeof(val() < val()) cmp; // #cwg1512-lt + typedef __typeof(val() < val()) cmp; // #cwg1512-lt // since-cxx17-warning@#cwg1512-lt {{ordered comparison of function pointers ('int (*)() noexcept' and 'int (*)()')}} // since-cxx17-note@#cwg1512-noexcept-1st {{in instantiation of function template specialization 'cwg1512::composite_pointer_type_is_ord' requested here}} // since-cxx17-warning@#cwg1512-lt {{ordered comparison of function pointers ('int (*)()' and 'int (*)() noexcept')}} @@ -140,13 +140,13 @@ namespace cwg1512 { // cwg1512: 4 void(Wrap() == Wrap()); void(Wrap() != Wrap()); void(Wrap() < Wrap()); - // since-cxx11-error@-1 {{invalid operands to binary expression ('Wrap' (aka 'Wrap') and 'Wrap' (aka 'Wrap'))}} + // since-cxx11-error@-1 {{invalid operands to binary expression ('Wrap' (aka 'Wrap') and 'Wrap')}} void(Wrap() > Wrap()); - // since-cxx11-error@-1 {{invalid operands to binary expression ('Wrap' (aka 'Wrap') and 'Wrap' (aka 'Wrap'))}} + // since-cxx11-error@-1 {{invalid operands to binary expression ('Wrap' (aka 'Wrap') and 'Wrap')}} void(Wrap() <= Wrap()); - // since-cxx11-error@-1 {{invalid operands to binary expression ('Wrap' (aka 'Wrap') and 'Wrap' (aka 'Wrap'))}} + // since-cxx11-error@-1 {{invalid operands to binary expression ('Wrap' (aka 'Wrap') and 'Wrap')}} void(Wrap() >= Wrap()); - // since-cxx11-error@-1 {{invalid operands to binary expression ('Wrap' (aka 'Wrap') and 'Wrap' (aka 'Wrap'))}} + // since-cxx11-error@-1 {{invalid operands to binary expression ('Wrap' (aka 'Wrap') and 'Wrap')}} // Under cwg1213, this is ill-formed: we select the builtin operator<(int*, int*) // but then only convert as far as 'nullptr_t', which we then can't convert to 'int*'. @@ -332,7 +332,7 @@ namespace cwg1550 { // cwg1550: 3.4 namespace cwg1558 { // cwg1558: 12 #if __cplusplus >= 201103L template using first_of = T; - template first_of f(int); // #cwg1558-f + template first_of f(int); // #cwg1558-f template void f(...) = delete; // #cwg1558-f-deleted struct X { typedef void type; }; @@ -639,7 +639,7 @@ namespace cwg1591 { //cwg1591. Deducing array bound and element type from initi #if __cplusplus >= 201103L template int h(T const(&)[N]); int X = h({1,2,3}); // T deduced to int, N deduced to 3 - + template int j(T const(&)[3]); int Y = j({42}); // T deduced to int, array bound not considered @@ -655,12 +655,12 @@ namespace cwg1591 { //cwg1591. Deducing array bound and element type from initi template int n(T const(&)[N], T); int X1 = n({{1},{2},{3}},Aggr()); // OK, T is Aggr, N is 3 - - + + namespace check_multi_dim_arrays { template int ***f(const T (&a)[N][M][O]); // #cwg1591-f-3 template int **f(const T (&a)[N][M]); // #cwg1591-f-2 - + template int *f(const T (&a)[N]); // #cwg1591-f-1 int ***p3 = f({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12} } }); int ***p33 = f({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12, 13} } }); @@ -675,7 +675,7 @@ namespace cwg1591 { //cwg1591. Deducing array bound and element type from initi namespace check_multi_dim_arrays_rref { template int ***g(T (&&a)[N][M][O]); // #cwg1591-g-3 template int **g(T (&&a)[N][M]); // #cwg1591-g-2 - + template int *g(T (&&a)[N]); // #cwg1591-g-1 int ***p3 = g({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12} } }); int ***p33 = g({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12, 13} } }); @@ -687,7 +687,7 @@ namespace cwg1591 { //cwg1591. Deducing array bound and element type from initi int **p22 = g({ {1,2}, {3, 4} }); int *p1 = g({1, 2, 3}); } - + namespace check_arrays_of_init_list { template float *h(const std::initializer_list (&)[N]); template double *h(const T(&)[N]); @@ -695,7 +695,7 @@ namespace cwg1591 { //cwg1591. Deducing array bound and element type from initi float *fp = h({{1}, {1, 2}, {1, 2, 3}}); } namespace core_reflector_28543 { - + template int *i(T (&&)[N]); // #1 template char *i(std::initializer_list &&); // #2 template int **i(T (&&)[N][M]); // #3 #cwg1591-i-2 @@ -704,13 +704,13 @@ namespace cwg1591 { //cwg1591. Deducing array bound and element type from initi template short *i(T (&&)[2]); // #5 template using Arr = T[]; - + char *pc = i({1, 2, 3}); // OK prefer #2 via 13.3.3.2 [over.ics.rank] - char *pc2 = i({1, 2}); // #2 also + char *pc2 = i({1, 2}); // #2 also int *pi = i(Arr{1, 2, 3}); // OK prefer #1 void *pv1 = i({ {1, 2, 3}, {4, 5, 6} }); // ambiguous btw 3 & 4 - // since-cxx11-error@-1 {{call to 'i' is ambiguous}} + // since-cxx11-error@-1 {{call to 'i' is ambiguous}} // since-cxx11-note@#cwg1591-i-2 {{candidate function [with T = int, N = 2, M = 3]}} // since-cxx11-note@#cwg1591-i-1 {{candidate function [with T = int, N = 2]}} char **pcc = i({ {1}, {2, 3} }); // OK #4 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 index 871bdc2a58c7..05295cc7b0c9 100644 --- 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 @@ A::C::B absip; 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 @@ namespace print_dependent_TemplateSpecializationType { 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/CodeGen/preferred_name.cpp b/clang/test/CodeGen/preferred_name.cpp index 9b3f532faf97..023245b0a4cb 100644 --- a/clang/test/CodeGen/preferred_name.cpp +++ b/clang/test/CodeGen/preferred_name.cpp @@ -69,20 +69,16 @@ int main() { Bar barShort; -// LLDB: !DILocalVariable(name: "barShort", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_SHORT_TY_2:[0-9]+]]) +// LLDB: !DILocalVariable(name: "barShort", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_SHORT_TY:[0-9]+]]) // GDB: !DILocalVariable(name: "barShort", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_SHORT_TYPEDEF:[0-9]+]]) // GDB: ![[BAR_SHORT_TYPEDEF]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar" Bar barChar; -// LLDB: ![[BAR_SHORT_TY_2]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar", file: ![[#]], line: [[#]], baseType: ![[BAR_SHORT_TY]]) - -// LLDB: !DILocalVariable(name: "barChar", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_CHAR_TY_2:[0-9]+]]) +// LLDB: !DILocalVariable(name: "barChar", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_CHAR_TY:[0-9]+]]) // GDB: !DILocalVariable(name: "barChar", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_CHAR_TYPEDEF:[0-9]+]]) // GDB: ![[BAR_CHAR_TYPEDEF]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar" -// LLDB: ![[BAR_CHAR_TY_2]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar", file: ![[#]], line: [[#]], baseType: ![[BAR_CHAR_TY]]) - return 0; } diff --git a/clang/test/SemaCXX/pr100095.cpp b/clang/test/SemaCXX/pr100095.cpp index 15913fec9d5a..f2a3b1f8b5ad 100644 --- a/clang/test/SemaCXX/pr100095.cpp +++ b/clang/test/SemaCXX/pr100095.cpp @@ -1,5 +1,8 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -// XFAIL: asserts + +// FIXME: With deduction changes to better preserve +// type sugar, the bug that this test case used to +// expose is harder to reproduce. template struct Pair; template struct Tuple { diff --git a/clang/test/SemaCXX/references.cpp b/clang/test/SemaCXX/references.cpp index 7ef3f43ff55a..01ea50809dcb 100644 --- a/clang/test/SemaCXX/references.cpp +++ b/clang/test/SemaCXX/references.cpp @@ -98,7 +98,7 @@ void test7(C& c) { // C++ [dcl.ref]p1, C++ [dcl.ref]p4 void test8(int& const,// expected-error{{'const' qualifier may not be applied to a reference}} - + void&, // expected-error{{cannot form a reference to 'void'}} int& &) // expected-error{{type name declared as a reference to a reference}} { @@ -131,7 +131,7 @@ class string { char *Data; unsigned Length; public: - string(); + string(); ~string(); }; @@ -144,11 +144,11 @@ void test9() { void test10() { __attribute((vector_size(16))) typedef int vec4; typedef __attribute__(( ext_vector_type(4) )) int ext_vec4; - + vec4 v; int &a = v[0]; // expected-error{{non-const reference cannot bind to vector element}} const int &b = v[0]; - + ext_vec4 ev; int &c = ev.x; // expected-error{{non-const reference cannot bind to vector element}} const int &d = ev.x; @@ -216,3 +216,15 @@ namespace PR45521 { int *d; const a &r = d; } + +namespace with_sugar { + template