Reland: [clang] Improved canonicalization for template specialization types (#135414)

This relands https://github.com/llvm/llvm-project/pull/135119, after
fixing crashes seen in LLDB CI reported here:
https://github.com/llvm/llvm-project/pull/135119#issuecomment-2794910840

Fixes https://github.com/llvm/llvm-project/pull/135119

This changes the TemplateArgument representation to hold a flag
indicating whether a tempalte argument of expression type is supposed to
be canonical or not.

This gets one step closer to solving
https://github.com/llvm/llvm-project/issues/92292

This still doesn't try to unique as-written TSTs. While this would
increase the amount of memory savings and make code dealing with the AST
more well-behaved, profiling template argument lists is still too
expensive for this to be worthwhile, at least for now.

This also fixes the context creation of TSTs, so that they don't in some
cases get incorrectly flagged as sugar over their own canonical form.
This is captured in the test expectation change of some AST dumps.

This fixes some places which were unnecessarily canonicalizing these
TSTs.
This commit is contained in:
Matheus Izvekov 2025-04-12 14:26:30 -03:00 committed by GitHub
parent 009971a0d3
commit 761787d425
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 515 additions and 501 deletions

View File

@ -439,7 +439,8 @@ QualType declaredType(const TypeDecl *D) {
if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D)) if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D))
if (const auto *Args = CTSD->getTemplateArgsAsWritten()) if (const auto *Args = CTSD->getTemplateArgsAsWritten())
return Context.getTemplateSpecializationType( return Context.getTemplateSpecializationType(
TemplateName(CTSD->getSpecializedTemplate()), Args->arguments()); TemplateName(CTSD->getSpecializedTemplate()), Args->arguments(),
/*CanonicalArgs=*/std::nullopt);
return Context.getTypeDeclType(D); return Context.getTypeDeclType(D);
} }

View File

@ -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 sugared types of pointers to member.
- Clang now better preserves the presence of the template keyword with dependent - Clang now better preserves the presence of the template keyword with dependent
prefixes. 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 - Clang now respects the current language mode when printing expressions in
diagnostics. This fixes a bunch of `bool` being printed as `_Bool`, and also diagnostics. This fixes a bunch of `bool` being printed as `_Bool`, and also
a bunch of HLSL types being printed as their C++ equivalents. a bunch of HLSL types being printed as their C++ equivalents.

View File

@ -243,8 +243,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<PackExpansionType> PackExpansionTypes; mutable llvm::FoldingSet<PackExpansionType> PackExpansionTypes;
mutable llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes; mutable llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes;
mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes; mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
mutable llvm::FoldingSet<DependentUnaryTransformType> mutable llvm::FoldingSet<UnaryTransformType> UnaryTransformTypes;
DependentUnaryTransformTypes;
// An AutoType can have a dependency on another AutoType via its template // An AutoType can have a dependency on another AutoType via its template
// arguments. Since both dependent and dependency are on the same set, // 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 // we can end up in an infinite recursion when looking for a node if we used
@ -367,9 +366,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
const ASTContext&> const ASTContext&>
CanonTemplateTemplateParms; CanonTemplateTemplateParms;
TemplateTemplateParmDecl *
getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const;
/// The typedef for the __int128_t type. /// The typedef for the __int128_t type.
mutable TypedefDecl *Int128Decl = nullptr; mutable TypedefDecl *Int128Decl = nullptr;
@ -1811,22 +1807,26 @@ public:
bool ParameterPack, bool ParameterPack,
TemplateTypeParmDecl *ParmDecl = nullptr) const; TemplateTypeParmDecl *ParmDecl = nullptr) const;
QualType getTemplateSpecializationType(TemplateName T, QualType getCanonicalTemplateSpecializationType(
ArrayRef<TemplateArgument> Args, TemplateName T, ArrayRef<TemplateArgument> CanonicalArgs) const;
QualType Canon = QualType()) const;
QualType QualType
getCanonicalTemplateSpecializationType(TemplateName T, getTemplateSpecializationType(TemplateName T,
ArrayRef<TemplateArgument> Args) const; ArrayRef<TemplateArgument> SpecifiedArgs,
ArrayRef<TemplateArgument> CanonicalArgs,
QualType Underlying = QualType()) const;
QualType getTemplateSpecializationType(TemplateName T, QualType
ArrayRef<TemplateArgumentLoc> Args, getTemplateSpecializationType(TemplateName T,
QualType Canon = QualType()) const; ArrayRef<TemplateArgumentLoc> SpecifiedArgs,
ArrayRef<TemplateArgument> CanonicalArgs,
QualType Canon = QualType()) const;
TypeSourceInfo * TypeSourceInfo *getTemplateSpecializationTypeInfo(
getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc, TemplateName T, SourceLocation TLoc,
const TemplateArgumentListInfo &Args, const TemplateArgumentListInfo &SpecifiedArgs,
QualType Canon = QualType()) const; ArrayRef<TemplateArgument> CanonicalArgs,
QualType Canon = QualType()) const;
QualType getParenType(QualType NamedType) const; QualType getParenType(QualType NamedType) const;
@ -2942,6 +2942,21 @@ public:
TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg) TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg)
const; 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, /// Type Query functions. If the type is an instance of the specified class,
/// return the Type pointer for the underlying maximally pretty type. This /// 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 /// is a member of ASTContext because this may need to do some amount of

View File

@ -877,11 +877,14 @@ let Class = PropertyTypeCase<TemplateArgument, "Expression"> in {
def : Property<"expression", ExprRef> { def : Property<"expression", ExprRef> {
let Read = [{ node.getAsExpr() }]; let Read = [{ node.getAsExpr() }];
} }
def : Property<"IsCanonical", Bool> {
let Read = [{ node.isCanonicalExpr() }];
}
def : Property<"isDefaulted", Bool> { def : Property<"isDefaulted", Bool> {
let Read = [{ node.getIsDefaulted() }]; let Read = [{ node.getIsDefaulted() }];
} }
def : Creator<[{ def : Creator<[{
return TemplateArgument(expression, isDefaulted); return TemplateArgument(expression, IsCanonical, isDefaulted);
}]>; }]>;
} }
let Class = PropertyTypeCase<TemplateArgument, "Pack"> in { let Class = PropertyTypeCase<TemplateArgument, "Pack"> in {

View File

@ -167,6 +167,8 @@ private:
unsigned Kind : 31; unsigned Kind : 31;
LLVM_PREFERRED_TYPE(bool) LLVM_PREFERRED_TYPE(bool)
unsigned IsDefaulted : 1; unsigned IsDefaulted : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IsCanonicalExpr : 1;
uintptr_t V; uintptr_t V;
}; };
union { union {
@ -187,7 +189,8 @@ private:
public: public:
/// Construct an empty, invalid template argument. /// 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. /// Construct a template type argument.
TemplateArgument(QualType T, bool isNullPtr = false, TemplateArgument(QualType T, bool isNullPtr = false,
@ -262,9 +265,10 @@ public:
/// This form of template argument only occurs in template argument /// This form of template argument only occurs in template argument
/// lists used for dependent types and for expression; it will not /// lists used for dependent types and for expression; it will not
/// occur in a non-dependent, canonical template argument list. /// 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.Kind = Expression;
TypeOrValue.IsDefaulted = IsDefaulted; TypeOrValue.IsDefaulted = IsDefaulted;
TypeOrValue.IsCanonicalExpr = IsCanonical;
TypeOrValue.V = reinterpret_cast<uintptr_t>(E); TypeOrValue.V = reinterpret_cast<uintptr_t>(E);
} }
@ -407,6 +411,11 @@ public:
return reinterpret_cast<Expr *>(TypeOrValue.V); 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. /// Iterator that traverses the elements of a template argument pack.
using pack_iterator = const TemplateArgument *; using pack_iterator = const TemplateArgument *;

View File

@ -5918,7 +5918,7 @@ public:
/// of this class via DecltypeType nodes. /// of this class via DecltypeType nodes.
class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode { class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode {
public: public:
DependentDecltypeType(Expr *E, QualType UnderlyingTpe); DependentDecltypeType(Expr *E);
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
Profile(ID, Context, getUnderlyingExpr()); Profile(ID, Context, getUnderlyingExpr());
@ -6003,7 +6003,7 @@ private:
}; };
/// A unary type transform, which is a type constructed from another. /// A unary type transform, which is a type constructed from another.
class UnaryTransformType : public Type { class UnaryTransformType : public Type, public llvm::FoldingSetNode {
public: public:
enum UTTKind { enum UTTKind {
#define TRANSFORM_TYPE_TRAIT_DEF(Enum, _) Enum, #define TRANSFORM_TYPE_TRAIT_DEF(Enum, _) Enum,
@ -6037,28 +6037,16 @@ public:
static bool classof(const Type *T) { static bool classof(const Type *T) {
return T->getTypeClass() == UnaryTransform; 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) { void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getBaseType(), getUTTKind()); Profile(ID, getBaseType(), getUnderlyingType(), getUTTKind());
} }
static void Profile(llvm::FoldingSetNodeID &ID, QualType BaseType, static void Profile(llvm::FoldingSetNodeID &ID, QualType BaseType,
UTTKind UKind) { QualType UnderlyingType, UTTKind UKind) {
ID.AddPointer(BaseType.getAsOpaquePtr()); BaseType.Profile(ID);
ID.AddInteger((unsigned)UKind); UnderlyingType.Profile(ID);
ID.AddInteger(UKind);
} }
}; };
@ -6676,10 +6664,9 @@ class TemplateSpecializationType : public Type, public llvm::FoldingSetNode {
/// replacement must, recursively, be one of these). /// replacement must, recursively, be one of these).
TemplateName Template; TemplateName Template;
TemplateSpecializationType(TemplateName T, TemplateSpecializationType(TemplateName T, bool IsAlias,
ArrayRef<TemplateArgument> Args, ArrayRef<TemplateArgument> Args,
QualType Canon, QualType Underlying);
QualType Aliased);
public: public:
/// Determine whether any of the given template arguments are dependent. /// Determine whether any of the given template arguments are dependent.
@ -6747,7 +6734,7 @@ public:
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx); void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx);
static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T,
ArrayRef<TemplateArgument> Args, ArrayRef<TemplateArgument> Args, QualType Underlying,
const ASTContext &Context); const ASTContext &Context);
static bool classof(const Type *T) { static bool classof(const Type *T) {

View File

@ -737,39 +737,19 @@ let Class = DependentAddressSpaceType in {
} }
let Class = TemplateSpecializationType in { let Class = TemplateSpecializationType in {
def : Property<"dependent", Bool> {
let Read = [{ node->isDependentType() }];
}
def : Property<"templateName", TemplateName> { def : Property<"templateName", TemplateName> {
let Read = [{ node->getTemplateName() }]; let Read = [{ node->getTemplateName() }];
} }
def : Property<"templateArguments", Array<TemplateArgument>> { def : Property<"args", Array<TemplateArgument>> {
let Read = [{ node->template_arguments() }]; let Read = [{ node->template_arguments() }];
} }
def : Property<"underlyingType", Optional<QualType>> { def : Property<"UnderlyingType", QualType> {
let Read = [{ let Read = [{ node->isCanonicalUnqualified() ? QualType() :
node->isTypeAlias() node->desugar() }];
? std::optional<QualType>(node->getAliasedType())
: node->isCanonicalUnqualified()
? std::nullopt
: std::optional<QualType>(node->getCanonicalTypeInternal())
}];
} }
def : Creator<[{ def : Creator<[{
QualType result; return ctx.getTemplateSpecializationType(templateName, args, std::nullopt, UnderlyingType);
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;
}]>; }]>;
} }

View File

@ -844,6 +844,31 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
return CanonTTP; 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 /// Check if a type can have its sanitizer instrumentation elided based on its
/// presence within an ignorelist. /// presence within an ignorelist.
bool ASTContext::isTypeIgnoredBySanitizer(const SanitizerMask &Mask, bool ASTContext::isTypeIgnoredBySanitizer(const SanitizerMask &Mask,
@ -3083,12 +3108,19 @@ static auto getCanonicalTemplateArguments(const ASTContext &C,
ArrayRef<TemplateArgument> Args, ArrayRef<TemplateArgument> Args,
bool &AnyNonCanonArgs) { bool &AnyNonCanonArgs) {
SmallVector<TemplateArgument, 16> CanonArgs(Args); 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; TemplateArgument OrigArg = Arg;
Arg = C.getCanonicalTemplateArgument(Arg); Arg = getCanonicalTemplateArgument(Arg);
AnyNonCanonArgs |= !Arg.structurallyEquals(OrigArg); AnyNonCanonArgs |= !Arg.structurallyEquals(OrigArg);
} }
return CanonArgs; return AnyNonCanonArgs;
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -5538,129 +5570,118 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
return QualType(TypeParm, 0); return QualType(TypeParm, 0);
} }
TypeSourceInfo * TypeSourceInfo *ASTContext::getTemplateSpecializationTypeInfo(
ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, TemplateName Name, SourceLocation NameLoc,
SourceLocation NameLoc, const TemplateArgumentListInfo &SpecifiedArgs,
const TemplateArgumentListInfo &Args, ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying) const {
QualType Underlying) const { QualType TST = getTemplateSpecializationType(Name, SpecifiedArgs.arguments(),
assert(!Name.getAsDependentTemplateName() && CanonicalArgs, Underlying);
"No dependent template names here!");
QualType TST =
getTemplateSpecializationType(Name, Args.arguments(), Underlying);
TypeSourceInfo *DI = CreateTypeSourceInfo(TST); TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
TemplateSpecializationTypeLoc TL = TemplateSpecializationTypeLoc TL =
DI->getTypeLoc().castAs<TemplateSpecializationTypeLoc>(); DI->getTypeLoc().castAs<TemplateSpecializationTypeLoc>();
TL.setTemplateKeywordLoc(SourceLocation()); TL.setTemplateKeywordLoc(SourceLocation());
TL.setTemplateNameLoc(NameLoc); TL.setTemplateNameLoc(NameLoc);
TL.setLAngleLoc(Args.getLAngleLoc()); TL.setLAngleLoc(SpecifiedArgs.getLAngleLoc());
TL.setRAngleLoc(Args.getRAngleLoc()); TL.setRAngleLoc(SpecifiedArgs.getRAngleLoc());
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
TL.setArgLocInfo(i, Args[i].getLocInfo()); TL.setArgLocInfo(i, SpecifiedArgs[i].getLocInfo());
return DI; return DI;
} }
QualType QualType ASTContext::getTemplateSpecializationType(
ASTContext::getTemplateSpecializationType(TemplateName Template, TemplateName Template, ArrayRef<TemplateArgumentLoc> SpecifiedArgs,
ArrayRef<TemplateArgumentLoc> Args, ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying) const {
QualType Underlying) const { SmallVector<TemplateArgument, 4> SpecifiedArgVec;
assert(!Template.getAsDependentTemplateName() && SpecifiedArgVec.reserve(SpecifiedArgs.size());
"No dependent template names here!"); for (const TemplateArgumentLoc &Arg : SpecifiedArgs)
SpecifiedArgVec.push_back(Arg.getArgument());
SmallVector<TemplateArgument, 4> ArgVec; return getTemplateSpecializationType(Template, SpecifiedArgVec, CanonicalArgs,
ArgVec.reserve(Args.size()); Underlying);
for (const TemplateArgumentLoc &Arg : Args)
ArgVec.push_back(Arg.getArgument());
return getTemplateSpecializationType(Template, ArgVec, Underlying);
} }
#ifndef NDEBUG [[maybe_unused]] static bool
static bool hasAnyPackExpansions(ArrayRef<TemplateArgument> Args) { hasAnyPackExpansions(ArrayRef<TemplateArgument> Args) {
for (const TemplateArgument &Arg : Args) for (const TemplateArgument &Arg : Args)
if (Arg.isPackExpansion()) if (Arg.isPackExpansion())
return true; return true;
return false;
return true;
}
#endif
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
ArrayRef<TemplateArgument> 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);
} }
QualType ASTContext::getCanonicalTemplateSpecializationType( QualType ASTContext::getCanonicalTemplateSpecializationType(
TemplateName Template, ArrayRef<TemplateArgument> Args) const { TemplateName Template, ArrayRef<TemplateArgument> 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<TemplateArgument> SpecifiedArgs,
ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying) const {
assert(!Template.getUnderlying().getAsDependentTemplateName() &&
"No dependent template names here!"); "No dependent template names here!");
// Build the canonical template specialization type. const auto *TD = Template.getAsTemplateDecl(/*IgnoreDeduced=*/true);
// Any DeducedTemplateNames are ignored, because the effective name of a TST bool IsTypeAlias = TD && TD->isTypeAlias();
// accounts for the TST arguments laid over any default arguments contained in if (Underlying.isNull()) {
// its name. TemplateName CanonTemplate =
TemplateName CanonTemplate = getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true);
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);
});
}
bool AnyNonCanonArgs = false; // We can get here with an alias template when the specialization
auto CanonArgs = // contains a pack expansion that does not match up with a parameter
::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs); // 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;
// Determine whether this canonical template specialization type already Underlying =
// exists. getCanonicalTemplateSpecializationType(CanonTemplate, CanonicalArgs);
llvm::FoldingSetNodeID ID; if (!NonCanonical)
TemplateSpecializationType::Profile(ID, CanonTemplate, return Underlying;
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);
} }
void *Mem = Allocate(sizeof(TemplateSpecializationType) +
assert(Spec->isDependentType() && sizeof(TemplateArgument) * SpecifiedArgs.size() +
"Non-dependent template-id type must have a canonical type"); (IsTypeAlias ? sizeof(QualType) : 0),
alignof(TemplateSpecializationType));
auto *Spec = new (Mem) TemplateSpecializationType(Template, IsTypeAlias,
SpecifiedArgs, Underlying);
Types.push_back(Spec);
return QualType(Spec, 0); return QualType(Spec, 0);
} }
@ -5853,7 +5874,7 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) const {
if (NTTP->isParameterPack()) if (NTTP->isParameterPack())
E = new (*this) PackExpansionExpr(E, NTTP->getLocation(), std::nullopt); E = new (*this) PackExpansionExpr(E, NTTP->getLocation(), std::nullopt);
Arg = TemplateArgument(E); Arg = TemplateArgument(E, /*IsCanonical=*/false);
} else { } else {
auto *TTP = cast<TemplateTemplateParmDecl>(Param); auto *TTP = cast<TemplateTemplateParmDecl>(Param);
TemplateName Name = getQualifiedTemplateName( 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 /// nodes. This would never be helpful, since each such type has its own
/// expression, and would not give a significant memory saving, since there /// expression, and would not give a significant memory saving, since there
/// is an Expr tree under each such type. /// is an Expr tree under each such type.
QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType) const { QualType ASTContext::getDecltypeType(Expr *E, QualType UnderlyingType) const {
DecltypeType *dt;
// C++11 [temp.type]p2: // C++11 [temp.type]p2:
// If an expression e involves a template parameter, decltype(e) denotes a // If an expression e involves a template parameter, decltype(e) denotes a
// unique dependent type. Two such decltype-specifiers refer to the same // unique dependent type. Two such decltype-specifiers refer to the same
// type only if their expressions are equivalent (14.5.6.1). // 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; llvm::FoldingSetNodeID ID;
DependentDecltypeType::Profile(ID, *this, e); DependentDecltypeType::Profile(ID, *this, E);
void *InsertPos = nullptr; void *InsertPos = nullptr;
DependentDecltypeType *Canon if (DependentDecltypeType *Canon =
= DependentDecltypeTypes.FindNodeOrInsertPos(ID, InsertPos); DependentDecltypeTypes.FindNodeOrInsertPos(ID, InsertPos))
if (!Canon) { return QualType(Canon, 0);
// Build a new, canonical decltype(expr) type.
Canon = new (*this, alignof(DependentDecltypeType)) // Build a new, canonical decltype(expr) type.
DependentDecltypeType(e, DependentTy); auto *DT =
DependentDecltypeTypes.InsertNode(Canon, InsertPos); new (*this, alignof(DependentDecltypeType)) DependentDecltypeType(E);
} DependentDecltypeTypes.InsertNode(DT, InsertPos);
dt = new (*this, alignof(DecltypeType)) Types.push_back(DT);
DecltypeType(e, UnderlyingType, QualType((DecltypeType *)Canon, 0)); return QualType(DT, 0);
} else {
dt = new (*this, alignof(DecltypeType))
DecltypeType(e, UnderlyingType, getCanonicalType(UnderlyingType));
} }
Types.push_back(dt); auto *DT = new (*this, alignof(DecltypeType))
return QualType(dt, 0); DecltypeType(E, UnderlyingType, CanonType);
Types.push_back(DT);
return QualType(DT, 0);
} }
QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr, 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 /// getUnaryTransformationType - We don't unique these, since the memory
/// savings are minimal and these are rare. /// savings are minimal and these are rare.
QualType ASTContext::getUnaryTransformType(QualType BaseType, QualType
QualType UnderlyingType, ASTContext::getUnaryTransformType(QualType BaseType, QualType UnderlyingType,
UnaryTransformType::UTTKind Kind) UnaryTransformType::UTTKind Kind) const {
const {
UnaryTransformType *ut = nullptr;
if (BaseType->isDependentType()) { llvm::FoldingSetNodeID ID;
// Look in the folding set for an existing type. UnaryTransformType::Profile(ID, BaseType, UnderlyingType, Kind);
llvm::FoldingSetNodeID ID;
DependentUnaryTransformType::Profile(ID, getCanonicalType(BaseType), Kind);
void *InsertPos = nullptr; void *InsertPos = nullptr;
DependentUnaryTransformType *Canon if (UnaryTransformType *UT =
= DependentUnaryTransformTypes.FindNodeOrInsertPos(ID, InsertPos); UnaryTransformTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(UT, 0);
if (!Canon) { QualType CanonType;
// Build a new, canonical __underlying_type(type) type. if (!BaseType->isDependentType()) {
Canon = new (*this, alignof(DependentUnaryTransformType)) CanonType = UnderlyingType.getCanonicalType();
DependentUnaryTransformType(*this, getCanonicalType(BaseType), Kind);
DependentUnaryTransformTypes.InsertNode(Canon, InsertPos);
}
ut = new (*this, alignof(UnaryTransformType))
UnaryTransformType(BaseType, QualType(), Kind, QualType(Canon, 0));
} else { } else {
QualType CanonType = getCanonicalType(UnderlyingType); assert(UnderlyingType.isNull() || BaseType == UnderlyingType);
ut = new (*this, alignof(UnaryTransformType)) UnderlyingType = QualType();
UnaryTransformType(BaseType, UnderlyingType, Kind, CanonType); 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( QualType ASTContext::getAutoTypeInternal(
@ -6461,9 +6489,9 @@ QualType ASTContext::getAutoTypeInternal(
auto CanonicalConceptArgs = ::getCanonicalTemplateArguments( auto CanonicalConceptArgs = ::getCanonicalTemplateArguments(
*this, TypeConstraintArgs, AnyNonCanonArgs); *this, TypeConstraintArgs, AnyNonCanonArgs);
if (CanonicalConcept != TypeConstraintConcept || AnyNonCanonArgs) { if (CanonicalConcept != TypeConstraintConcept || AnyNonCanonArgs) {
Canon = Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack,
getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack, CanonicalConcept, CanonicalConceptArgs,
CanonicalConcept, CanonicalConceptArgs, true); /*IsCanon=*/true);
} }
} }
} }
@ -7543,7 +7571,8 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
return Arg; return Arg;
case TemplateArgument::Expression: case TemplateArgument::Expression:
return Arg; return TemplateArgument(Arg.getAsExpr(), /*IsCanonical=*/true,
Arg.getIsDefaulted());
case TemplateArgument::Declaration: { case TemplateArgument::Declaration: {
auto *D = cast<ValueDecl>(Arg.getAsDecl()->getCanonicalDecl()); auto *D = cast<ValueDecl>(Arg.getAsDecl()->getCanonicalDecl());
@ -8199,8 +8228,7 @@ QualType ASTContext::getObjCSuperType() const {
void ASTContext::setCFConstantStringType(QualType T) { void ASTContext::setCFConstantStringType(QualType T) {
const auto *TD = T->castAs<TypedefType>(); const auto *TD = T->castAs<TypedefType>();
CFConstantStringTypeDecl = cast<TypedefDecl>(TD->getDecl()); CFConstantStringTypeDecl = cast<TypedefDecl>(TD->getDecl());
const auto *TagType = const auto *TagType = TD->castAs<RecordType>();
CFConstantStringTypeDecl->getUnderlyingType()->castAs<RecordType>();
CFConstantStringTagDecl = TagType->getDecl(); CFConstantStringTagDecl = TagType->getDecl();
} }
@ -14012,7 +14040,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(), ::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(),
TY->getTemplateName(), TY->getTemplateName(),
/*IgnoreDeduced=*/true), /*IgnoreDeduced=*/true),
As, X->getCanonicalTypeInternal()); As, /*CanonicalArgs=*/std::nullopt, X->getCanonicalTypeInternal());
} }
case Type::Decltype: { case Type::Decltype: {
const auto *DX = cast<DecltypeType>(X); const auto *DX = cast<DecltypeType>(X);
@ -14252,11 +14280,12 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
TY->getTemplateName(), /*IgnoreDeduced=*/true); TY->getTemplateName(), /*IgnoreDeduced=*/true);
if (!CTN.getAsVoidPointer()) if (!CTN.getAsVoidPointer())
return QualType(); return QualType();
SmallVector<TemplateArgument, 8> Args; SmallVector<TemplateArgument, 8> As;
if (getCommonTemplateArguments(Ctx, Args, TX->template_arguments(), if (getCommonTemplateArguments(Ctx, As, TX->template_arguments(),
TY->template_arguments())) TY->template_arguments()))
return QualType(); return QualType();
return Ctx.getTemplateSpecializationType(CTN, Args, return Ctx.getTemplateSpecializationType(CTN, As,
/*CanonicalArgs=*/std::nullopt,
Ctx.getQualifiedType(Underlying)); Ctx.getQualifiedType(Underlying));
} }
case Type::Typedef: { case Type::Typedef: {

View File

@ -128,7 +128,7 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT,
if (DesugarArgument) { if (DesugarArgument) {
ShouldAKA = true; ShouldAKA = true;
QT = Context.getTemplateSpecializationType( QT = Context.getTemplateSpecializationType(
TST->getTemplateName(), Args, QT); TST->getTemplateName(), Args, /*CanonicalArgs=*/std::nullopt, QT);
} }
break; break;
} }
@ -1142,9 +1142,9 @@ class TemplateDiff {
return nullptr; return nullptr;
Ty = Context.getTemplateSpecializationType( Ty = Context.getTemplateSpecializationType(
TemplateName(CTSD->getSpecializedTemplate()), TemplateName(CTSD->getSpecializedTemplate()),
CTSD->getTemplateArgs().asArray(), CTSD->getTemplateArgs().asArray(), /*CanonicalArgs=*/std::nullopt,
Ty.getLocalUnqualifiedType().getCanonicalType()); Ty.getLocalUnqualifiedType().getCanonicalType());
return Ty->getAs<TemplateSpecializationType>(); return Ty->getAs<TemplateSpecializationType>();
} }

View File

@ -893,7 +893,8 @@ ASTNodeImporter::import(const TemplateArgument &From) {
case TemplateArgument::Expression: case TemplateArgument::Expression:
if (ExpectedExpr ToExpr = import(From.getAsExpr())) if (ExpectedExpr ToExpr = import(From.getAsExpr()))
return TemplateArgument(*ToExpr, From.getIsDefaulted()); return TemplateArgument(*ToExpr, From.isCanonicalExpr(),
From.getIsDefaulted());
else else
return ToExpr.takeError(); return ToExpr.takeError();
@ -1660,18 +1661,12 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType(
ImportTemplateArguments(T->template_arguments(), ToTemplateArgs)) ImportTemplateArguments(T->template_arguments(), ToTemplateArgs))
return std::move(Err); return std::move(Err);
QualType ToCanonType; ExpectedType ToUnderlyingOrErr =
if (!T->isCanonicalUnqualified()) { T->isCanonicalUnqualified() ? QualType() : import(T->desugar());
QualType FromCanonType if (!ToUnderlyingOrErr)
= Importer.getFromContext().getCanonicalType(QualType(T, 0)); return ToUnderlyingOrErr.takeError();
if (ExpectedType TyOrErr = import(FromCanonType)) return Importer.getToContext().getTemplateSpecializationType(
ToCanonType = *TyOrErr; *ToTemplateOrErr, ToTemplateArgs, std::nullopt, *ToUnderlyingOrErr);
else
return TyOrErr.takeError();
}
return Importer.getToContext().getTemplateSpecializationType(*ToTemplateOrErr,
ToTemplateArgs,
ToCanonType);
} }
ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) {
@ -6018,6 +6013,12 @@ ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
ExpectedDecl ExpectedDecl
ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
bool IsCanonical = false;
if (auto *CanonD = Importer.getFromContext()
.findCanonicalTemplateTemplateParmDeclInternal(D);
CanonD == D)
IsCanonical = true;
// Import the name of this declaration. // Import the name of this declaration.
auto NameOrErr = import(D->getDeclName()); auto NameOrErr = import(D->getDeclName());
if (!NameOrErr) if (!NameOrErr)
@ -6045,6 +6046,10 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
if (Error Err = importTemplateParameterDefaultArgument(D, ToD)) if (Error Err = importTemplateParameterDefaultArgument(D, ToD))
return Err; return Err;
if (IsCanonical)
return Importer.getToContext()
.insertCanonicalTemplateTemplateParmDeclInternal(ToD);
return ToD; return ToD;
} }

View File

@ -580,7 +580,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const DependentTemplateStorage &S1, const DependentTemplateStorage &S1,
const DependentTemplateStorage &S2) { 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; return false;
IdentifierOrOverloadedOperator IO1 = S1.getName(), IO2 = S2.getName(); IdentifierOrOverloadedOperator IO1 = S1.getName(), IO2 = S2.getName();

View File

@ -671,8 +671,11 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
ASTContext &Context = getASTContext(); ASTContext &Context = getASTContext();
TemplateName Name = Context.getQualifiedTemplateName( TemplateName Name = Context.getQualifiedTemplateName(
/*NNS=*/nullptr, /*TemplateKeyword=*/false, TemplateName(this)); /*NNS=*/nullptr, /*TemplateKeyword=*/false, TemplateName(this));
CommonPtr->InjectedClassNameType = Context.getTemplateSpecializationType( auto TemplateArgs = getTemplateParameters()->getInjectedTemplateArgs(Context);
Name, getTemplateParameters()->getInjectedTemplateArgs(Context)); CommonPtr->InjectedClassNameType =
Context.getTemplateSpecializationType(Name,
/*SpecifiedArgs=*/TemplateArgs,
/*CanonicalArgs=*/std::nullopt);
return CommonPtr->InjectedClassNameType; return CommonPtr->InjectedClassNameType;
} }

View File

@ -140,7 +140,7 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
if (MightHaveChanged) { if (MightHaveChanged) {
QualType QT = Ctx.getTemplateSpecializationType( QualType QT = Ctx.getTemplateSpecializationType(
TST->getTemplateName(), FQArgs, TST->getTemplateName(), FQArgs,
TST->getCanonicalTypeInternal()); /*CanonicalArgs=*/std::nullopt, TST->desugar());
// getTemplateSpecializationType returns a fully qualified // getTemplateSpecializationType returns a fully qualified
// version of the specialization itself, so no need to qualify // version of the specialization itself, so no need to qualify
// it. // it.
@ -172,6 +172,7 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
TemplateName TN(TSTDecl->getSpecializedTemplate()); TemplateName TN(TSTDecl->getSpecializedTemplate());
QualType QT = Ctx.getTemplateSpecializationType( QualType QT = Ctx.getTemplateSpecializationType(
TN, FQArgs, TN, FQArgs,
/*CanonicalArgs=*/std::nullopt,
TSTRecord->getCanonicalTypeInternal()); TSTRecord->getCanonicalTypeInternal());
// getTemplateSpecializationType returns a fully qualified // getTemplateSpecializationType returns a fully qualified
// version of the specialization itself, so no need to qualify // version of the specialization itself, so no need to qualify

View File

@ -414,9 +414,16 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
getAsStructuralValue().Profile(ID); getAsStructuralValue().Profile(ID);
break; break;
case Expression: case Expression: {
getAsExpr()->Profile(ID, Context, true); const Expr *E = getAsExpr();
bool IsCanonical = isCanonicalExpr();
ID.AddBoolean(IsCanonical);
if (IsCanonical)
E->Profile(ID, Context, true);
else
ID.AddPointer(E);
break; break;
}
case Pack: case Pack:
ID.AddInteger(Args.NumArgs); ID.AddInteger(Args.NumArgs);
@ -431,9 +438,11 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
switch (getKind()) { switch (getKind()) {
case Null: case Null:
case Type: case Type:
case Expression:
case NullPtr: case NullPtr:
return TypeOrValue.V == Other.TypeOrValue.V; return TypeOrValue.V == Other.TypeOrValue.V;
case Expression:
return TypeOrValue.V == Other.TypeOrValue.V &&
TypeOrValue.IsCanonicalExpr == Other.TypeOrValue.IsCanonicalExpr;
case Template: case Template:
case TemplateExpansion: case TemplateExpansion:
@ -478,7 +487,8 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
return getAsType()->castAs<PackExpansionType>()->getPattern(); return getAsType()->castAs<PackExpansionType>()->getPattern();
case Expression: case Expression:
return TemplateArgument(cast<PackExpansionExpr>(getAsExpr())->getPattern()); return TemplateArgument(cast<PackExpansionExpr>(getAsExpr())->getPattern(),
isCanonicalExpr());
case TemplateExpansion: case TemplateExpansion:
return TemplateArgument(getAsTemplateOrTemplatePattern()); return TemplateArgument(getAsTemplateOrTemplatePattern());
@ -655,6 +665,7 @@ static const T &DiagTemplateArg(const T &DB, const TemplateArgument &Arg) {
return DB << Arg.getAsTemplateOrTemplatePattern() << "..."; return DB << Arg.getAsTemplateOrTemplatePattern() << "...";
case TemplateArgument::Expression: case TemplateArgument::Expression:
// FIXME: Support printing expressions as canonical
return DB << Arg.getAsExpr(); return DB << Arg.getAsExpr();
case TemplateArgument::Pack: { case TemplateArgument::Pack: {

View File

@ -4055,8 +4055,8 @@ QualType DecltypeType::desugar() const {
return QualType(this, 0); return QualType(this, 0);
} }
DependentDecltypeType::DependentDecltypeType(Expr *E, QualType UnderlyingType) DependentDecltypeType::DependentDecltypeType(Expr *E)
: DecltypeType(E, UnderlyingType) {} : DecltypeType(E, QualType()) {}
void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID, void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,
const ASTContext &Context, Expr *E) { const ASTContext &Context, Expr *E) {
@ -4127,11 +4127,6 @@ UnaryTransformType::UnaryTransformType(QualType BaseType,
: Type(UnaryTransform, CanonicalType, BaseType->getDependence()), : Type(UnaryTransform, CanonicalType, BaseType->getDependence()),
BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind) {} 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) TagType::TagType(TypeClass TC, const TagDecl *D, QualType can)
: Type(TC, can, : Type(TC, can,
D->isDependentType() ? TypeDependence::DependentInstantiation D->isDependentType() ? TypeDependence::DependentInstantiation
@ -4388,17 +4383,19 @@ bool TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
} }
TemplateSpecializationType::TemplateSpecializationType( TemplateSpecializationType::TemplateSpecializationType(
TemplateName T, ArrayRef<TemplateArgument> Args, QualType Canon, TemplateName T, bool IsAlias, ArrayRef<TemplateArgument> Args,
QualType AliasedType) QualType Underlying)
: Type(TemplateSpecialization, Canon.isNull() ? QualType(this, 0) : Canon, : Type(TemplateSpecialization,
(Canon.isNull() Underlying.isNull() ? QualType(this, 0)
: Underlying.getCanonicalType(),
(Underlying.isNull()
? TypeDependence::DependentInstantiation ? TypeDependence::DependentInstantiation
: toSemanticDependence(Canon->getDependence())) | : toSemanticDependence(Underlying->getDependence())) |
(toTypeDependence(T.getDependence()) & (toTypeDependence(T.getDependence()) &
TypeDependence::UnexpandedPack)), TypeDependence::UnexpandedPack)),
Template(T) { Template(T) {
TemplateSpecializationTypeBits.NumArgs = Args.size(); TemplateSpecializationTypeBits.NumArgs = Args.size();
TemplateSpecializationTypeBits.TypeAlias = !AliasedType.isNull(); TemplateSpecializationTypeBits.TypeAlias = IsAlias;
assert(!T.getAsDependentTemplateName() && assert(!T.getAsDependentTemplateName() &&
"Use DependentTemplateSpecializationType for dependent template-name"); "Use DependentTemplateSpecializationType for dependent template-name");
@ -4410,7 +4407,8 @@ TemplateSpecializationType::TemplateSpecializationType(
T.getKind() == TemplateName::DeducedTemplate) && T.getKind() == TemplateName::DeducedTemplate) &&
"Unexpected template name for TemplateSpecializationType"); "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) { for (const TemplateArgument &Arg : Args) {
// Update instantiation-dependent, variably-modified, and error bits. // Update instantiation-dependent, variably-modified, and error bits.
// If the canonical type exists and is non-dependent, the template // If the canonical type exists and is non-dependent, the template
@ -4428,11 +4426,10 @@ TemplateSpecializationType::TemplateSpecializationType(
new (TemplateArgs++) TemplateArgument(Arg); new (TemplateArgs++) TemplateArgument(Arg);
} }
// Store the aliased type if this is a type alias template specialization. // Store the aliased type after the template arguments, if this is a type
if (isTypeAlias()) { // alias template specialization.
auto *Begin = reinterpret_cast<TemplateArgument *>(this + 1); if (IsAlias)
*reinterpret_cast<QualType *>(Begin + Args.size()) = AliasedType; *reinterpret_cast<QualType *>(TemplateArgs) = Underlying;
}
} }
QualType TemplateSpecializationType::getAliasedType() const { QualType TemplateSpecializationType::getAliasedType() const {
@ -4442,17 +4439,19 @@ QualType TemplateSpecializationType::getAliasedType() const {
void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
const ASTContext &Ctx) { const ASTContext &Ctx) {
Profile(ID, Template, template_arguments(), Ctx); Profile(ID, Template, template_arguments(),
if (isTypeAlias()) isSugared() ? desugar() : QualType(), Ctx);
getAliasedType().Profile(ID);
} }
void void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, TemplateName T,
TemplateName T, ArrayRef<TemplateArgument> Args,
ArrayRef<TemplateArgument> Args, QualType Underlying,
const ASTContext &Context) { const ASTContext &Context) {
T.Profile(ID); T.Profile(ID);
Underlying.Profile(ID);
ID.AddInteger(Args.size());
for (const TemplateArgument &Arg : Args) for (const TemplateArgument &Arg : Args)
Arg.Profile(ID, Context); Arg.Profile(ID, Context);
} }
@ -5264,9 +5263,9 @@ AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
} }
void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
QualType Deduced, AutoTypeKeyword Keyword, QualType Deduced, AutoTypeKeyword Keyword,
bool IsDependent, ConceptDecl *CD, bool IsDependent, ConceptDecl *CD,
ArrayRef<TemplateArgument> Arguments) { ArrayRef<TemplateArgument> Arguments) {
ID.AddPointer(Deduced.getAsOpaquePtr()); ID.AddPointer(Deduced.getAsOpaquePtr());
ID.AddInteger((unsigned)Keyword); ID.AddInteger((unsigned)Keyword);
ID.AddBoolean(IsDependent); ID.AddBoolean(IsDependent);

View File

@ -69,17 +69,14 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
// Look through type alias templates, per C++0x [temp.dep.type]p1. // Look through type alias templates, per C++0x [temp.dep.type]p1.
NNSType = Context.getCanonicalType(NNSType); NNSType = Context.getCanonicalType(NNSType);
if (const TemplateSpecializationType *SpecType if (const auto *SpecType =
= NNSType->getAs<TemplateSpecializationType>()) { dyn_cast<TemplateSpecializationType>(NNSType)) {
// We are entering the context of the nested name specifier, so try to // We are entering the context of the nested name specifier, so try to
// match the nested name specifier to either a primary class template // match the nested name specifier to either a primary class template
// or a class template partial specialization. // or a class template partial specialization.
if (ClassTemplateDecl *ClassTemplate if (ClassTemplateDecl *ClassTemplate =
= dyn_cast_or_null<ClassTemplateDecl>( dyn_cast_or_null<ClassTemplateDecl>(
SpecType->getTemplateName().getAsTemplateDecl())) { SpecType->getTemplateName().getAsTemplateDecl())) {
QualType ContextType =
Context.getCanonicalType(QualType(SpecType, 0));
// FIXME: The fallback on the search of partial // FIXME: The fallback on the search of partial
// specialization using ContextType should be eventually removed since // specialization using ContextType should be eventually removed since
// it doesn't handle the case of constrained template parameters // 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); SpecType->template_arguments(), *L, Pos);
} }
} else { } else {
PartialSpec = ClassTemplate->findPartialSpecialization(ContextType); PartialSpec =
ClassTemplate->findPartialSpecialization(QualType(SpecType, 0));
} }
if (PartialSpec) { if (PartialSpec) {
@ -122,7 +120,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
// into that class template definition. // into that class template definition.
QualType Injected = QualType Injected =
ClassTemplate->getInjectedClassNameSpecialization(); ClassTemplate->getInjectedClassNameSpecialization();
if (Context.hasSameType(Injected, ContextType)) if (Context.hasSameType(Injected, QualType(SpecType, 0)))
return ClassTemplate->getTemplatedDecl(); return ClassTemplate->getTemplatedDecl();
} }
} else if (const RecordType *RecordT = NNSType->getAs<RecordType>()) { } else if (const RecordType *RecordT = NNSType->getAs<RecordType>()) {

View File

@ -2183,7 +2183,7 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
case LOLR_Template: { case LOLR_Template: {
TemplateArgumentListInfo ExplicitArgs; TemplateArgumentListInfo ExplicitArgs;
TemplateArgument Arg(Lit); TemplateArgument Arg(Lit, /*IsCanonical=*/false);
TemplateArgumentLocInfo ArgInfo(Lit); TemplateArgumentLocInfo ArgInfo(Lit);
ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
return BuildLiteralOperatorCall(R, OpNameInfo, {}, StringTokLocs.back(), return BuildLiteralOperatorCall(R, OpNameInfo, {}, StringTokLocs.back(),
@ -21108,8 +21108,22 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
Diag(Temp->getLocation(), diag::note_referenced_type_template) Diag(Temp->getLocation(), diag::note_referenced_type_template)
<< IsTypeAliasTemplateDecl; << IsTypeAliasTemplateDecl;
QualType TST = TemplateArgumentListInfo TAL(ULE->getLAngleLoc(), ULE->getRAngleLoc());
Context.getTemplateSpecializationType(TN, ULE->template_arguments()); 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 = QualType ET =
Context.getElaboratedType(ElaboratedTypeKeyword::None, NNS, TST); Context.getElaboratedType(ElaboratedTypeKeyword::None, NNS, TST);
return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {}, return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {},

View File

@ -3713,7 +3713,8 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
if (StringLit) { if (StringLit) {
SFINAETrap Trap(*this); SFINAETrap Trap(*this);
CheckTemplateArgumentInfo CTAI; CheckTemplateArgumentInfo CTAI;
TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit); TemplateArgumentLoc Arg(
TemplateArgument(StringLit, /*IsCanonical=*/false), StringLit);
if (CheckTemplateArgument( if (CheckTemplateArgument(
Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(), Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
/*ArgumentPackIndex=*/0, CTAI, CTAK_Specified) || /*ArgumentPackIndex=*/0, CTAI, CTAK_Specified) ||

View File

@ -909,7 +909,7 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
case ParsedTemplateArgument::NonType: { case ParsedTemplateArgument::NonType: {
Expr *E = static_cast<Expr *>(Arg.getAsExpr()); Expr *E = static_cast<Expr *>(Arg.getAsExpr());
return TemplateArgumentLoc(TemplateArgument(E), E); return TemplateArgumentLoc(TemplateArgument(E, /*IsCanonical=*/false), E);
} }
case ParsedTemplateArgument::Template: { case ParsedTemplateArgument::Template: {
@ -1576,8 +1576,9 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
return Param; return Param;
Param->setDefaultArgument( Param->setDefaultArgument(
Context, getTrivialTemplateArgumentLoc(TemplateArgument(Default), Context, getTrivialTemplateArgumentLoc(
QualType(), SourceLocation())); TemplateArgument(Default, /*IsCanonical=*/false),
QualType(), SourceLocation()));
} }
return Param; return Param;
@ -3250,8 +3251,7 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
TemplateArgument NumArgsArg = Converted[2]; TemplateArgument NumArgsArg = Converted[2];
if (NumArgsArg.isDependent()) if (NumArgsArg.isDependent())
return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD), return QualType();
Converted);
TemplateArgumentListInfo SyntheticTemplateArgs; TemplateArgumentListInfo SyntheticTemplateArgs;
// The type argument, wrapped in substitution sugar, gets reused as the // 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> // __type_pack_element<Index, T_1, ..., T_N>
// are treated like T_Index. // are treated like T_Index.
assert(Converted.size() == 2 && 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]; TemplateArgument IndexArg = Converted[0], Ts = Converted[1];
if (IndexArg.isDependent() || Ts.isDependent()) if (IndexArg.isDependent() || Ts.isDependent())
return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD), return QualType();
Converted);
llvm::APSInt Index = IndexArg.getAsIntegral(); llvm::APSInt Index = IndexArg.getAsIntegral();
assert(Index >= 0 && "the index used with __type_pack_element should be of " 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: { case BTK__builtin_common_type: {
assert(Converted.size() == 4); assert(Converted.size() == 4);
if (llvm::any_of(Converted, [](auto &C) { return C.isDependent(); })) if (llvm::any_of(Converted, [](auto &C) { return C.isDependent(); }))
return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD), return QualType();
Converted);
TemplateName BaseTemplate = Converted[0].getAsTemplate(); TemplateName BaseTemplate = Converted[0].getAsTemplate();
TemplateName HasTypeMember = Converted[1].getAsTemplate();
QualType HasNoTypeMember = Converted[2].getAsType();
ArrayRef<TemplateArgument> Ts = Converted[3].getPackAsArray(); ArrayRef<TemplateArgument> Ts = Converted[3].getPackAsArray();
if (auto CT = builtinCommonTypeImpl(SemaRef, BaseTemplate, TemplateLoc, Ts); if (auto CT = builtinCommonTypeImpl(SemaRef, BaseTemplate, TemplateLoc, Ts);
!CT.isNull()) { !CT.isNull()) {
@ -3326,9 +3322,10 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
TAs.addArgument(TemplateArgumentLoc( TAs.addArgument(TemplateArgumentLoc(
TemplateArgument(CT), SemaRef.Context.getTrivialTypeSourceInfo( TemplateArgument(CT), SemaRef.Context.getTrivialTypeSourceInfo(
CT, TemplateArgs[1].getLocation()))); CT, TemplateArgs[1].getLocation())));
TemplateName HasTypeMember = Converted[1].getAsTemplate();
return SemaRef.CheckTemplateIdType(HasTypeMember, TemplateLoc, TAs); return SemaRef.CheckTemplateIdType(HasTypeMember, TemplateLoc, TAs);
} }
QualType HasNoTypeMember = Converted[2].getAsType();
return HasNoTypeMember; return HasNoTypeMember;
} }
} }
@ -3492,20 +3489,19 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
resolveAssumedTemplateNameAsType(/*Scope=*/nullptr, Name, TemplateLoc)) resolveAssumedTemplateNameAsType(/*Scope=*/nullptr, Name, TemplateLoc))
return QualType(); return QualType();
auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs(); TemplateDecl *Template;
DefaultArguments DefaultArgs;
if (!Template || isa<FunctionTemplateDecl>(Template) || if (const SubstTemplateTemplateParmPackStorage *S =
isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) { Name.getAsSubstTemplateTemplateParmPack()) {
// We might have a substituted template template parameter pack. If so, Template = S->getParameterPack();
// build a template specialization type for it. } else {
if (Name.getAsSubstTemplateTemplateParmPack()) std::tie(Template, DefaultArgs) = Name.getTemplateDeclAndDefaultArgs();
return Context.getTemplateSpecializationType(Name, if (!Template || isa<FunctionTemplateDecl>(Template) ||
TemplateArgs.arguments()); isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) {
Diag(TemplateLoc, diag::err_template_id_not_a_type) << Name;
Diag(TemplateLoc, diag::err_template_id_not_a_type) NoteAllFoundTemplates(Name);
<< Name; return QualType();
NoteAllFoundTemplates(Name); }
return QualType();
} }
// Check that the template argument list is well-formed for this // Check that the template argument list is well-formed for this
@ -3519,8 +3515,11 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
QualType CanonType; QualType CanonType;
if (TypeAliasTemplateDecl *AliasTemplate = if (isa<TemplateTemplateParmDecl>(Template)) {
dyn_cast<TypeAliasTemplateDecl>(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. // Find the canonical type for this type alias template specialization.
TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl(); TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl();
@ -3602,7 +3601,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// //
// template<typename T, typename U = T> struct A; // template<typename T, typename U = T> struct A;
CanonType = Context.getCanonicalTemplateSpecializationType( 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 // This might work out to be a current instantiation, in which
// case the canonical type needs to be the InjectedClassNameType. // 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 // Build the fully-sugared type for this class template
// specialization, which refers back to the class template // specialization, which refers back to the class template
// specialization we created or found. // specialization we created or found.
return Context.getTemplateSpecializationType(Name, TemplateArgs.arguments(), return Context.getTemplateSpecializationType(
CanonType); Name, TemplateArgs.arguments(), CTAI.CanonicalConverted, CanonType);
} }
void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName, 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 // If the resulting expression is new, then use it in place of the
// old expression in the template argument. // old expression in the template argument.
if (R != E) { if (R != E) {
TemplateArgument TA(R); TemplateArgument TA(R, /*IsCanonical=*/false);
ArgLoc = TemplateArgumentLoc(TA, R); ArgLoc = TemplateArgumentLoc(TA, R);
} }
break; break;
@ -6476,7 +6477,7 @@ static bool CheckTemplateArgumentAddressOfObjectOrFunction(
// Stop checking the precise nature of the argument if it is value dependent, // Stop checking the precise nature of the argument if it is value dependent,
// it should be checked when instantiated. // it should be checked when instantiated.
if (Arg->isValueDependent()) { if (Arg->isValueDependent()) {
SugaredConverted = TemplateArgument(ArgIn); SugaredConverted = TemplateArgument(ArgIn, /*IsCanonical=*/false);
CanonicalConverted = CanonicalConverted =
S.Context.getCanonicalTemplateArgument(SugaredConverted); S.Context.getCanonicalTemplateArgument(SugaredConverted);
return false; return false;
@ -6667,7 +6668,7 @@ CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param,
if (VD->getType()->isMemberPointerType()) { if (VD->getType()->isMemberPointerType()) {
if (isa<NonTypeTemplateParmDecl>(VD)) { if (isa<NonTypeTemplateParmDecl>(VD)) {
if (Arg->isTypeDependent() || Arg->isValueDependent()) { if (Arg->isTypeDependent() || Arg->isValueDependent()) {
SugaredConverted = TemplateArgument(Arg); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = CanonicalConverted =
S.Context.getCanonicalTemplateArgument(SugaredConverted); S.Context.getCanonicalTemplateArgument(SugaredConverted);
} else { } else {
@ -6733,7 +6734,7 @@ CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param,
// Okay: this is the address of a non-static member, and therefore // Okay: this is the address of a non-static member, and therefore
// a member pointer constant. // a member pointer constant.
if (Arg->isTypeDependent() || Arg->isValueDependent()) { if (Arg->isTypeDependent() || Arg->isValueDependent()) {
SugaredConverted = TemplateArgument(Arg); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = CanonicalConverted =
S.Context.getCanonicalTemplateArgument(SugaredConverted); S.Context.getCanonicalTemplateArgument(SugaredConverted);
} else { } else {
@ -6784,7 +6785,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (DeductionArg->isTypeDependent()) { if (DeductionArg->isTypeDependent()) {
auto *AT = dyn_cast<AutoType>(DeducedT); auto *AT = dyn_cast<AutoType>(DeducedT);
if (AT && AT->isDecltypeAuto()) { if (AT && AT->isDecltypeAuto()) {
SugaredConverted = TemplateArgument(Arg); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = TemplateArgument( CanonicalConverted = TemplateArgument(
Context.getCanonicalTemplateArgument(SugaredConverted)); Context.getCanonicalTemplateArgument(SugaredConverted));
return Arg; return Arg;
@ -6858,7 +6859,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (E.isInvalid()) if (E.isInvalid())
return ExprError(); return ExprError();
setDeductionArg(E.get()); setDeductionArg(E.get());
SugaredConverted = TemplateArgument(Arg); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = TemplateArgument( CanonicalConverted = TemplateArgument(
Context.getCanonicalTemplateArgument(SugaredConverted)); Context.getCanonicalTemplateArgument(SugaredConverted));
return Arg; return Arg;
@ -6889,7 +6890,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// normal template rules apply: we accept the template if it would be valid // normal template rules apply: we accept the template if it would be valid
// for any number of expansions (i.e. none). // for any number of expansions (i.e. none).
if (ArgPE && !StrictCheck) { if (ArgPE && !StrictCheck) {
SugaredConverted = TemplateArgument(Arg); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = TemplateArgument( CanonicalConverted = TemplateArgument(
Context.getCanonicalTemplateArgument(SugaredConverted)); Context.getCanonicalTemplateArgument(SugaredConverted));
return Arg; return Arg;
@ -6915,7 +6916,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return Arg; return Arg;
} }
if (isa<NonTypeTemplateParmDecl>(ND)) { if (isa<NonTypeTemplateParmDecl>(ND)) {
SugaredConverted = TemplateArgument(Arg); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = CanonicalConverted =
Context.getCanonicalTemplateArgument(SugaredConverted); Context.getCanonicalTemplateArgument(SugaredConverted);
return Arg; return Arg;
@ -6972,7 +6973,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// permitted (and expected) to be unable to determine a value. // permitted (and expected) to be unable to determine a value.
if (ArgResult.get()->isValueDependent()) { if (ArgResult.get()->isValueDependent()) {
setDeductionArg(ArgResult.get()); setDeductionArg(ArgResult.get());
SugaredConverted = TemplateArgument(Arg); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = CanonicalConverted =
Context.getCanonicalTemplateArgument(SugaredConverted); Context.getCanonicalTemplateArgument(SugaredConverted);
return Arg; return Arg;
@ -7010,7 +7011,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
Value.getLValuePath()[0].getAsArrayIndex() == 0 && Value.getLValuePath()[0].getAsArrayIndex() == 0 &&
!Value.isLValueOnePastTheEnd() && ParamType->isPointerType()) { !Value.isLValueOnePastTheEnd() && ParamType->isPointerType()) {
if (ArgPE) { if (ArgPE) {
SugaredConverted = TemplateArgument(Arg); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = CanonicalConverted =
Context.getCanonicalTemplateArgument(SugaredConverted); Context.getCanonicalTemplateArgument(SugaredConverted);
} else { } else {
@ -7041,7 +7042,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff); return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff);
if (ArgPE) { if (ArgPE) {
SugaredConverted = TemplateArgument(Arg); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = CanonicalConverted =
Context.getCanonicalTemplateArgument(SugaredConverted); Context.getCanonicalTemplateArgument(SugaredConverted);
} else { } else {
@ -7086,7 +7087,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// We can't check arbitrary value-dependent arguments. // We can't check arbitrary value-dependent arguments.
if (DeductionArg->isValueDependent()) { if (DeductionArg->isValueDependent()) {
SugaredConverted = TemplateArgument(Arg); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = CanonicalConverted =
Context.getCanonicalTemplateArgument(SugaredConverted); Context.getCanonicalTemplateArgument(SugaredConverted);
return Arg; return Arg;
@ -7103,7 +7104,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
: Context.getTypeSize(IntegerType)); : Context.getTypeSize(IntegerType));
if (ArgPE) { if (ArgPE) {
SugaredConverted = TemplateArgument(Arg); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = CanonicalConverted =
Context.getCanonicalTemplateArgument(SugaredConverted); Context.getCanonicalTemplateArgument(SugaredConverted);
} else { } else {
@ -7187,7 +7188,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (DeductionArg->isValueDependent()) { if (DeductionArg->isValueDependent()) {
// The argument is value-dependent. Create a new // The argument is value-dependent. Create a new
// TemplateArgument with the converted expression. // TemplateArgument with the converted expression.
SugaredConverted = TemplateArgument(Arg); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = CanonicalConverted =
Context.getCanonicalTemplateArgument(SugaredConverted); Context.getCanonicalTemplateArgument(SugaredConverted);
return Arg; return Arg;
@ -7243,7 +7244,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
} }
if (ArgPE) { if (ArgPE) {
SugaredConverted = TemplateArgument(Arg); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = CanonicalConverted =
Context.getCanonicalTemplateArgument(SugaredConverted); Context.getCanonicalTemplateArgument(SugaredConverted);
} else { } else {
@ -7366,7 +7367,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// Deal with parameters of type std::nullptr_t. // Deal with parameters of type std::nullptr_t.
if (ParamType->isNullPtrType()) { if (ParamType->isNullPtrType()) {
if (DeductionArg->isTypeDependent() || DeductionArg->isValueDependent()) { if (DeductionArg->isTypeDependent() || DeductionArg->isValueDependent()) {
SugaredConverted = TemplateArgument(Arg); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = CanonicalConverted =
Context.getCanonicalTemplateArgument(SugaredConverted); Context.getCanonicalTemplateArgument(SugaredConverted);
return Arg; return Arg;
@ -7386,7 +7387,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
case NPV_NullPointer: case NPV_NullPointer:
Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
if (ArgPE) { if (ArgPE) {
SugaredConverted = TemplateArgument(Arg); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = CanonicalConverted =
Context.getCanonicalTemplateArgument(SugaredConverted); Context.getCanonicalTemplateArgument(SugaredConverted);
} else { } else {
@ -8523,17 +8524,34 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
isPartialSpecialization)) isPartialSpecialization))
return true; return true;
// The canonical type
QualType CanonType; QualType CanonType;
if (isPartialSpecialization) { if (!isPartialSpecialization) {
// Build the canonical type that describes the converted template // Create a new class template specialization declaration node for
// arguments of the class template partial specialization. // this explicit specialization or friend declaration.
TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); Specialization = ClassTemplateSpecializationDecl::Create(
CanonType = Context.getTemplateSpecializationType(CanonTemplate, Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
CTAI.CanonicalConverted); 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, if (!PrevDecl)
ClassTemplate->getInjectedClassNameSpecialization()) && 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 || (!Context.getLangOpts().CPlusPlus20 ||
!TemplateParams->hasAssociatedConstraints())) { !TemplateParams->hasAssociatedConstraints())) {
// C++ [temp.class.spec]p9b3: // C++ [temp.class.spec]p9b3:
@ -8560,7 +8578,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
ClassTemplatePartialSpecializationDecl *Partial = ClassTemplatePartialSpecializationDecl *Partial =
ClassTemplatePartialSpecializationDecl::Create( ClassTemplatePartialSpecializationDecl::Create(
Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams, Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams,
ClassTemplate, CTAI.CanonicalConverted, CanonType, PrevPartial); ClassTemplate, CTAI.CanonicalConverted, WrittenTy->getType(),
PrevPartial);
Partial->setTemplateArgsAsWritten(TemplateArgs); Partial->setTemplateArgsAsWritten(TemplateArgs);
SetNestedNameSpecifier(*this, Partial, SS); SetNestedNameSpecifier(*this, Partial, SS);
if (TemplateParameterLists.size() > 1 && SS.isSet()) { if (TemplateParameterLists.size() > 1 && SS.isSet()) {
@ -8578,29 +8597,6 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
PrevPartial->setMemberSpecialization(); PrevPartial->setMemberSpecialization();
CheckTemplatePartialSpecialization(Partial); 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: // C++ [temp.expl.spec]p6:
@ -8690,8 +8686,6 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// actually wrote the specialization, rather than formatting the // actually wrote the specialization, rather than formatting the
// name based on the "canonical" representation used to store the // name based on the "canonical" representation used to store the
// template arguments in the specialization. // template arguments in the specialization.
TypeSourceInfo *WrittenTy = Context.getTemplateSpecializationTypeInfo(
Name, TemplateNameLoc, TemplateArgs, CanonType);
FriendDecl *Friend = FriendDecl::Create(Context, CurContext, FriendDecl *Friend = FriendDecl::Create(Context, CurContext,
TemplateNameLoc, TemplateNameLoc,
WrittenTy, WrittenTy,

View File

@ -493,8 +493,8 @@ DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
: CK_NullToPointer) : CK_NullToPointer)
.get(); .get();
return DeduceNonTypeTemplateArgument( return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, TemplateArgument(Value), Value->getType(), Info, S, TemplateParams, NTTP, TemplateArgument(Value, /*IsCanonical=*/false),
PartialOrdering, Deduced, HasDeducedAnyParam); Value->getType(), Info, PartialOrdering, Deduced, HasDeducedAnyParam);
} }
/// Deduce the value of the given non-type template parameter /// Deduce the value of the given non-type template parameter
@ -508,8 +508,8 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
SmallVectorImpl<DeducedTemplateArgument> &Deduced, SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool *HasDeducedAnyParam) { bool *HasDeducedAnyParam) {
return DeduceNonTypeTemplateArgument( return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, TemplateArgument(Value), Value->getType(), Info, S, TemplateParams, NTTP, TemplateArgument(Value, /*IsCanonical=*/false),
PartialOrdering, Deduced, HasDeducedAnyParam); Value->getType(), Info, PartialOrdering, Deduced, HasDeducedAnyParam);
} }
/// Deduce the value of the given non-type template parameter /// 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. /// but it may still fail, later, for other reasons.
static const TemplateSpecializationType *getLastTemplateSpecType(QualType QT) { static const TemplateSpecializationType *getLastTemplateSpecType(QualType QT) {
const TemplateSpecializationType *LastTST = nullptr;
for (const Type *T = QT.getTypePtr(); /**/; /**/) { for (const Type *T = QT.getTypePtr(); /**/; /**/) {
const TemplateSpecializationType *TST = const TemplateSpecializationType *TST =
T->getAs<TemplateSpecializationType>(); T->getAs<TemplateSpecializationType>();
assert(TST && "Expected a TemplateSpecializationType"); if (!TST)
return LastTST;
if (!TST->isSugared()) if (!TST->isSugared())
return TST; return TST;
LastTST = TST;
T = TST->desugar().getTypePtr(); T = TST->desugar().getTypePtr();
} }
} }
@ -2899,7 +2902,7 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc, Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc,
TemplateParam) TemplateParam)
.getAs<Expr>(); .getAs<Expr>();
return TemplateArgumentLoc(TemplateArgument(E), E); return TemplateArgumentLoc(TemplateArgument(E, /*IsCanonical=*/false), E);
} }
case TemplateArgument::NullPtr: { case TemplateArgument::NullPtr: {
@ -2914,7 +2917,7 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
case TemplateArgument::Integral: case TemplateArgument::Integral:
case TemplateArgument::StructuralValue: { case TemplateArgument::StructuralValue: {
Expr *E = BuildExpressionFromNonTypeTemplateArgument(Arg, Loc).get(); Expr *E = BuildExpressionFromNonTypeTemplateArgument(Arg, Loc).get();
return TemplateArgumentLoc(TemplateArgument(E), E); return TemplateArgumentLoc(TemplateArgument(E, /*IsCanonical=*/false), E);
} }
case TemplateArgument::Template: case TemplateArgument::Template:
@ -6415,8 +6418,8 @@ Sema::getMoreSpecializedPartialSpecialization(
ClassTemplatePartialSpecializationDecl *PS1, ClassTemplatePartialSpecializationDecl *PS1,
ClassTemplatePartialSpecializationDecl *PS2, ClassTemplatePartialSpecializationDecl *PS2,
SourceLocation Loc) { SourceLocation Loc) {
QualType PT1 = PS1->getInjectedSpecializationType(); QualType PT1 = PS1->getInjectedSpecializationType().getCanonicalType();
QualType PT2 = PS2->getInjectedSpecializationType(); QualType PT2 = PS2->getInjectedSpecializationType().getCanonicalType();
TemplateDeductionInfo Info(Loc); TemplateDeductionInfo Info(Loc);
return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info); return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info);
@ -6425,8 +6428,9 @@ Sema::getMoreSpecializedPartialSpecialization(
bool Sema::isMoreSpecializedThanPrimary( bool Sema::isMoreSpecializedThanPrimary(
ClassTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) { ClassTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) {
ClassTemplateDecl *Primary = Spec->getSpecializedTemplate(); ClassTemplateDecl *Primary = Spec->getSpecializedTemplate();
QualType PrimaryT = Primary->getInjectedClassNameSpecialization(); QualType PrimaryT =
QualType PartialT = Spec->getInjectedSpecializationType(); Primary->getInjectedClassNameSpecialization().getCanonicalType();
QualType PartialT = Spec->getInjectedSpecializationType().getCanonicalType();
ClassTemplatePartialSpecializationDecl *MaybeSpec = ClassTemplatePartialSpecializationDecl *MaybeSpec =
getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info); getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info);
@ -6444,10 +6448,10 @@ Sema::getMoreSpecializedPartialSpecialization(
assert(PS1->getSpecializedTemplate() == PS2->getSpecializedTemplate() && assert(PS1->getSpecializedTemplate() == PS2->getSpecializedTemplate() &&
"the partial specializations being compared should specialize" "the partial specializations being compared should specialize"
" the same template."); " the same template.");
TemplateName Name(PS1->getSpecializedTemplate()); TemplateName Name(PS1->getSpecializedTemplate()->getCanonicalDecl());
QualType PT1 = Context.getTemplateSpecializationType( QualType PT1 = Context.getCanonicalTemplateSpecializationType(
Name, PS1->getTemplateArgs().asArray()); Name, PS1->getTemplateArgs().asArray());
QualType PT2 = Context.getTemplateSpecializationType( QualType PT2 = Context.getCanonicalTemplateSpecializationType(
Name, PS2->getTemplateArgs().asArray()); Name, PS2->getTemplateArgs().asArray());
TemplateDeductionInfo Info(Loc); TemplateDeductionInfo Info(Loc);
@ -6457,10 +6461,15 @@ Sema::getMoreSpecializedPartialSpecialization(
bool Sema::isMoreSpecializedThanPrimary( bool Sema::isMoreSpecializedThanPrimary(
VarTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) { VarTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) {
VarTemplateDecl *Primary = Spec->getSpecializedTemplate(); VarTemplateDecl *Primary = Spec->getSpecializedTemplate();
TemplateName Name(Primary); TemplateName Name(Primary->getCanonicalDecl());
QualType PrimaryT = Context.getTemplateSpecializationType(
Name, Primary->getInjectedTemplateArgs(Context)); SmallVector<TemplateArgument, 8> PrimaryCanonArgs(
QualType PartialT = Context.getTemplateSpecializationType( Primary->getInjectedTemplateArgs(Context));
Context.canonicalizeTemplateArguments(PrimaryCanonArgs);
QualType PrimaryT =
Context.getCanonicalTemplateSpecializationType(Name, PrimaryCanonArgs);
QualType PartialT = Context.getCanonicalTemplateSpecializationType(
Name, Spec->getTemplateArgs().asArray()); Name, Spec->getTemplateArgs().asArray());
VarTemplatePartialSpecializationDecl *MaybeSpec = VarTemplatePartialSpecializationDecl *MaybeSpec =

View File

@ -4791,17 +4791,18 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
ClassTemplate->findPartialSpecialization(CTAI.CanonicalConverted, ClassTemplate->findPartialSpecialization(CTAI.CanonicalConverted,
InstParams, InsertPos); InstParams, InsertPos);
// Build the canonical type that describes the converted template // Build the type that describes the converted template arguments of the class
// arguments of the class template partial specialization. // template partial specialization.
QualType CanonType = SemaRef.Context.getTemplateSpecializationType( TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo(
TemplateName(ClassTemplate), CTAI.CanonicalConverted); TemplateName(ClassTemplate), TemplArgInfo->getLAngleLoc(),
InstTemplateArgs, CTAI.CanonicalConverted);
// Create the class template partial specialization declaration. // Create the class template partial specialization declaration.
ClassTemplatePartialSpecializationDecl *InstPartialSpec = ClassTemplatePartialSpecializationDecl *InstPartialSpec =
ClassTemplatePartialSpecializationDecl::Create( ClassTemplatePartialSpecializationDecl::Create(
SemaRef.Context, PartialSpec->getTagKind(), Owner, SemaRef.Context, PartialSpec->getTagKind(), Owner,
PartialSpec->getBeginLoc(), PartialSpec->getLocation(), InstParams, PartialSpec->getBeginLoc(), PartialSpec->getLocation(), InstParams,
ClassTemplate, CTAI.CanonicalConverted, CanonType, ClassTemplate, CTAI.CanonicalConverted, WrittenTy->getType(),
/*PrevDecl=*/nullptr); /*PrevDecl=*/nullptr);
InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs); InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs);

View File

@ -1286,7 +1286,8 @@ TemplateArgumentLoc Sema::getTemplateArgumentPackExpansionPattern(
Expr *Pattern = Expansion->getPattern(); Expr *Pattern = Expansion->getPattern();
Ellipsis = Expansion->getEllipsisLoc(); Ellipsis = Expansion->getEllipsisLoc();
NumExpansions = Expansion->getNumExpansions(); NumExpansions = Expansion->getNumExpansions();
return TemplateArgumentLoc(TemplateArgument(Pattern), Pattern); return TemplateArgumentLoc(
TemplateArgument(Pattern, Argument.isCanonicalExpr()), Pattern);
} }
case TemplateArgument::TemplateExpansion: case TemplateArgument::TemplateExpansion:

View File

@ -3981,7 +3981,9 @@ public:
if (Result.isInvalid()) if (Result.isInvalid())
return TemplateArgumentLoc(); return TemplateArgumentLoc();
return TemplateArgumentLoc(TemplateArgument(Result.get()), Result.get()); return TemplateArgumentLoc(TemplateArgument(Result.get(),
/*IsCanonical=*/false),
Result.get());
} }
case TemplateArgument::Template: case TemplateArgument::Template:
@ -4941,7 +4943,8 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
E = SemaRef.ActOnConstantExpression(E); E = SemaRef.ActOnConstantExpression(E);
if (E.isInvalid()) if (E.isInvalid())
return true; return true;
Output = TemplateArgumentLoc(TemplateArgument(E.get()), E.get()); Output = TemplateArgumentLoc(
TemplateArgument(E.get(), /*IsCanonical=*/false), E.get());
return false; return false;
} }
} }
@ -16131,8 +16134,10 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
E->getPackLoc()); E->getPackLoc());
if (DRE.isInvalid()) if (DRE.isInvalid())
return ExprError(); return ExprError();
ArgStorage = TemplateArgument(new (getSema().Context) PackExpansionExpr( ArgStorage = TemplateArgument(
DRE.get(), E->getPackLoc(), std::nullopt)); new (getSema().Context)
PackExpansionExpr(DRE.get(), E->getPackLoc(), std::nullopt),
/*IsCanonical=*/false);
} }
PackArgs = ArgStorage; PackArgs = ArgStorage;
} }

View File

@ -63,7 +63,7 @@ namespace CurrentInstantiation {
struct A0<T>::B5<U>::C3 : A0, B5 { }; struct A0<T>::B5<U>::C3 : A0, B5 { };
template<typename T> 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}} struct B0 : A0 { }; // expected-error {{base class has incomplete type}}
template<typename U> template<typename U>

View File

@ -38,7 +38,7 @@ A<short>::C::B<int*> absip;
template<typename T, typename U> template<typename T, typename U>
struct Outer { struct Outer {
template<typename X, typename Y> struct Inner; 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}} 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 <class T, class U> struct Foo {
template <unsigned long, class X, class Y> struct Bar; template <unsigned long, class X, class Y> struct Bar;
template <class Y> struct Bar<0, T, Y> {}; 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> {}; template <class Y> struct Bar<0, U, Y> {};
// expected-error@-1 {{partial specialization 'Bar<0, int, Y>' cannot be redeclared}} // expected-error@-1 {{partial specialization 'Bar<0, int, Y>' cannot be redeclared}}
}; };

View File

@ -10,6 +10,6 @@ template <typename T>
class boo<T, true>; class boo<T, true>;
template<typename T> 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}}
} }

View File

@ -73,76 +73,47 @@ using test2 = B<int, 1>;
template <template <class T, T...> class S, class T, int N> struct C { template <template <class T, T...> class S, class T, int N> struct C {
using test3 = __make_integer_seq<S, T, N>; 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: `-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: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<S, T, N>' dependent
// CHECK-NEXT: |-name: '__make_integer_seq' qualified // CHECK-NEXT: |-name: '__make_integer_seq'
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq // CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq
// CHECK-NEXT: |-TemplateArgument template 'S' // 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: | | `-TemplateTemplateParmDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:11, col:42> col:42 depth 0 index 0 S
// CHECK-NEXT: |-TemplateArgument type 'T' // CHECK-NEXT: |-TemplateArgument type 'T'
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'T' dependent depth 0 index 1 // 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: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'T'
// CHECK-NEXT: |-TemplateArgument expr 'N' // CHECK-NEXT: `-TemplateArgument expr 'N'
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent> // 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: `-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'
using test4 = __make_integer_seq<A, T, 1>; 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: `-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: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, T, 1>' dependent
// CHECK-NEXT: |-name: '__make_integer_seq' qualified // CHECK-NEXT: |-name: '__make_integer_seq'
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq // CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq
// CHECK-NEXT: |-TemplateArgument template 'A' // CHECK-NEXT: |-TemplateArgument template 'A'
// CHECK-NEXT: | `-ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:1, col:41> col:38 A // CHECK-NEXT: | `-ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:1, col:41> col:38 A
// CHECK-NEXT: |-TemplateArgument type 'T' // CHECK-NEXT: |-TemplateArgument type 'T'
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'T' dependent depth 0 index 1 // 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: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'T'
// CHECK-NEXT: |-TemplateArgument expr '1' // CHECK-NEXT: `-TemplateArgument expr '1'
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent> // 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: `-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
using test5 = __make_integer_seq<A, int, N>; 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: `-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: `-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: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' dependent
// CHECK-NEXT: |-name: '__make_integer_seq' qualified // CHECK-NEXT: |-name: '__make_integer_seq'
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq // CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq
// CHECK-NEXT: |-TemplateArgument template 'A' // CHECK-NEXT: |-TemplateArgument template 'A'
// CHECK-NEXT: | `-ClassTemplateDecl 0x{{.+}} <line:{{.+}}:1, col:41> col:38 A // CHECK-NEXT: | `-ClassTemplateDecl 0x{{.+}} <line:{{.+}}:1, col:41> col:38 A
// CHECK-NEXT: |-TemplateArgument type 'int' // CHECK-NEXT: |-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int' // CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
// CHECK-NEXT: |-TemplateArgument expr 'N' // 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: `-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'
}; };
// expected-no-diagnostics // expected-no-diagnostics

View File

@ -17,33 +17,23 @@ using test1 = __type_pack_element<0, int>;
template<int N, class ...Ts> struct A { template<int N, class ...Ts> struct A {
using test2 = __type_pack_element<N, Ts...>; 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: `-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: |-name: '__type_pack_element' qualified
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element // CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element
// CHECK-NEXT: |-TemplateArgument expr 'N' // CHECK-NEXT: |-TemplateArgument expr 'N'
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast> // 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: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
// CHECK-NEXT: |-TemplateArgument type 'Ts...' // CHECK-NEXT: `-TemplateArgument type 'Ts...'
// CHECK-NEXT: | `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent // 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: `-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: `-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
using test3 = __type_pack_element<0, 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: `-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: |-name: '__type_pack_element' qualified
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element // CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element
// CHECK-NEXT: |-TemplateArgument expr '0' // CHECK-NEXT: |-TemplateArgument expr '0'
@ -51,39 +41,22 @@ template<int N, class ...Ts> struct A {
// CHECK-NEXT: | |-value: Int 0 // CHECK-NEXT: | |-value: Int 0
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast> // 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: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:37> 'int' 0
// CHECK-NEXT: |-TemplateArgument type 'Ts...' // CHECK-NEXT: `-TemplateArgument type 'Ts...'
// CHECK-NEXT: | `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent // 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: `-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: `-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
using test4 = __type_pack_element<N, int>; 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: `-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: `-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: |-name: '__type_pack_element' qualified
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element // CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element
// CHECK-NEXT: |-TemplateArgument expr 'N' // CHECK-NEXT: |-TemplateArgument expr 'N'
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast> // 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: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
// CHECK-NEXT: |-TemplateArgument type 'int' // CHECK-NEXT: `-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} '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'
}; };
// expected-no-diagnostics // expected-no-diagnostics

View File

@ -257,7 +257,7 @@ TEST(TypePrinter, TemplateArgumentsSubstitution_Expressions) {
const int Result = 42; const int Result = 42;
auto *ConstExpr = createBinOpExpr(LHS, RHS, Result); auto *ConstExpr = createBinOpExpr(LHS, RHS, Result);
// Arg is instantiated with '40 + 2' // Arg is instantiated with '40 + 2'
TemplateArgument Arg(ConstExpr); TemplateArgument Arg(ConstExpr, /*IsCanonical=*/false);
// Param has default expr of '42' // Param has default expr of '42'
auto const *Param = Params->getParam(1); auto const *Param = Params->getParam(1);
@ -273,7 +273,7 @@ TEST(TypePrinter, TemplateArgumentsSubstitution_Expressions) {
auto *ConstExpr = createBinOpExpr(LHS, RHS, Result); auto *ConstExpr = createBinOpExpr(LHS, RHS, Result);
// Arg is instantiated with '40 + 1' // Arg is instantiated with '40 + 1'
TemplateArgument Arg(ConstExpr); TemplateArgument Arg(ConstExpr, /*IsCanonical=*/false);
// Param has default expr of '42' // Param has default expr of '42'
auto const *Param = Params->getParam(1); auto const *Param = Params->getParam(1);
@ -289,7 +289,7 @@ TEST(TypePrinter, TemplateArgumentsSubstitution_Expressions) {
auto *ConstExpr = createBinOpExpr(LHS, RHS, Result); auto *ConstExpr = createBinOpExpr(LHS, RHS, Result);
// Arg is instantiated with '4 + 0' // Arg is instantiated with '4 + 0'
TemplateArgument Arg(ConstExpr); TemplateArgument Arg(ConstExpr, /*IsCanonical=*/false);
// Param has is value-dependent expression (i.e., sizeof(T)) // Param has is value-dependent expression (i.e., sizeof(T))
auto const *Param = Params->getParam(3); auto const *Param = Params->getParam(3);