https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/135119
>From 03801aef9b4f950940d33276095c14047da0a3e6 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov <mizve...@gmail.com> Date: Sat, 17 Sep 2022 18:07:28 +0200 Subject: [PATCH] [clang] Improved canonicalization for template specialization types 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 | 46 ++-- clang/include/clang/AST/PropertiesBase.td | 5 +- clang/include/clang/AST/TemplateBase.h | 13 +- clang/include/clang/AST/Type.h | 7 +- clang/include/clang/AST/TypeProperties.td | 30 +-- clang/lib/AST/ASTContext.cpp | 236 ++++++++++-------- clang/lib/AST/ASTDiagnostic.cpp | 8 +- clang/lib/AST/ASTImporter.cpp | 34 ++- clang/lib/AST/DeclTemplate.cpp | 7 +- clang/lib/AST/QualTypeNames.cpp | 3 +- clang/lib/AST/TemplateBase.cpp | 19 +- clang/lib/AST/Type.cpp | 50 ++-- 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 +- 28 files changed, 448 insertions(+), 422 deletions(-) diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp index 66b587f00ff4a..3b991e5e9013f 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<ClassTemplateSpecializationDecl>(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 cd16641c25ed8..204d41476232c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -280,6 +280,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 3ff9f308f3a5e..c339bb698e099 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -364,9 +364,6 @@ class ASTContext : public RefCountedBase<ASTContext> { const ASTContext&> CanonTemplateTemplateParms; - TemplateTemplateParmDecl * - getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const; - /// The typedef for the __int128_t type. mutable TypedefDecl *Int128Decl = nullptr; @@ -1808,22 +1805,26 @@ class ASTContext : public RefCountedBase<ASTContext> { bool ParameterPack, TemplateTypeParmDecl *ParmDecl = nullptr) const; - QualType getTemplateSpecializationType(TemplateName T, - ArrayRef<TemplateArgument> Args, - QualType Canon = QualType()) const; + QualType getCanonicalTemplateSpecializationType( + TemplateName T, ArrayRef<TemplateArgument> CanonicalArgs) const; QualType - getCanonicalTemplateSpecializationType(TemplateName T, - ArrayRef<TemplateArgument> Args) const; + getTemplateSpecializationType(TemplateName T, + ArrayRef<TemplateArgument> SpecifiedArgs, + ArrayRef<TemplateArgument> CanonicalArgs, + QualType Underlying = QualType()) const; - QualType getTemplateSpecializationType(TemplateName T, - ArrayRef<TemplateArgumentLoc> Args, - QualType Canon = QualType()) const; + QualType + getTemplateSpecializationType(TemplateName T, + ArrayRef<TemplateArgumentLoc> SpecifiedArgs, + ArrayRef<TemplateArgument> 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<TemplateArgument> CanonicalArgs, + QualType Canon = QualType()) const; QualType getParenType(QualType NamedType) const; @@ -2939,6 +2940,21 @@ class ASTContext : public RefCountedBase<ASTContext> { 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<TemplateArgument> 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 90537d47dd9c9..33336d57b6298 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -877,11 +877,14 @@ let Class = PropertyTypeCase<TemplateArgument, "Expression"> 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<TemplateArgument, "Pack"> in { diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h index bea624eb04942..f833a1ec02455 100644 --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -168,6 +168,8 @@ class TemplateArgument { LLVM_PREFERRED_TYPE(bool) unsigned IsDefaulted : 1; uintptr_t V; + LLVM_PREFERRED_TYPE(bool) + unsigned IsCanonicalExpr : 1; }; union { struct DA DeclArg; @@ -187,7 +189,8 @@ class TemplateArgument { public: /// Construct an empty, invalid template argument. - constexpr TemplateArgument() : TypeOrValue({Null, 0, /* IsDefaulted */ 0}) {} + constexpr TemplateArgument() + : TypeOrValue{Null, /*IsDefaulted=*/0, /*V=*/0, /*IsCanonicalExpr=*/0} {} /// Construct a template type argument. TemplateArgument(QualType T, bool isNullPtr = false, @@ -262,10 +265,11 @@ class TemplateArgument { /// 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.V = reinterpret_cast<uintptr_t>(E); + TypeOrValue.IsCanonicalExpr = IsCanonical; } /// Construct a template argument that is a template argument pack. @@ -407,6 +411,11 @@ class TemplateArgument { return reinterpret_cast<Expr *>(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 9f6189440fabf..dc57170bf9160 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -6676,10 +6676,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<TemplateArgument> Args, - QualType Canon, - QualType Aliased); + QualType Underlying); public: /// Determine whether any of the given template arguments are dependent. @@ -6747,7 +6746,7 @@ class TemplateSpecializationType : public Type, public llvm::FoldingSetNode { void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx); static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, - ArrayRef<TemplateArgument> Args, + ArrayRef<TemplateArgument> 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 66d490850678a..3bf9239e9cbf5 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<TemplateArgument>> { + def : Property<"args", Array<TemplateArgument>> { let Read = [{ node->template_arguments() }]; } - def : Property<"underlyingType", Optional<QualType>> { - let Read = [{ - node->isTypeAlias() - ? std::optional<QualType>(node->getAliasedType()) - : node->isCanonicalUnqualified() - ? std::nullopt - : std::optional<QualType>(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<Type *>(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 0fe941e063d49..6ad49c27b34d1 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<TemplateArgument> Args, bool &AnyNonCanonArgs) { SmallVector<TemplateArgument, 16> CanonArgs(Args); - for (auto &Arg : CanonArgs) { + AnyNonCanonArgs |= C.canonicalizeTemplateArguments(CanonArgs); + return CanonArgs; +} + +bool ASTContext::canonicalizeTemplateArguments( + MutableArrayRef<TemplateArgument> 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<TemplateArgument> CanonicalArgs, QualType Underlying) const { + QualType TST = getTemplateSpecializationType(Name, SpecifiedArgs.arguments(), + CanonicalArgs, Underlying); TypeSourceInfo *DI = CreateTypeSourceInfo(TST); TemplateSpecializationTypeLoc TL = DI->getTypeLoc().castAs<TemplateSpecializationTypeLoc>(); 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<TemplateArgumentLoc> Args, - QualType Underlying) const { - assert(!Template.getAsDependentTemplateName() && - "No dependent template names here!"); +QualType ASTContext::getTemplateSpecializationType( + TemplateName Template, ArrayRef<TemplateArgumentLoc> SpecifiedArgs, + ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying) const { + SmallVector<TemplateArgument, 4> SpecifiedArgVec; + SpecifiedArgVec.reserve(SpecifiedArgs.size()); + for (const TemplateArgumentLoc &Arg : SpecifiedArgs) + SpecifiedArgVec.push_back(Arg.getArgument()); - SmallVector<TemplateArgument, 4> 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<TemplateArgument> Args) { +[[maybe_unused]] static bool +hasAnyPackExpansions(ArrayRef<TemplateArgument> Args) { for (const TemplateArgument &Arg : Args) if (Arg.isPackExpansion()) return true; - - return true; + return false; } -#endif -QualType -ASTContext::getTemplateSpecializationType(TemplateName Template, - ArrayRef<TemplateArgument> Args, - QualType Underlying) const { - assert(!Template.getAsDependentTemplateName() && - "No dependent template names here!"); +QualType ASTContext::getCanonicalTemplateSpecializationType( + TemplateName Template, ArrayRef<TemplateArgument> Args) const { + assert(Template == + getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true)); + assert(!Args.empty()); +#ifndef NDEBUG + for (const auto &Arg : Args) + assert(Arg.structurallyEquals(getCanonicalTemplateArgument(Arg))); +#endif - 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); - } + llvm::FoldingSetNodeID ID; + TemplateSpecializationType::Profile(ID, Template, Args, QualType(), *this); + void *InsertPos = nullptr; + if (auto *T = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(T, 0); - // 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), + sizeof(TemplateArgument) * Args.size(), alignof(TemplateSpecializationType)); - auto *Spec - = new (Mem) TemplateSpecializationType(Template, Args, CanonType, - IsTypeAlias ? Underlying : QualType()); - + 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::getCanonicalTemplateSpecializationType( - TemplateName Template, ArrayRef<TemplateArgument> Args) const { - assert(!Template.getAsDependentTemplateName() && +QualType ASTContext::getTemplateSpecializationType( + TemplateName Template, ArrayRef<TemplateArgument> SpecifiedArgs, + ArrayRef<TemplateArgument> 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); - - bool AnyNonCanonArgs = false; - auto CanonArgs = - ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs); - - // Determine whether this canonical template specialization type already - // exists. - llvm::FoldingSetNodeID ID; - TemplateSpecializationType::Profile(ID, CanonTemplate, - CanonArgs, *this); - - void *InsertPos = nullptr; - TemplateSpecializationType *Spec - = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); + 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<TemplateArgument, 4> CanonArgsVec; + if (CanonicalArgs.empty()) { + CanonArgsVec = SmallVector<TemplateArgument, 4>(SpecifiedArgs); + NonCanonical |= canonicalizeTemplateArguments(CanonArgsVec); + CanonicalArgs = CanonArgsVec; + } else { + NonCanonical |= !llvm::equal( + SpecifiedArgs, CanonicalArgs, + [](const TemplateArgument &A, const TemplateArgument &B) { + return A.structurallyEquals(B); + }); + } + + // 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<TypeAliasTemplateDecl>(TD) || + hasAnyPackExpansions(CanonicalArgs)) && + "Caller must compute aliased type"); + IsTypeAlias = false; - 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<TemplateTemplateParmDecl>(Param); TemplateName Name = getQualifiedTemplateName( @@ -6461,9 +6482,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 +7564,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<ValueDecl>(Arg.getAsDecl()->getCanonicalDecl()); @@ -8199,8 +8221,7 @@ QualType ASTContext::getObjCSuperType() const { void ASTContext::setCFConstantStringType(QualType T) { const auto *TD = T->castAs<TypedefType>(); CFConstantStringTypeDecl = cast<TypedefDecl>(TD->getDecl()); - const auto *TagType = - CFConstantStringTypeDecl->getUnderlyingType()->castAs<RecordType>(); + const auto *TagType = TD->castAs<RecordType>(); CFConstantStringTagDecl = TagType->getDecl(); } @@ -13986,7 +14007,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<DecltypeType>(X); @@ -14226,11 +14247,12 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, TY->getTemplateName(), /*IgnoreDeduced=*/true); if (!CTN.getAsVoidPointer()) return QualType(); - SmallVector<TemplateArgument, 8> Args; - if (getCommonTemplateArguments(Ctx, Args, TX->template_arguments(), + SmallVector<TemplateArgument, 8> 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 ccfef9c7ae361..5baff6c1e13e9 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<TemplateSpecializationType>(); } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index f4b977d1d14b3..1528fb9021aec 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,15 @@ 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); + if (T->isCanonicalUnqualified()) + return Importer.getToContext().getCanonicalTemplateSpecializationType( + *ToTemplateOrErr, ToTemplateArgs); + + ExpectedType ToUnderlyingOrErr = import(T->desugar()); + if (!ToUnderlyingOrErr) + return ToUnderlyingOrErr.takeError(); + return Importer.getToContext().getTemplateSpecializationType( + *ToTemplateOrErr, ToTemplateArgs, std::nullopt, *ToUnderlyingOrErr); } ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { @@ -6015,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) @@ -6042,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/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index e8e2cad721981..79a36109276f0 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 5c151254c36e7..4d11a3b623314 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 42da4e6ca9964..ad4f919b7483e 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<PackExpansionType>()->getPattern(); case Expression: - return TemplateArgument(cast<PackExpansionExpr>(getAsExpr())->getPattern()); + return TemplateArgument(cast<PackExpansionExpr>(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 4336fe44b82ad..2f395ccfb163e 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4384,17 +4384,19 @@ bool TemplateSpecializationType::anyInstantiationDependentTemplateArguments( } TemplateSpecializationType::TemplateSpecializationType( - TemplateName T, ArrayRef<TemplateArgument> Args, QualType Canon, - QualType AliasedType) - : Type(TemplateSpecialization, Canon.isNull() ? QualType(this, 0) : Canon, - (Canon.isNull() + TemplateName T, bool IsAlias, ArrayRef<TemplateArgument> 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"); @@ -4406,7 +4408,8 @@ TemplateSpecializationType::TemplateSpecializationType( T.getKind() == TemplateName::DeducedTemplate) && "Unexpected template name for TemplateSpecializationType"); - auto *TemplateArgs = reinterpret_cast<TemplateArgument *>(this + 1); + auto *TemplateArgs = + const_cast<TemplateArgument *>(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 @@ -4424,11 +4427,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<TemplateArgument *>(this + 1); - *reinterpret_cast<QualType *>(Begin + Args.size()) = AliasedType; - } + // Store the aliased type after the template arguments, if this is a type + // alias template specialization. + if (IsAlias) + *reinterpret_cast<QualType *>(TemplateArgs) = Underlying; } QualType TemplateSpecializationType::getAliasedType() const { @@ -4438,17 +4440,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<TemplateArgument> Args, - const ASTContext &Context) { +void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, + TemplateName T, + ArrayRef<TemplateArgument> 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); } @@ -5260,9 +5264,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<TemplateArgument> Arguments) { + QualType Deduced, AutoTypeKeyword Keyword, + bool IsDependent, ConceptDecl *CD, + ArrayRef<TemplateArgument> 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 68ee006c6cf00..f497106223df4 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<TemplateSpecializationType>()) { + if (const auto *SpecType = + dyn_cast<TemplateSpecializationType>(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<ClassTemplateDecl>( - SpecType->getTemplateName().getAsTemplateDecl())) { - QualType ContextType = - Context.getCanonicalType(QualType(SpecType, 0)); - + if (ClassTemplateDecl *ClassTemplate = + dyn_cast_or_null<ClassTemplateDecl>( + 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<RecordType>()) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e7f418ae6802e..2729c35b6fb2d 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2183,7 +2183,7 @@ Sema::ActOnStringLiteral(ArrayRef<Token> 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(), @@ -21086,8 +21086,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 a77ca779a9ee3..58134603424a6 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 3d7fa38272e6a..40e29bb18807a 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<Expr *>(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<Index, T_1, ..., T_N> // 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<TemplateArgument> 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<FunctionTemplateDecl>(Template) || - isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(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<FunctionTemplateDecl>(Template) || + isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(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<TypeAliasTemplateDecl>(Template)) { + if (isa<TemplateTemplateParmDecl>(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<TypeAliasTemplateDecl>(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<typename T, typename U = T> 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<NonTypeTemplateParmDecl>(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<AutoType>(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<NonTypeTemplateParmDecl>(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) { + // 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 (!PrevDecl) + ClassTemplate->AddSpecialization(Specialization, InsertPos); + + if (!CurContext->isDependentContext()) + CanonType = Context.getTypeDeclType(Specialization); + } + + TypeSourceInfo *WrittenTy = Context.getTemplateSpecializationTypeInfo( + Name, TemplateNameLoc, TemplateArgs, CTAI.CanonicalConverted, 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 (Context.hasSameType(CanonType, - ClassTemplate->getInjectedClassNameSpecialization()) && + 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 6236bce743438..814ece2066885 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<DeducedTemplateArgument> &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<TemplateSpecializationType>(); - 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<Expr>(); - 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<TemplateArgument, 8> 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 e0f7ccc4674d8..8b8db36c10771 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4789,17 +4789,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 3040a30454b0c..dc7e3a0bf8875 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 13762dc485c32..21e250e172d5e 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3981,7 +3981,9 @@ class TreeTransform { 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<Derived>::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<Derived>::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 888d9cd7a939d..1423eeabebf59 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<T>::B5<U>::C3 : A0, B5 { }; template<typename T> - struct A0<T*> { // expected-note 2{{definition of 'A0<type-parameter-0-0 *>' is not complete until the closing '}'}} + struct A0<T*> { // expected-note 2{{definition of 'A0<T *>' is not complete until the closing '}'}} struct B0 : A0 { }; // expected-error {{base class has incomplete type}} template<typename U> 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 0f7653c96dcc5..2da0382accff3 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<short>::C::B<int*> absip; template<typename T, typename U> struct Outer { template<typename X, typename Y> struct Inner; - template<typename Y> struct Inner<T, Y> {}; // expected-note{{previous declaration of class template partial specialization 'Inner<int, type-parameter-0-0>' is here}} + template<typename Y> struct Inner<T, Y> {}; // expected-note{{previous declaration of class template partial specialization 'Inner<int, Y>' is here}} template<typename Y> struct Inner<U, Y> {}; // expected-error{{cannot be redeclared}} }; @@ -80,7 +80,7 @@ namespace print_dependent_TemplateSpecializationType { template <class T, class U> struct Foo { template <unsigned long, class X, class Y> struct Bar; template <class Y> 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 <class Y> 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 b07a513270fd6..0f776a6145fef 100644 --- a/clang/test/SemaCXX/undefined-partial-specialization.cpp +++ b/clang/test/SemaCXX/undefined-partial-specialization.cpp @@ -10,6 +10,6 @@ template <typename T> class boo<T, true>; template<typename T> -void boo<T, true>::foo(){} // expected-error{{out-of-line definition of 'foo' from class 'boo<type-parameter-0-0, true>' without definition}} +void boo<T, true>::foo(){} // expected-error{{out-of-line definition of 'foo' from class 'boo<T, true>' without definition}} } diff --git a/clang/test/SemaTemplate/make_integer_seq.cpp b/clang/test/SemaTemplate/make_integer_seq.cpp index 7ca7b55b49964..cd36d1e2c8e09 100644 --- a/clang/test/SemaTemplate/make_integer_seq.cpp +++ b/clang/test/SemaTemplate/make_integer_seq.cpp @@ -73,76 +73,47 @@ using test2 = B<int, 1>; template <template <class T, T...> class S, class T, int N> struct C { using test3 = __make_integer_seq<S, T, N>; -// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:43> col:9 test3 '__make_integer_seq<S, T, N>':'__make_integer_seq<template-parameter-0-0, type-parameter-0-1, N>' +// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:43> col:9 test3 '__make_integer_seq<S, T, N>' // CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<S, T, N>' sugar dependent -// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<S, T, N>' sugar dependent alias -// CHECK-NEXT: |-name: '__make_integer_seq' qualified +// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<S, T, N>' dependent +// CHECK-NEXT: |-name: '__make_integer_seq' // CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq // CHECK-NEXT: |-TemplateArgument template 'S' // CHECK-NEXT: | | `-TemplateTemplateParmDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:11, col:42> col:42 depth 0 index 0 S // CHECK-NEXT: |-TemplateArgument type 'T' // CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'T' dependent depth 0 index 1 // CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'T' -// CHECK-NEXT: |-TemplateArgument expr 'N' -// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent> -// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int' -// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<template-parameter-0-0, type-parameter-0-1, N>' dependent -// CHECK-NEXT: |-name: '__make_integer_seq' -// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq -// CHECK-NEXT: |-TemplateArgument template 'template-parameter-0-0' -// CHECK-NEXT: | `-TemplateTemplateParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> depth 0 index 0 -// CHECK-NEXT: |-TemplateArgument type 'type-parameter-0-1' -// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1' dependent depth 0 index 1 -// CHECK-NEXT: `-TemplateArgument expr 'N' -// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'T' <Dependent> -// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int' +// CHECK-NEXT: `-TemplateArgument expr 'N' +// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent> +// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int' using test4 = __make_integer_seq<A, T, 1>; -// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:43> col:9 test4 '__make_integer_seq<A, T, 1>':'__make_integer_seq<A, type-parameter-0-1, 1>' +// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:43> col:9 test4 '__make_integer_seq<A, T, 1>' // CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, T, 1>' sugar dependent -// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, T, 1>' sugar dependent alias -// CHECK-NEXT: |-name: '__make_integer_seq' qualified +// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, T, 1>' dependent +// CHECK-NEXT: |-name: '__make_integer_seq' // CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq // CHECK-NEXT: |-TemplateArgument template 'A' // CHECK-NEXT: | `-ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:1, col:41> col:38 A // CHECK-NEXT: |-TemplateArgument type 'T' // CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'T' dependent depth 0 index 1 // CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'T' -// CHECK-NEXT: |-TemplateArgument expr '1' -// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent> -// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 1 -// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, type-parameter-0-1, 1>' dependent -// CHECK-NEXT: |-name: '__make_integer_seq' -// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq -// CHECK-NEXT: |-TemplateArgument template 'A' -// CHECK-NEXT: | `-ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:1, col:41> col:38 A -// CHECK-NEXT: |-TemplateArgument type 'type-parameter-0-1' -// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1' dependent depth 0 index 1 -// CHECK-NEXT: `-TemplateArgument expr '1' -// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent> -// CHECK-NEXT: `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 1 +// CHECK-NEXT: `-TemplateArgument expr '1' +// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent> +// CHECK-NEXT: `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 1 using test5 = __make_integer_seq<A, int, N>; // CHECK: `-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:45> col:9 test5 '__make_integer_seq<A, int, N>' // CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' sugar dependent -// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' sugar dependent alias -// CHECK-NEXT: |-name: '__make_integer_seq' qualified +// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' dependent +// CHECK-NEXT: |-name: '__make_integer_seq' // CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq // CHECK-NEXT: |-TemplateArgument template 'A' // CHECK-NEXT: | `-ClassTemplateDecl 0x{{.+}} <line:{{.+}}:1, col:41> col:38 A // CHECK-NEXT: |-TemplateArgument type 'int' // CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int' -// CHECK-NEXT: |-TemplateArgument expr 'N' -// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:44> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int' -// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' dependent -// CHECK-NEXT: |-name: '__make_integer_seq' -// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq -// CHECK-NEXT: |-TemplateArgument template 'A' -// CHECK-NEXT: | `-ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:1, col:41> col:38 A -// CHECK-NEXT: |-TemplateArgument type 'int' -// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int' -// CHECK-NEXT: `-TemplateArgument expr 'N' -// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:44> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int' +// CHECK-NEXT: `-TemplateArgument expr 'N' +// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:44> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int' }; // expected-no-diagnostics diff --git a/clang/test/SemaTemplate/type_pack_element.cpp b/clang/test/SemaTemplate/type_pack_element.cpp index e08a4a6ee6c5a..264b4dcdc044d 100644 --- a/clang/test/SemaTemplate/type_pack_element.cpp +++ b/clang/test/SemaTemplate/type_pack_element.cpp @@ -17,33 +17,23 @@ using test1 = __type_pack_element<0, int>; template<int N, class ...Ts> struct A { using test2 = __type_pack_element<N, Ts...>; -// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:45> col:9 test2 '__type_pack_element<N, Ts...>':'__type_pack_element<N, type-parameter-0-1...>' +// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:45> col:9 test2 '__type_pack_element<N, Ts...>' // CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, Ts...>' sugar dependent -// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, Ts...>' sugar dependent alias +// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, Ts...>' dependent // CHECK-NEXT: |-name: '__type_pack_element' qualified // CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element // CHECK-NEXT: |-TemplateArgument expr 'N' // CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast> // CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int' -// CHECK-NEXT: |-TemplateArgument type 'Ts...' -// CHECK-NEXT: | `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent -// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack -// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'Ts' -// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, type-parameter-0-1...>' dependent -// CHECK-NEXT: |-name: '__type_pack_element' -// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element -// CHECK-NEXT: |-TemplateArgument expr 'N' -// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast> -// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int' -// CHECK-NEXT: `-TemplateArgument pack '<type-parameter-0-1...>' -// CHECK-NEXT: `-TemplateArgument type 'type-parameter-0-1...' -// CHECK-NEXT: `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1...' dependent -// CHECK-NEXT: `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1' dependent contains_unexpanded_pack depth 0 index 1 pack +// CHECK-NEXT: `-TemplateArgument type 'Ts...' +// CHECK-NEXT: `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent +// CHECK-NEXT: `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack +// CHECK-NEXT: `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'Ts' using test3 = __type_pack_element<0, Ts...>; -// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:45> col:9 test3 '__type_pack_element<0, Ts...>':'__type_pack_element<0, type-parameter-0-1...>' +// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:45> col:9 test3 '__type_pack_element<0, Ts...>' // CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, Ts...>' sugar dependent -// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, Ts...>' sugar dependent alias +// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, Ts...>' dependent // CHECK-NEXT: |-name: '__type_pack_element' qualified // CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element // CHECK-NEXT: |-TemplateArgument expr '0' @@ -51,39 +41,22 @@ template<int N, class ...Ts> struct A { // CHECK-NEXT: | |-value: Int 0 // CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast> // CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:37> 'int' 0 -// CHECK-NEXT: |-TemplateArgument type 'Ts...' -// CHECK-NEXT: | `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent -// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack -// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'Ts' -// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, type-parameter-0-1...>' dependent -// CHECK-NEXT: |-name: '__type_pack_element' -// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element -// CHECK-NEXT: |-TemplateArgument integral '0UL' -// CHECK-NEXT: `-TemplateArgument pack '<type-parameter-0-1...>' -// CHECK-NEXT: `-TemplateArgument type 'type-parameter-0-1...' -// CHECK-NEXT: `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1...' dependent -// CHECK-NEXT: `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1' dependent contains_unexpanded_pack depth 0 index 1 pack +// CHECK-NEXT: `-TemplateArgument type 'Ts...' +// CHECK-NEXT: `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent +// CHECK-NEXT: `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack +// CHECK-NEXT: `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'Ts' using test4 = __type_pack_element<N, int>; // CHECK: `-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:43> col:9 test4 '__type_pack_element<N, int>' // CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, int>' sugar dependent -// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, int>' sugar dependent alias +// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, int>' dependent // CHECK-NEXT: |-name: '__type_pack_element' qualified // CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element // CHECK-NEXT: |-TemplateArgument expr 'N' // CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast> // CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int' -// CHECK-NEXT: |-TemplateArgument type 'int' -// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int' -// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, int>' dependent -// CHECK-NEXT: |-name: '__type_pack_element' -// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element -// CHECK-NEXT: |-TemplateArgument expr 'N' -// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast> -// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int' -// CHECK-NEXT: `-TemplateArgument pack '<int>' -// CHECK-NEXT: `-TemplateArgument type 'int' -// CHECK-NEXT: `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int' +// CHECK-NEXT: `-TemplateArgument type 'int' +// CHECK-NEXT: `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int' }; // expected-no-diagnostics diff --git a/clang/unittests/AST/TypePrinterTest.cpp b/clang/unittests/AST/TypePrinterTest.cpp index 494085a2ebca6..dd6df43864481 100644 --- a/clang/unittests/AST/TypePrinterTest.cpp +++ b/clang/unittests/AST/TypePrinterTest.cpp @@ -257,7 +257,7 @@ TEST(TypePrinter, TemplateArgumentsSubstitution_Expressions) { const int Result = 42; auto *ConstExpr = createBinOpExpr(LHS, RHS, Result); // Arg is instantiated with '40 + 2' - TemplateArgument Arg(ConstExpr); + TemplateArgument Arg(ConstExpr, /*IsCanonical=*/false); // Param has default expr of '42' auto const *Param = Params->getParam(1); @@ -273,7 +273,7 @@ TEST(TypePrinter, TemplateArgumentsSubstitution_Expressions) { auto *ConstExpr = createBinOpExpr(LHS, RHS, Result); // Arg is instantiated with '40 + 1' - TemplateArgument Arg(ConstExpr); + TemplateArgument Arg(ConstExpr, /*IsCanonical=*/false); // Param has default expr of '42' auto const *Param = Params->getParam(1); @@ -289,7 +289,7 @@ TEST(TypePrinter, TemplateArgumentsSubstitution_Expressions) { auto *ConstExpr = createBinOpExpr(LHS, RHS, Result); // Arg is instantiated with '4 + 0' - TemplateArgument Arg(ConstExpr); + TemplateArgument Arg(ConstExpr, /*IsCanonical=*/false); // Param has is value-dependent expression (i.e., sizeof(T)) auto const *Param = Params->getParam(3); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits