From 761787d42576751afbaaba5107233ee849f81b6f Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Sat, 12 Apr 2025 14:26:30 -0300 Subject: [PATCH] Reland: [clang] Improved canonicalization for template specialization types (#135414) This relands https://github.com/llvm/llvm-project/pull/135119, after fixing crashes seen in LLDB CI reported here: https://github.com/llvm/llvm-project/pull/135119#issuecomment-2794910840 Fixes https://github.com/llvm/llvm-project/pull/135119 This changes the TemplateArgument representation to hold a flag indicating whether a tempalte argument of expression type is supposed to be canonical or not. This gets one step closer to solving https://github.com/llvm/llvm-project/issues/92292 This still doesn't try to unique as-written TSTs. While this would increase the amount of memory savings and make code dealing with the AST more well-behaved, profiling template argument lists is still too expensive for this to be worthwhile, at least for now. This also fixes the context creation of TSTs, so that they don't in some cases get incorrectly flagged as sugar over their own canonical form. This is captured in the test expectation change of some AST dumps. This fixes some places which were unnecessarily canonicalizing these TSTs. --- clang-tools-extra/clangd/AST.cpp | 3 +- clang/docs/ReleaseNotes.rst | 2 + clang/include/clang/AST/ASTContext.h | 49 ++- clang/include/clang/AST/PropertiesBase.td | 5 +- clang/include/clang/AST/TemplateBase.h | 13 +- clang/include/clang/AST/Type.h | 33 +- clang/include/clang/AST/TypeProperties.td | 30 +- clang/lib/AST/ASTContext.cpp | 343 ++++++++++-------- clang/lib/AST/ASTDiagnostic.cpp | 8 +- clang/lib/AST/ASTImporter.cpp | 31 +- clang/lib/AST/ASTStructuralEquivalence.cpp | 4 +- clang/lib/AST/DeclTemplate.cpp | 7 +- clang/lib/AST/QualTypeNames.cpp | 3 +- clang/lib/AST/TemplateBase.cpp | 19 +- clang/lib/AST/Type.cpp | 59 ++- clang/lib/Sema/SemaCXXScopeSpec.cpp | 18 +- clang/lib/Sema/SemaExpr.cpp | 20 +- clang/lib/Sema/SemaLookup.cpp | 3 +- clang/lib/Sema/SemaTemplate.cpp | 162 ++++----- clang/lib/Sema/SemaTemplateDeduction.cpp | 45 ++- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 11 +- clang/lib/Sema/SemaTemplateVariadic.cpp | 3 +- clang/lib/Sema/TreeTransform.h | 13 +- .../class.derived.general/p2.cpp | 2 +- .../temp/temp.decls/temp.class.spec/p6.cpp | 4 +- .../undefined-partial-specialization.cpp | 2 +- clang/test/SemaTemplate/make_integer_seq.cpp | 61 +--- clang/test/SemaTemplate/type_pack_element.cpp | 57 +-- clang/unittests/AST/TypePrinterTest.cpp | 6 +- 29 files changed, 515 insertions(+), 501 deletions(-) diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp index 66b587f00ff4..3b991e5e9013 100644 --- a/clang-tools-extra/clangd/AST.cpp +++ b/clang-tools-extra/clangd/AST.cpp @@ -439,7 +439,8 @@ QualType declaredType(const TypeDecl *D) { if (const auto *CTSD = llvm::dyn_cast(D)) if (const auto *Args = CTSD->getTemplateArgsAsWritten()) return Context.getTemplateSpecializationType( - TemplateName(CTSD->getSpecializedTemplate()), Args->arguments()); + TemplateName(CTSD->getSpecializedTemplate()), Args->arguments(), + /*CanonicalArgs=*/std::nullopt); return Context.getTypeDeclType(D); } diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9c45965dc4d8..11f62bc881b0 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -303,6 +303,8 @@ Improvements to Clang's diagnostics - Clang now better preserves the sugared types of pointers to member. - Clang now better preserves the presence of the template keyword with dependent prefixes. +- Clang now in more cases avoids printing 'type-parameter-X-X' instead of the name of + the template parameter. - Clang now respects the current language mode when printing expressions in diagnostics. This fixes a bunch of `bool` being printed as `_Bool`, and also a bunch of HLSL types being printed as their C++ equivalents. diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index b1e6344576eb..0f6c727f6f9c 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -243,8 +243,7 @@ class ASTContext : public RefCountedBase { mutable llvm::FoldingSet PackExpansionTypes; mutable llvm::FoldingSet ObjCObjectTypes; mutable llvm::FoldingSet ObjCObjectPointerTypes; - mutable llvm::FoldingSet - DependentUnaryTransformTypes; + mutable llvm::FoldingSet UnaryTransformTypes; // An AutoType can have a dependency on another AutoType via its template // arguments. Since both dependent and dependency are on the same set, // we can end up in an infinite recursion when looking for a node if we used @@ -367,9 +366,6 @@ class ASTContext : public RefCountedBase { const ASTContext&> CanonTemplateTemplateParms; - TemplateTemplateParmDecl * - getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const; - /// The typedef for the __int128_t type. mutable TypedefDecl *Int128Decl = nullptr; @@ -1811,22 +1807,26 @@ public: bool ParameterPack, TemplateTypeParmDecl *ParmDecl = nullptr) const; - QualType getTemplateSpecializationType(TemplateName T, - ArrayRef Args, - QualType Canon = QualType()) const; + QualType getCanonicalTemplateSpecializationType( + TemplateName T, ArrayRef CanonicalArgs) const; QualType - getCanonicalTemplateSpecializationType(TemplateName T, - ArrayRef Args) const; + getTemplateSpecializationType(TemplateName T, + ArrayRef SpecifiedArgs, + ArrayRef CanonicalArgs, + QualType Underlying = QualType()) const; - QualType getTemplateSpecializationType(TemplateName T, - ArrayRef Args, - QualType Canon = QualType()) const; + QualType + getTemplateSpecializationType(TemplateName T, + ArrayRef SpecifiedArgs, + ArrayRef CanonicalArgs, + 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 CanonicalArgs, + QualType Canon = QualType()) const; QualType getParenType(QualType NamedType) const; @@ -2942,6 +2942,21 @@ 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; + + /// Canonicalize the given TemplateTemplateParmDecl. + TemplateTemplateParmDecl * + getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const; + + TemplateTemplateParmDecl *findCanonicalTemplateTemplateParmDeclInternal( + TemplateTemplateParmDecl *TTP) const; + TemplateTemplateParmDecl *insertCanonicalTemplateTemplateParmDeclInternal( + TemplateTemplateParmDecl *CanonTTP) 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/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td index 90537d47dd9c..33336d57b629 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -877,11 +877,14 @@ let Class = PropertyTypeCase in { def : Property<"expression", ExprRef> { let Read = [{ node.getAsExpr() }]; } + def : Property<"IsCanonical", Bool> { + let Read = [{ node.isCanonicalExpr() }]; + } def : Property<"isDefaulted", Bool> { let Read = [{ node.getIsDefaulted() }]; } def : Creator<[{ - return TemplateArgument(expression, isDefaulted); + return TemplateArgument(expression, IsCanonical, isDefaulted); }]>; } let Class = PropertyTypeCase in { diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h index bea624eb0494..279feb858e66 100644 --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -167,6 +167,8 @@ private: unsigned Kind : 31; LLVM_PREFERRED_TYPE(bool) unsigned IsDefaulted : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned IsCanonicalExpr : 1; uintptr_t V; }; union { @@ -187,7 +189,8 @@ private: public: /// Construct an empty, invalid template argument. - constexpr TemplateArgument() : TypeOrValue({Null, 0, /* IsDefaulted */ 0}) {} + constexpr TemplateArgument() + : TypeOrValue{Null, /*IsDefaulted=*/0, /*IsCanonicalExpr=*/0, /*V=*/0} {} /// Construct a template type argument. TemplateArgument(QualType T, bool isNullPtr = false, @@ -262,9 +265,10 @@ public: /// This form of template argument only occurs in template argument /// lists used for dependent types and for expression; it will not /// occur in a non-dependent, canonical template argument list. - explicit TemplateArgument(Expr *E, bool IsDefaulted = false) { + TemplateArgument(Expr *E, bool IsCanonical, bool IsDefaulted = false) { TypeOrValue.Kind = Expression; TypeOrValue.IsDefaulted = IsDefaulted; + TypeOrValue.IsCanonicalExpr = IsCanonical; TypeOrValue.V = reinterpret_cast(E); } @@ -407,6 +411,11 @@ public: return reinterpret_cast(TypeOrValue.V); } + bool isCanonicalExpr() const { + assert(getKind() == Expression && "Unexpected kind"); + return TypeOrValue.IsCanonicalExpr; + } + /// Iterator that traverses the elements of a template argument pack. using pack_iterator = const TemplateArgument *; diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 9f6189440fab..fe62120a2564 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -5918,7 +5918,7 @@ public: /// of this class via DecltypeType nodes. class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode { public: - DependentDecltypeType(Expr *E, QualType UnderlyingTpe); + DependentDecltypeType(Expr *E); void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { Profile(ID, Context, getUnderlyingExpr()); @@ -6003,7 +6003,7 @@ private: }; /// A unary type transform, which is a type constructed from another. -class UnaryTransformType : public Type { +class UnaryTransformType : public Type, public llvm::FoldingSetNode { public: enum UTTKind { #define TRANSFORM_TYPE_TRAIT_DEF(Enum, _) Enum, @@ -6037,28 +6037,16 @@ public: static bool classof(const Type *T) { return T->getTypeClass() == UnaryTransform; } -}; - -/// Internal representation of canonical, dependent -/// __underlying_type(type) types. -/// -/// This class is used internally by the ASTContext to manage -/// canonical, dependent types, only. Clients will only see instances -/// of this class via UnaryTransformType nodes. -class DependentUnaryTransformType : public UnaryTransformType, - public llvm::FoldingSetNode { -public: - DependentUnaryTransformType(const ASTContext &C, QualType BaseType, - UTTKind UKind); void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getBaseType(), getUTTKind()); + Profile(ID, getBaseType(), getUnderlyingType(), getUTTKind()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType BaseType, - UTTKind UKind) { - ID.AddPointer(BaseType.getAsOpaquePtr()); - ID.AddInteger((unsigned)UKind); + QualType UnderlyingType, UTTKind UKind) { + BaseType.Profile(ID); + UnderlyingType.Profile(ID); + ID.AddInteger(UKind); } }; @@ -6676,10 +6664,9 @@ class TemplateSpecializationType : public Type, public llvm::FoldingSetNode { /// replacement must, recursively, be one of these). TemplateName Template; - TemplateSpecializationType(TemplateName T, + TemplateSpecializationType(TemplateName T, bool IsAlias, ArrayRef Args, - QualType Canon, - QualType Aliased); + QualType Underlying); public: /// Determine whether any of the given template arguments are dependent. @@ -6747,7 +6734,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx); static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, - ArrayRef Args, + ArrayRef Args, QualType Underlying, const ASTContext &Context); static bool classof(const Type *T) { diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index 66d490850678..3bf9239e9cbf 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -737,39 +737,19 @@ let Class = DependentAddressSpaceType in { } let Class = TemplateSpecializationType in { - def : Property<"dependent", Bool> { - let Read = [{ node->isDependentType() }]; - } def : Property<"templateName", TemplateName> { let Read = [{ node->getTemplateName() }]; } - def : Property<"templateArguments", Array> { + def : Property<"args", Array> { let Read = [{ node->template_arguments() }]; } - def : Property<"underlyingType", Optional> { - let Read = [{ - node->isTypeAlias() - ? std::optional(node->getAliasedType()) - : node->isCanonicalUnqualified() - ? std::nullopt - : std::optional(node->getCanonicalTypeInternal()) - }]; + def : Property<"UnderlyingType", QualType> { + let Read = [{ node->isCanonicalUnqualified() ? QualType() : + node->desugar() }]; } def : Creator<[{ - QualType result; - if (!underlyingType) { - result = ctx.getCanonicalTemplateSpecializationType(templateName, - templateArguments); - } else { - result = ctx.getTemplateSpecializationType(templateName, - templateArguments, - *underlyingType); - } - if (dependent) - const_cast(result.getTypePtr()) - ->addDependence(TypeDependence::DependentInstantiation); - return result; + return ctx.getTemplateSpecializationType(templateName, args, std::nullopt, UnderlyingType); }]>; } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 00e2fa267a46..46bd1977d688 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -844,6 +844,31 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( return CanonTTP; } +TemplateTemplateParmDecl * +ASTContext::findCanonicalTemplateTemplateParmDeclInternal( + TemplateTemplateParmDecl *TTP) const { + llvm::FoldingSetNodeID ID; + CanonicalTemplateTemplateParm::Profile(ID, *this, TTP); + void *InsertPos = nullptr; + CanonicalTemplateTemplateParm *Canonical = + CanonTemplateTemplateParms.FindNodeOrInsertPos(ID, InsertPos); + return Canonical ? Canonical->getParam() : nullptr; +} + +TemplateTemplateParmDecl * +ASTContext::insertCanonicalTemplateTemplateParmDeclInternal( + TemplateTemplateParmDecl *CanonTTP) const { + llvm::FoldingSetNodeID ID; + CanonicalTemplateTemplateParm::Profile(ID, *this, CanonTTP); + void *InsertPos = nullptr; + if (auto *Existing = + CanonTemplateTemplateParms.FindNodeOrInsertPos(ID, InsertPos)) + return Existing->getParam(); + CanonTemplateTemplateParms.InsertNode( + new (*this) CanonicalTemplateTemplateParm(CanonTTP), InsertPos); + return CanonTTP; +} + /// Check if a type can have its sanitizer instrumentation elided based on its /// presence within an ignorelist. bool ASTContext::isTypeIgnoredBySanitizer(const SanitizerMask &Mask, @@ -3083,12 +3108,19 @@ static auto getCanonicalTemplateArguments(const ASTContext &C, ArrayRef Args, bool &AnyNonCanonArgs) { SmallVector CanonArgs(Args); - for (auto &Arg : CanonArgs) { + AnyNonCanonArgs |= C.canonicalizeTemplateArguments(CanonArgs); + return CanonArgs; +} + +bool ASTContext::canonicalizeTemplateArguments( + MutableArrayRef Args) const { + bool AnyNonCanonArgs = false; + for (auto &Arg : Args) { TemplateArgument OrigArg = Arg; - Arg = C.getCanonicalTemplateArgument(Arg); + Arg = getCanonicalTemplateArgument(Arg); AnyNonCanonArgs |= !Arg.structurallyEquals(OrigArg); } - return CanonArgs; + return AnyNonCanonArgs; } //===----------------------------------------------------------------------===// @@ -5538,129 +5570,118 @@ 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 CanonicalArgs, QualType Underlying) const { + QualType TST = getTemplateSpecializationType(Name, SpecifiedArgs.arguments(), + CanonicalArgs, 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 CanonicalArgs, 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, CanonicalArgs, + Underlying); } -#ifndef NDEBUG -static bool hasAnyPackExpansions(ArrayRef Args) { +[[maybe_unused]] static bool +hasAnyPackExpansions(ArrayRef Args) { for (const TemplateArgument &Arg : Args) if (Arg.isPackExpansion()) return true; - - return true; -} -#endif - -QualType -ASTContext::getTemplateSpecializationType(TemplateName Template, - ArrayRef Args, - QualType Underlying) const { - assert(!Template.getAsDependentTemplateName() && - "No dependent template names here!"); - - 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)) && - "Caller must compute aliased type"); - IsTypeAlias = false; - CanonType = getCanonicalTemplateSpecializationType(Template, Args); - } - - // 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()); - - Types.push_back(Spec); - return QualType(Spec, 0); + return false; } QualType ASTContext::getCanonicalTemplateSpecializationType( TemplateName Template, ArrayRef Args) const { - assert(!Template.getAsDependentTemplateName() && + assert(Template == + getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true)); + assert(!Args.empty()); +#ifndef NDEBUG + for (const auto &Arg : Args) + assert(Arg.structurallyEquals(getCanonicalTemplateArgument(Arg))); +#endif + + llvm::FoldingSetNodeID ID; + TemplateSpecializationType::Profile(ID, Template, Args, QualType(), *this); + void *InsertPos = nullptr; + if (auto *T = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(T, 0); + + void *Mem = Allocate(sizeof(TemplateSpecializationType) + + sizeof(TemplateArgument) * Args.size(), + alignof(TemplateSpecializationType)); + auto *Spec = new (Mem) + TemplateSpecializationType(Template, /*IsAlias=*/false, Args, QualType()); + assert(Spec->isDependentType() && + "canonical template specialization must be dependent"); + Types.push_back(Spec); + TemplateSpecializationTypes.InsertNode(Spec, InsertPos); + return QualType(Spec, 0); +} + +QualType ASTContext::getTemplateSpecializationType( + TemplateName Template, ArrayRef SpecifiedArgs, + ArrayRef CanonicalArgs, QualType Underlying) const { + assert(!Template.getUnderlying().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); + const auto *TD = Template.getAsTemplateDecl(/*IgnoreDeduced=*/true); + bool IsTypeAlias = TD && TD->isTypeAlias(); + if (Underlying.isNull()) { + TemplateName CanonTemplate = + getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true); + bool NonCanonical = Template != CanonTemplate; + SmallVector CanonArgsVec; + if (CanonicalArgs.empty()) { + CanonArgsVec = SmallVector(SpecifiedArgs); + NonCanonical |= canonicalizeTemplateArguments(CanonArgsVec); + CanonicalArgs = CanonArgsVec; + } else { + NonCanonical |= !llvm::equal( + SpecifiedArgs, CanonicalArgs, + [](const TemplateArgument &A, const TemplateArgument &B) { + return A.structurallyEquals(B); + }); + } - bool AnyNonCanonArgs = false; - auto CanonArgs = - ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs); + // We can get here with an alias template when the specialization + // contains a pack expansion that does not match up with a parameter + // pack, or a builtin template which cannot be resolved due to dependency. + assert((!isa_and_nonnull(TD) || + hasAnyPackExpansions(CanonicalArgs)) && + "Caller must compute aliased type"); + IsTypeAlias = false; - // 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); + Underlying = + getCanonicalTemplateSpecializationType(CanonTemplate, CanonicalArgs); + if (!NonCanonical) + return Underlying; } - - assert(Spec->isDependentType() && - "Non-dependent template-id type must have a canonical type"); + void *Mem = Allocate(sizeof(TemplateSpecializationType) + + sizeof(TemplateArgument) * SpecifiedArgs.size() + + (IsTypeAlias ? sizeof(QualType) : 0), + alignof(TemplateSpecializationType)); + auto *Spec = new (Mem) TemplateSpecializationType(Template, IsTypeAlias, + SpecifiedArgs, Underlying); + Types.push_back(Spec); return QualType(Spec, 0); } @@ -5853,7 +5874,7 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) const { if (NTTP->isParameterPack()) E = new (*this) PackExpansionExpr(E, NTTP->getLocation(), std::nullopt); - Arg = TemplateArgument(E); + Arg = TemplateArgument(E, /*IsCanonical=*/false); } else { auto *TTP = cast(Param); TemplateName Name = getQualifiedTemplateName( @@ -6334,34 +6355,36 @@ QualType ASTContext::getReferenceQualifiedType(const Expr *E) const { /// nodes. This would never be helpful, since each such type has its own /// expression, and would not give a significant memory saving, since there /// is an Expr tree under each such type. -QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType) const { - DecltypeType *dt; - +QualType ASTContext::getDecltypeType(Expr *E, QualType UnderlyingType) const { // C++11 [temp.type]p2: // If an expression e involves a template parameter, decltype(e) denotes a // unique dependent type. Two such decltype-specifiers refer to the same // type only if their expressions are equivalent (14.5.6.1). - if (e->isInstantiationDependent()) { + QualType CanonType; + if (!E->isInstantiationDependent()) { + CanonType = getCanonicalType(UnderlyingType); + } else if (!UnderlyingType.isNull()) { + CanonType = getDecltypeType(E, QualType()); + } else { llvm::FoldingSetNodeID ID; - DependentDecltypeType::Profile(ID, *this, e); + DependentDecltypeType::Profile(ID, *this, E); void *InsertPos = nullptr; - DependentDecltypeType *Canon - = DependentDecltypeTypes.FindNodeOrInsertPos(ID, InsertPos); - if (!Canon) { - // Build a new, canonical decltype(expr) type. - Canon = new (*this, alignof(DependentDecltypeType)) - DependentDecltypeType(e, DependentTy); - DependentDecltypeTypes.InsertNode(Canon, InsertPos); - } - dt = new (*this, alignof(DecltypeType)) - DecltypeType(e, UnderlyingType, QualType((DecltypeType *)Canon, 0)); - } else { - dt = new (*this, alignof(DecltypeType)) - DecltypeType(e, UnderlyingType, getCanonicalType(UnderlyingType)); + if (DependentDecltypeType *Canon = + DependentDecltypeTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(Canon, 0); + + // Build a new, canonical decltype(expr) type. + auto *DT = + new (*this, alignof(DependentDecltypeType)) DependentDecltypeType(E); + DependentDecltypeTypes.InsertNode(DT, InsertPos); + Types.push_back(DT); + return QualType(DT, 0); } - Types.push_back(dt); - return QualType(dt, 0); + auto *DT = new (*this, alignof(DecltypeType)) + DecltypeType(E, UnderlyingType, CanonType); + Types.push_back(DT); + return QualType(DT, 0); } QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr, @@ -6401,36 +6424,41 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr, /// getUnaryTransformationType - We don't unique these, since the memory /// savings are minimal and these are rare. -QualType ASTContext::getUnaryTransformType(QualType BaseType, - QualType UnderlyingType, - UnaryTransformType::UTTKind Kind) - const { - UnaryTransformType *ut = nullptr; +QualType +ASTContext::getUnaryTransformType(QualType BaseType, QualType UnderlyingType, + UnaryTransformType::UTTKind Kind) const { - if (BaseType->isDependentType()) { - // Look in the folding set for an existing type. - llvm::FoldingSetNodeID ID; - DependentUnaryTransformType::Profile(ID, getCanonicalType(BaseType), Kind); + llvm::FoldingSetNodeID ID; + UnaryTransformType::Profile(ID, BaseType, UnderlyingType, Kind); - void *InsertPos = nullptr; - DependentUnaryTransformType *Canon - = DependentUnaryTransformTypes.FindNodeOrInsertPos(ID, InsertPos); + void *InsertPos = nullptr; + if (UnaryTransformType *UT = + UnaryTransformTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(UT, 0); - if (!Canon) { - // Build a new, canonical __underlying_type(type) type. - Canon = new (*this, alignof(DependentUnaryTransformType)) - DependentUnaryTransformType(*this, getCanonicalType(BaseType), Kind); - DependentUnaryTransformTypes.InsertNode(Canon, InsertPos); - } - ut = new (*this, alignof(UnaryTransformType)) - UnaryTransformType(BaseType, QualType(), Kind, QualType(Canon, 0)); + QualType CanonType; + if (!BaseType->isDependentType()) { + CanonType = UnderlyingType.getCanonicalType(); } else { - QualType CanonType = getCanonicalType(UnderlyingType); - ut = new (*this, alignof(UnaryTransformType)) - UnaryTransformType(BaseType, UnderlyingType, Kind, CanonType); + assert(UnderlyingType.isNull() || BaseType == UnderlyingType); + UnderlyingType = QualType(); + if (QualType CanonBase = BaseType.getCanonicalType(); + BaseType != CanonBase) { + CanonType = getUnaryTransformType(CanonBase, QualType(), Kind); + assert(CanonType.isCanonical()); + + // Find the insertion position again. + [[maybe_unused]] UnaryTransformType *UT = + UnaryTransformTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!UT && "broken canonicalization"); + } } - Types.push_back(ut); - return QualType(ut, 0); + + auto *UT = new (*this, alignof(UnaryTransformType)) + UnaryTransformType(BaseType, UnderlyingType, Kind, CanonType); + UnaryTransformTypes.InsertNode(UT, InsertPos); + Types.push_back(UT); + return QualType(UT, 0); } QualType ASTContext::getAutoTypeInternal( @@ -6461,9 +6489,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); } } } @@ -7543,7 +7571,8 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { return Arg; case TemplateArgument::Expression: - return Arg; + return TemplateArgument(Arg.getAsExpr(), /*IsCanonical=*/true, + Arg.getIsDefaulted()); case TemplateArgument::Declaration: { auto *D = cast(Arg.getAsDecl()->getCanonicalDecl()); @@ -8199,8 +8228,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(); } @@ -14012,7 +14040,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, ::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(), TY->getTemplateName(), /*IgnoreDeduced=*/true), - As, X->getCanonicalTypeInternal()); + As, /*CanonicalArgs=*/std::nullopt, X->getCanonicalTypeInternal()); } case Type::Decltype: { const auto *DX = cast(X); @@ -14252,11 +14280,12 @@ 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(), + SmallVector As; + if (getCommonTemplateArguments(Ctx, As, TX->template_arguments(), TY->template_arguments())) return QualType(); - return Ctx.getTemplateSpecializationType(CTN, Args, + return Ctx.getTemplateSpecializationType(CTN, As, + /*CanonicalArgs=*/std::nullopt, Ctx.getQualifiedType(Underlying)); } case Type::Typedef: { diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index ccfef9c7ae36..5baff6c1e13e 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -128,7 +128,7 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT, if (DesugarArgument) { ShouldAKA = true; QT = Context.getTemplateSpecializationType( - TST->getTemplateName(), Args, QT); + TST->getTemplateName(), Args, /*CanonicalArgs=*/std::nullopt, QT); } break; } @@ -1142,9 +1142,9 @@ class TemplateDiff { return nullptr; Ty = Context.getTemplateSpecializationType( - TemplateName(CTSD->getSpecializedTemplate()), - CTSD->getTemplateArgs().asArray(), - Ty.getLocalUnqualifiedType().getCanonicalType()); + TemplateName(CTSD->getSpecializedTemplate()), + CTSD->getTemplateArgs().asArray(), /*CanonicalArgs=*/std::nullopt, + Ty.getLocalUnqualifiedType().getCanonicalType()); return Ty->getAs(); } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index ab550d7aff5f..378734e9c190 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -893,7 +893,8 @@ ASTNodeImporter::import(const TemplateArgument &From) { case TemplateArgument::Expression: if (ExpectedExpr ToExpr = import(From.getAsExpr())) - return TemplateArgument(*ToExpr, From.getIsDefaulted()); + return TemplateArgument(*ToExpr, From.isCanonicalExpr(), + From.getIsDefaulted()); else return ToExpr.takeError(); @@ -1660,18 +1661,12 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType( ImportTemplateArguments(T->template_arguments(), ToTemplateArgs)) return std::move(Err); - QualType ToCanonType; - if (!T->isCanonicalUnqualified()) { - QualType FromCanonType - = Importer.getFromContext().getCanonicalType(QualType(T, 0)); - if (ExpectedType TyOrErr = import(FromCanonType)) - ToCanonType = *TyOrErr; - else - return TyOrErr.takeError(); - } - return Importer.getToContext().getTemplateSpecializationType(*ToTemplateOrErr, - ToTemplateArgs, - ToCanonType); + ExpectedType ToUnderlyingOrErr = + T->isCanonicalUnqualified() ? QualType() : import(T->desugar()); + if (!ToUnderlyingOrErr) + return ToUnderlyingOrErr.takeError(); + return Importer.getToContext().getTemplateSpecializationType( + *ToTemplateOrErr, ToTemplateArgs, std::nullopt, *ToUnderlyingOrErr); } ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { @@ -6018,6 +6013,12 @@ ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { ExpectedDecl ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + bool IsCanonical = false; + if (auto *CanonD = Importer.getFromContext() + .findCanonicalTemplateTemplateParmDeclInternal(D); + CanonD == D) + IsCanonical = true; + // Import the name of this declaration. auto NameOrErr = import(D->getDeclName()); if (!NameOrErr) @@ -6045,6 +6046,10 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { if (Error Err = importTemplateParameterDefaultArgument(D, ToD)) return Err; + if (IsCanonical) + return Importer.getToContext() + .insertCanonicalTemplateTemplateParmDeclInternal(ToD); + return ToD; } diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 2c7cb581ccfa..b8db635a2b89 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -580,7 +580,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const DependentTemplateStorage &S1, const DependentTemplateStorage &S2) { - if (!IsStructurallyEquivalent(Context, S1.getQualifier(), S2.getQualifier())) + if (NestedNameSpecifier *NNS1 = S1.getQualifier(), *NNS2 = S2.getQualifier(); + !NNS1 != !NNS2 || + (NNS1 && !IsStructurallyEquivalent(Context, NNS1, NNS2))) return false; IdentifierOrOverloadedOperator IO1 = S1.getName(), IO2 = S2.getName(); diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index e8e2cad72198..79a36109276f 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -671,8 +671,11 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() { ASTContext &Context = getASTContext(); TemplateName Name = Context.getQualifiedTemplateName( /*NNS=*/nullptr, /*TemplateKeyword=*/false, TemplateName(this)); - CommonPtr->InjectedClassNameType = Context.getTemplateSpecializationType( - Name, getTemplateParameters()->getInjectedTemplateArgs(Context)); + auto TemplateArgs = getTemplateParameters()->getInjectedTemplateArgs(Context); + CommonPtr->InjectedClassNameType = + Context.getTemplateSpecializationType(Name, + /*SpecifiedArgs=*/TemplateArgs, + /*CanonicalArgs=*/std::nullopt); return CommonPtr->InjectedClassNameType; } diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp index 5c151254c36e..4d11a3b62331 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -140,7 +140,7 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx, if (MightHaveChanged) { QualType QT = Ctx.getTemplateSpecializationType( TST->getTemplateName(), FQArgs, - TST->getCanonicalTypeInternal()); + /*CanonicalArgs=*/std::nullopt, TST->desugar()); // getTemplateSpecializationType returns a fully qualified // version of the specialization itself, so no need to qualify // it. @@ -172,6 +172,7 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx, TemplateName TN(TSTDecl->getSpecializedTemplate()); QualType QT = Ctx.getTemplateSpecializationType( TN, FQArgs, + /*CanonicalArgs=*/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 42da4e6ca996..ad4f919b7483 100644 --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -414,9 +414,16 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, getAsStructuralValue().Profile(ID); break; - case Expression: - getAsExpr()->Profile(ID, Context, true); + case Expression: { + const Expr *E = getAsExpr(); + bool IsCanonical = isCanonicalExpr(); + ID.AddBoolean(IsCanonical); + if (IsCanonical) + E->Profile(ID, Context, true); + else + ID.AddPointer(E); break; + } case Pack: ID.AddInteger(Args.NumArgs); @@ -431,9 +438,11 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const { switch (getKind()) { case Null: case Type: - case Expression: case NullPtr: return TypeOrValue.V == Other.TypeOrValue.V; + case Expression: + return TypeOrValue.V == Other.TypeOrValue.V && + TypeOrValue.IsCanonicalExpr == Other.TypeOrValue.IsCanonicalExpr; case Template: case TemplateExpansion: @@ -478,7 +487,8 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const { return getAsType()->castAs()->getPattern(); case Expression: - return TemplateArgument(cast(getAsExpr())->getPattern()); + return TemplateArgument(cast(getAsExpr())->getPattern(), + isCanonicalExpr()); case TemplateExpansion: return TemplateArgument(getAsTemplateOrTemplatePattern()); @@ -655,6 +665,7 @@ static const T &DiagTemplateArg(const T &DB, const TemplateArgument &Arg) { return DB << Arg.getAsTemplateOrTemplatePattern() << "..."; case TemplateArgument::Expression: + // FIXME: Support printing expressions as canonical return DB << Arg.getAsExpr(); case TemplateArgument::Pack: { diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index f6dffeb0a1a8..7898e6b90bf4 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4055,8 +4055,8 @@ QualType DecltypeType::desugar() const { return QualType(this, 0); } -DependentDecltypeType::DependentDecltypeType(Expr *E, QualType UnderlyingType) - : DecltypeType(E, UnderlyingType) {} +DependentDecltypeType::DependentDecltypeType(Expr *E) + : DecltypeType(E, QualType()) {} void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, Expr *E) { @@ -4127,11 +4127,6 @@ UnaryTransformType::UnaryTransformType(QualType BaseType, : Type(UnaryTransform, CanonicalType, BaseType->getDependence()), BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind) {} -DependentUnaryTransformType::DependentUnaryTransformType(const ASTContext &C, - QualType BaseType, - UTTKind UKind) - : UnaryTransformType(BaseType, C.DependentTy, UKind, QualType()) {} - TagType::TagType(TypeClass TC, const TagDecl *D, QualType can) : Type(TC, can, D->isDependentType() ? TypeDependence::DependentInstantiation @@ -4388,17 +4383,19 @@ 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 Args, + 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.TypeAlias = IsAlias; assert(!T.getAsDependentTemplateName() && "Use DependentTemplateSpecializationType for dependent template-name"); @@ -4410,7 +4407,8 @@ TemplateSpecializationType::TemplateSpecializationType( T.getKind() == TemplateName::DeducedTemplate) && "Unexpected template name for TemplateSpecializationType"); - auto *TemplateArgs = reinterpret_cast(this + 1); + auto *TemplateArgs = + const_cast(template_arguments().data()); for (const TemplateArgument &Arg : Args) { // Update instantiation-dependent, variably-modified, and error bits. // If the canonical type exists and is non-dependent, the template @@ -4428,11 +4426,10 @@ TemplateSpecializationType::TemplateSpecializationType( new (TemplateArgs++) TemplateArgument(Arg); } - // 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; - } + // Store the aliased type after the template arguments, if this is a type + // alias template specialization. + if (IsAlias) + *reinterpret_cast(TemplateArgs) = Underlying; } QualType TemplateSpecializationType::getAliasedType() const { @@ -4442,17 +4439,19 @@ QualType TemplateSpecializationType::getAliasedType() const { void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { - Profile(ID, Template, template_arguments(), Ctx); - if (isTypeAlias()) - getAliasedType().Profile(ID); + Profile(ID, Template, template_arguments(), + isSugared() ? desugar() : QualType(), Ctx); } -void -TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, - TemplateName T, - ArrayRef Args, - const ASTContext &Context) { +void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, + TemplateName T, + ArrayRef Args, + QualType Underlying, + const ASTContext &Context) { T.Profile(ID); + Underlying.Profile(ID); + + ID.AddInteger(Args.size()); for (const TemplateArgument &Arg : Args) Arg.Profile(ID, Context); } @@ -5264,9 +5263,9 @@ 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) { ID.AddPointer(Deduced.getAsOpaquePtr()); ID.AddInteger((unsigned)Keyword); ID.AddBoolean(IsDependent); diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 68ee006c6cf0..f497106223df 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -69,17 +69,14 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, // Look through type alias templates, per C++0x [temp.dep.type]p1. NNSType = Context.getCanonicalType(NNSType); - if (const TemplateSpecializationType *SpecType - = NNSType->getAs()) { + if (const auto *SpecType = + dyn_cast(NNSType)) { // We are entering the context of the nested name specifier, so try to // match the nested name specifier to either a primary class template // or a class template partial specialization. - if (ClassTemplateDecl *ClassTemplate - = dyn_cast_or_null( - SpecType->getTemplateName().getAsTemplateDecl())) { - QualType ContextType = - Context.getCanonicalType(QualType(SpecType, 0)); - + if (ClassTemplateDecl *ClassTemplate = + dyn_cast_or_null( + SpecType->getTemplateName().getAsTemplateDecl())) { // FIXME: The fallback on the search of partial // specialization using ContextType should be eventually removed since // it doesn't handle the case of constrained template parameters @@ -100,7 +97,8 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, SpecType->template_arguments(), *L, Pos); } } else { - PartialSpec = ClassTemplate->findPartialSpecialization(ContextType); + PartialSpec = + ClassTemplate->findPartialSpecialization(QualType(SpecType, 0)); } if (PartialSpec) { @@ -122,7 +120,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, // into that class template definition. QualType Injected = ClassTemplate->getInjectedClassNameSpecialization(); - if (Context.hasSameType(Injected, ContextType)) + if (Context.hasSameType(Injected, QualType(SpecType, 0))) return ClassTemplate->getTemplatedDecl(); } } else if (const RecordType *RecordT = NNSType->getAs()) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 25b7bd0e1694..c25daaa022f4 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2183,7 +2183,7 @@ Sema::ActOnStringLiteral(ArrayRef StringToks, Scope *UDLScope) { case LOLR_Template: { TemplateArgumentListInfo ExplicitArgs; - TemplateArgument Arg(Lit); + TemplateArgument Arg(Lit, /*IsCanonical=*/false); TemplateArgumentLocInfo ArgInfo(Lit); ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); return BuildLiteralOperatorCall(R, OpNameInfo, {}, StringTokLocs.back(), @@ -21108,8 +21108,22 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { Diag(Temp->getLocation(), diag::note_referenced_type_template) << IsTypeAliasTemplateDecl; - QualType TST = - Context.getTemplateSpecializationType(TN, ULE->template_arguments()); + TemplateArgumentListInfo TAL(ULE->getLAngleLoc(), ULE->getRAngleLoc()); + bool HasAnyDependentTA = false; + for (const TemplateArgumentLoc &Arg : ULE->template_arguments()) { + HasAnyDependentTA |= Arg.getArgument().isDependent(); + TAL.addArgument(Arg); + } + + QualType TST; + { + SFINAETrap Trap(*this); + TST = CheckTemplateIdType(TN, NameInfo.getBeginLoc(), TAL); + } + if (TST.isNull()) + TST = Context.getTemplateSpecializationType( + TN, ULE->template_arguments(), /*CanonicalArgs=*/std::nullopt, + HasAnyDependentTA ? Context.DependentTy : Context.IntTy); QualType ET = Context.getElaboratedType(ElaboratedTypeKeyword::None, NNS, TST); return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {}, diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index a77ca779a9ee..58134603424a 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -3713,7 +3713,8 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R, if (StringLit) { SFINAETrap Trap(*this); CheckTemplateArgumentInfo CTAI; - TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit); + TemplateArgumentLoc Arg( + TemplateArgument(StringLit, /*IsCanonical=*/false), StringLit); if (CheckTemplateArgument( Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(), /*ArgumentPackIndex=*/0, CTAI, CTAK_Specified) || diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 3d7fa38272e6..40e29bb18807 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -909,7 +909,7 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef, case ParsedTemplateArgument::NonType: { Expr *E = static_cast(Arg.getAsExpr()); - return TemplateArgumentLoc(TemplateArgument(E), E); + return TemplateArgumentLoc(TemplateArgument(E, /*IsCanonical=*/false), E); } case ParsedTemplateArgument::Template: { @@ -1576,8 +1576,9 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, return Param; Param->setDefaultArgument( - Context, getTrivialTemplateArgumentLoc(TemplateArgument(Default), - QualType(), SourceLocation())); + Context, getTrivialTemplateArgumentLoc( + TemplateArgument(Default, /*IsCanonical=*/false), + QualType(), SourceLocation())); } return Param; @@ -3250,8 +3251,7 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, TemplateArgument NumArgsArg = Converted[2]; if (NumArgsArg.isDependent()) - return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD), - Converted); + return QualType(); TemplateArgumentListInfo SyntheticTemplateArgs; // The type argument, wrapped in substitution sugar, gets reused as the @@ -3288,12 +3288,11 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, // __type_pack_element // are treated like T_Index. assert(Converted.size() == 2 && - "__type_pack_element should be given an index and a parameter pack"); + "__type_pack_element should be given an index and a parameter pack"); TemplateArgument IndexArg = Converted[0], Ts = Converted[1]; if (IndexArg.isDependent() || Ts.isDependent()) - return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD), - Converted); + return QualType(); llvm::APSInt Index = IndexArg.getAsIntegral(); assert(Index >= 0 && "the index used with __type_pack_element should be of " @@ -3313,12 +3312,9 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, 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); + return QualType(); TemplateName BaseTemplate = Converted[0].getAsTemplate(); - TemplateName HasTypeMember = Converted[1].getAsTemplate(); - QualType HasNoTypeMember = Converted[2].getAsType(); ArrayRef Ts = Converted[3].getPackAsArray(); if (auto CT = builtinCommonTypeImpl(SemaRef, BaseTemplate, TemplateLoc, Ts); !CT.isNull()) { @@ -3326,9 +3322,10 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, TAs.addArgument(TemplateArgumentLoc( TemplateArgument(CT), SemaRef.Context.getTrivialTypeSourceInfo( CT, TemplateArgs[1].getLocation()))); - + TemplateName HasTypeMember = Converted[1].getAsTemplate(); return SemaRef.CheckTemplateIdType(HasTypeMember, TemplateLoc, TAs); } + QualType HasNoTypeMember = Converted[2].getAsType(); return HasNoTypeMember; } } @@ -3492,20 +3489,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 +3515,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(); @@ -3602,7 +3601,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // // template struct A; CanonType = Context.getCanonicalTemplateSpecializationType( - Name, CTAI.CanonicalConverted); + Context.getCanonicalTemplateName(Name, /*IgnoreDeduced=*/true), + CTAI.CanonicalConverted); + assert(CanonType->isCanonicalUnqualified()); // This might work out to be a current instantiation, in which // case the canonical type needs to be the InjectedClassNameType. @@ -3688,8 +3689,8 @@ 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.CanonicalConverted, CanonType); } void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName, @@ -5286,7 +5287,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc, // If the resulting expression is new, then use it in place of the // old expression in the template argument. if (R != E) { - TemplateArgument TA(R); + TemplateArgument TA(R, /*IsCanonical=*/false); ArgLoc = TemplateArgumentLoc(TA, R); } break; @@ -6476,7 +6477,7 @@ static bool CheckTemplateArgumentAddressOfObjectOrFunction( // Stop checking the precise nature of the argument if it is value dependent, // it should be checked when instantiated. if (Arg->isValueDependent()) { - SugaredConverted = TemplateArgument(ArgIn); + SugaredConverted = TemplateArgument(ArgIn, /*IsCanonical=*/false); CanonicalConverted = S.Context.getCanonicalTemplateArgument(SugaredConverted); return false; @@ -6667,7 +6668,7 @@ CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param, if (VD->getType()->isMemberPointerType()) { if (isa(VD)) { if (Arg->isTypeDependent() || Arg->isValueDependent()) { - SugaredConverted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = S.Context.getCanonicalTemplateArgument(SugaredConverted); } else { @@ -6733,7 +6734,7 @@ CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param, // Okay: this is the address of a non-static member, and therefore // a member pointer constant. if (Arg->isTypeDependent() || Arg->isValueDependent()) { - SugaredConverted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = S.Context.getCanonicalTemplateArgument(SugaredConverted); } else { @@ -6784,7 +6785,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (DeductionArg->isTypeDependent()) { auto *AT = dyn_cast(DeducedT); if (AT && AT->isDecltypeAuto()) { - SugaredConverted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = TemplateArgument( Context.getCanonicalTemplateArgument(SugaredConverted)); return Arg; @@ -6858,7 +6859,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (E.isInvalid()) return ExprError(); setDeductionArg(E.get()); - SugaredConverted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = TemplateArgument( Context.getCanonicalTemplateArgument(SugaredConverted)); return Arg; @@ -6889,7 +6890,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // normal template rules apply: we accept the template if it would be valid // for any number of expansions (i.e. none). if (ArgPE && !StrictCheck) { - SugaredConverted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = TemplateArgument( Context.getCanonicalTemplateArgument(SugaredConverted)); return Arg; @@ -6915,7 +6916,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return Arg; } if (isa(ND)) { - SugaredConverted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = Context.getCanonicalTemplateArgument(SugaredConverted); return Arg; @@ -6972,7 +6973,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // permitted (and expected) to be unable to determine a value. if (ArgResult.get()->isValueDependent()) { setDeductionArg(ArgResult.get()); - SugaredConverted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = Context.getCanonicalTemplateArgument(SugaredConverted); return Arg; @@ -7010,7 +7011,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Value.getLValuePath()[0].getAsArrayIndex() == 0 && !Value.isLValueOnePastTheEnd() && ParamType->isPointerType()) { if (ArgPE) { - SugaredConverted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = Context.getCanonicalTemplateArgument(SugaredConverted); } else { @@ -7041,7 +7042,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff); if (ArgPE) { - SugaredConverted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = Context.getCanonicalTemplateArgument(SugaredConverted); } else { @@ -7086,7 +7087,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // We can't check arbitrary value-dependent arguments. if (DeductionArg->isValueDependent()) { - SugaredConverted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = Context.getCanonicalTemplateArgument(SugaredConverted); return Arg; @@ -7103,7 +7104,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, : Context.getTypeSize(IntegerType)); if (ArgPE) { - SugaredConverted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = Context.getCanonicalTemplateArgument(SugaredConverted); } else { @@ -7187,7 +7188,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (DeductionArg->isValueDependent()) { // The argument is value-dependent. Create a new // TemplateArgument with the converted expression. - SugaredConverted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = Context.getCanonicalTemplateArgument(SugaredConverted); return Arg; @@ -7243,7 +7244,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } if (ArgPE) { - SugaredConverted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = Context.getCanonicalTemplateArgument(SugaredConverted); } else { @@ -7366,7 +7367,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // Deal with parameters of type std::nullptr_t. if (ParamType->isNullPtrType()) { if (DeductionArg->isTypeDependent() || DeductionArg->isValueDependent()) { - SugaredConverted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = Context.getCanonicalTemplateArgument(SugaredConverted); return Arg; @@ -7386,7 +7387,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, case NPV_NullPointer: Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); if (ArgPE) { - SugaredConverted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = Context.getCanonicalTemplateArgument(SugaredConverted); } else { @@ -8523,17 +8524,34 @@ 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.CanonicalConverted, CanonType); + + if (isPartialSpecialization) { + if (Context.hasSameType( + WrittenTy->getType(), + ClassTemplate->getInjectedClassNameSpecialization()) && (!Context.getLangOpts().CPlusPlus20 || !TemplateParams->hasAssociatedConstraints())) { // C++ [temp.class.spec]p9b3: @@ -8560,7 +8578,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()) { @@ -8578,29 +8597,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: @@ -8690,8 +8686,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 5dc69a5413db..772962ac653f 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -493,8 +493,8 @@ DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, : CK_NullToPointer) .get(); return DeduceNonTypeTemplateArgument( - S, TemplateParams, NTTP, TemplateArgument(Value), Value->getType(), Info, - PartialOrdering, Deduced, HasDeducedAnyParam); + S, TemplateParams, NTTP, TemplateArgument(Value, /*IsCanonical=*/false), + Value->getType(), Info, PartialOrdering, Deduced, HasDeducedAnyParam); } /// Deduce the value of the given non-type template parameter @@ -508,8 +508,8 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { return DeduceNonTypeTemplateArgument( - S, TemplateParams, NTTP, TemplateArgument(Value), Value->getType(), Info, - PartialOrdering, Deduced, HasDeducedAnyParam); + S, TemplateParams, NTTP, TemplateArgument(Value, /*IsCanonical=*/false), + Value->getType(), Info, PartialOrdering, Deduced, HasDeducedAnyParam); } /// Deduce the value of the given non-type template parameter @@ -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(); } } @@ -2899,7 +2902,7 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc, TemplateParam) .getAs(); - return TemplateArgumentLoc(TemplateArgument(E), E); + return TemplateArgumentLoc(TemplateArgument(E, /*IsCanonical=*/false), E); } case TemplateArgument::NullPtr: { @@ -2914,7 +2917,7 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, case TemplateArgument::Integral: case TemplateArgument::StructuralValue: { Expr *E = BuildExpressionFromNonTypeTemplateArgument(Arg, Loc).get(); - return TemplateArgumentLoc(TemplateArgument(E), E); + return TemplateArgumentLoc(TemplateArgument(E, /*IsCanonical=*/false), E); } case TemplateArgument::Template: @@ -6415,8 +6418,8 @@ Sema::getMoreSpecializedPartialSpecialization( ClassTemplatePartialSpecializationDecl *PS1, ClassTemplatePartialSpecializationDecl *PS2, SourceLocation Loc) { - QualType PT1 = PS1->getInjectedSpecializationType(); - QualType PT2 = PS2->getInjectedSpecializationType(); + QualType PT1 = PS1->getInjectedSpecializationType().getCanonicalType(); + QualType PT2 = PS2->getInjectedSpecializationType().getCanonicalType(); TemplateDeductionInfo Info(Loc); return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info); @@ -6425,8 +6428,9 @@ Sema::getMoreSpecializedPartialSpecialization( bool Sema::isMoreSpecializedThanPrimary( ClassTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) { ClassTemplateDecl *Primary = Spec->getSpecializedTemplate(); - QualType PrimaryT = Primary->getInjectedClassNameSpecialization(); - QualType PartialT = Spec->getInjectedSpecializationType(); + QualType PrimaryT = + Primary->getInjectedClassNameSpecialization().getCanonicalType(); + QualType PartialT = Spec->getInjectedSpecializationType().getCanonicalType(); ClassTemplatePartialSpecializationDecl *MaybeSpec = getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info); @@ -6444,10 +6448,10 @@ Sema::getMoreSpecializedPartialSpecialization( assert(PS1->getSpecializedTemplate() == PS2->getSpecializedTemplate() && "the partial specializations being compared should specialize" " the same template."); - TemplateName Name(PS1->getSpecializedTemplate()); - QualType PT1 = Context.getTemplateSpecializationType( + TemplateName Name(PS1->getSpecializedTemplate()->getCanonicalDecl()); + QualType PT1 = Context.getCanonicalTemplateSpecializationType( Name, PS1->getTemplateArgs().asArray()); - QualType PT2 = Context.getTemplateSpecializationType( + QualType PT2 = Context.getCanonicalTemplateSpecializationType( Name, PS2->getTemplateArgs().asArray()); TemplateDeductionInfo Info(Loc); @@ -6457,10 +6461,15 @@ Sema::getMoreSpecializedPartialSpecialization( bool Sema::isMoreSpecializedThanPrimary( VarTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) { VarTemplateDecl *Primary = Spec->getSpecializedTemplate(); - TemplateName Name(Primary); - QualType PrimaryT = Context.getTemplateSpecializationType( - Name, Primary->getInjectedTemplateArgs(Context)); - QualType PartialT = Context.getTemplateSpecializationType( + TemplateName Name(Primary->getCanonicalDecl()); + + SmallVector PrimaryCanonArgs( + Primary->getInjectedTemplateArgs(Context)); + Context.canonicalizeTemplateArguments(PrimaryCanonArgs); + + QualType PrimaryT = + Context.getCanonicalTemplateSpecializationType(Name, PrimaryCanonArgs); + QualType PartialT = Context.getCanonicalTemplateSpecializationType( Name, Spec->getTemplateArgs().asArray()); VarTemplatePartialSpecializationDecl *MaybeSpec = diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index eb8632d9eb25..108d7e1dbaeb 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4791,17 +4791,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.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/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 3040a30454b0..dc7e3a0bf887 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -1286,7 +1286,8 @@ TemplateArgumentLoc Sema::getTemplateArgumentPackExpansionPattern( Expr *Pattern = Expansion->getPattern(); Ellipsis = Expansion->getEllipsisLoc(); NumExpansions = Expansion->getNumExpansions(); - return TemplateArgumentLoc(TemplateArgument(Pattern), Pattern); + return TemplateArgumentLoc( + TemplateArgument(Pattern, Argument.isCanonicalExpr()), Pattern); } case TemplateArgument::TemplateExpansion: diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 13762dc485c3..21e250e172d5 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3981,7 +3981,9 @@ public: if (Result.isInvalid()) return TemplateArgumentLoc(); - return TemplateArgumentLoc(TemplateArgument(Result.get()), Result.get()); + return TemplateArgumentLoc(TemplateArgument(Result.get(), + /*IsCanonical=*/false), + Result.get()); } case TemplateArgument::Template: @@ -4941,7 +4943,8 @@ bool TreeTransform::TransformTemplateArgument( E = SemaRef.ActOnConstantExpression(E); if (E.isInvalid()) return true; - Output = TemplateArgumentLoc(TemplateArgument(E.get()), E.get()); + Output = TemplateArgumentLoc( + TemplateArgument(E.get(), /*IsCanonical=*/false), E.get()); return false; } } @@ -16131,8 +16134,10 @@ TreeTransform::TransformSizeOfPackExpr(SizeOfPackExpr *E) { E->getPackLoc()); if (DRE.isInvalid()) return ExprError(); - ArgStorage = TemplateArgument(new (getSema().Context) PackExpansionExpr( - DRE.get(), E->getPackLoc(), std::nullopt)); + ArgStorage = TemplateArgument( + new (getSema().Context) + PackExpansionExpr(DRE.get(), E->getPackLoc(), std::nullopt), + /*IsCanonical=*/false); } PackArgs = ArgStorage; } 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/temp/temp.decls/temp.class.spec/p6.cpp b/clang/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp index 0f7653c96dcc..2da0382accff 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/SemaCXX/undefined-partial-specialization.cpp b/clang/test/SemaCXX/undefined-partial-specialization.cpp index b07a513270fd..0f776a6145fe 100644 --- a/clang/test/SemaCXX/undefined-partial-specialization.cpp +++ b/clang/test/SemaCXX/undefined-partial-specialization.cpp @@ -10,6 +10,6 @@ template class boo; template -void boo::foo(){} // expected-error{{out-of-line definition of 'foo' from class 'boo' without definition}} +void boo::foo(){} // expected-error{{out-of-line definition of 'foo' from class 'boo' without definition}} } diff --git a/clang/test/SemaTemplate/make_integer_seq.cpp b/clang/test/SemaTemplate/make_integer_seq.cpp index 7ca7b55b4996..cd36d1e2c8e0 100644 --- a/clang/test/SemaTemplate/make_integer_seq.cpp +++ b/clang/test/SemaTemplate/make_integer_seq.cpp @@ -73,76 +73,47 @@ using test2 = B; template