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