WIP: [clang] store sugared converted arguments on TemplateSpecializationType

Not ready for review

This is a quite large patch, half of which will
be redone following a different approach.

Although it improves sugar retention in template argument
deduction on its own, this is an enabler for resugaring.

This stores the sugared converted template arguments in
a TST, in addition to the existing as-written ones,
so this is quite wasteful.

This is the biggest performance impact on the whole
of resugaring so far, although it is hoped the
new approach will have negligible impact.

This is a continuation of https://reviews.llvm.org/D134113
This commit is contained in:
Matheus Izvekov 2022-09-17 18:07:28 +02:00
parent cfee056b4e
commit 5b6f71b8f6
No known key found for this signature in database
60 changed files with 693 additions and 596 deletions

View File

@ -94,9 +94,9 @@ void UseTransparentFunctorsCheck::check(
unsigned ArgNum = 0; unsigned ArgNum = 0;
const auto *FunctorParentType = const auto *FunctorParentType =
FunctorParentLoc.getType()->castAs<TemplateSpecializationType>(); FunctorParentLoc.getType()->castAs<TemplateSpecializationType>();
for (; ArgNum < FunctorParentType->template_arguments().size(); ++ArgNum) { for (; ArgNum < FunctorParentType->getSpecifiedArguments().size(); ++ArgNum) {
const TemplateArgument &Arg = const TemplateArgument &Arg =
FunctorParentType->template_arguments()[ArgNum]; FunctorParentType->getSpecifiedArguments()[ArgNum];
if (Arg.getKind() != TemplateArgument::Type) if (Arg.getKind() != TemplateArgument::Type)
continue; continue;
QualType ParentArgType = Arg.getAsType(); QualType ParentArgType = Arg.getAsType();
@ -106,7 +106,7 @@ void UseTransparentFunctorsCheck::check(
break; break;
} }
// Functor is a default template argument. // Functor is a default template argument.
if (ArgNum == FunctorParentType->template_arguments().size()) if (ArgNum == FunctorParentType->getSpecifiedArguments().size())
return; return;
TemplateArgumentLoc FunctorLoc = FunctorParentLoc.getArgLoc(ArgNum); TemplateArgumentLoc FunctorLoc = FunctorParentLoc.getArgLoc(ArgNum);
auto FunctorTypeLoc = getInnerTypeLocAs<TemplateSpecializationTypeLoc>( auto FunctorTypeLoc = getInnerTypeLocAs<TemplateSpecializationTypeLoc>(

View File

@ -181,7 +181,7 @@ isCXXComplexTypeMatching(const TemplateSpecializationType *const Template,
if (Template->getAsCXXRecordDecl()->getName() != "complex") if (Template->getAsCXXRecordDecl()->getName() != "complex")
return true; return true;
const auto *Builtin = Template->template_arguments()[0] const auto *Builtin = Template->getSpecifiedArguments()[0]
.getAsType() .getAsType()
.getTypePtr() .getTypePtr()
->getAs<BuiltinType>(); ->getAs<BuiltinType>();

View File

@ -437,9 +437,15 @@ bool hasReservedScope(const DeclContext &DC) {
QualType declaredType(const TypeDecl *D) { QualType declaredType(const TypeDecl *D) {
ASTContext &Context = D->getASTContext(); ASTContext &Context = D->getASTContext();
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 *ArgList = CTSD->getTemplateArgsAsWritten()) {
SmallVector<TemplateArgument, 4> Args(ArgList->arguments().size());
for (unsigned I = 0, E = Args.size(); I < E; ++I)
Args[I] = ArgList->arguments()[I].getArgument();
return Context.getTemplateSpecializationType( return Context.getTemplateSpecializationType(
TemplateName(CTSD->getSpecializedTemplate()), Args->arguments()); TemplateName(CTSD->getSpecializedTemplate()), Args,
/*SugaredConvertedArgs=*/std::nullopt,
/*CanonicalConvertedArgs=*/std::nullopt);
}
return Context.getTypeDeclType(D); return Context.getTypeDeclType(D);
} }

View File

@ -1808,22 +1808,24 @@ public:
bool ParameterPack, bool ParameterPack,
TemplateTypeParmDecl *ParmDecl = nullptr) const; TemplateTypeParmDecl *ParmDecl = nullptr) const;
QualType getTemplateSpecializationType(TemplateName T, QualType getTemplateSpecializationType(
ArrayRef<TemplateArgument> Args, TemplateName T, ArrayRef<TemplateArgument> SpecifiedArgs,
QualType Canon = QualType()) const; ArrayRef<TemplateArgument> SugaredConvertedArgs,
ArrayRef<TemplateArgument> CanonicalConvertedArgs,
QualType Canon = QualType()) const;
QualType QualType getTemplateSpecializationType(
getCanonicalTemplateSpecializationType(TemplateName T, TemplateName T, ArrayRef<TemplateArgumentLoc> SpecifiedArgs,
ArrayRef<TemplateArgument> Args) const; ArrayRef<TemplateArgument> SugaredConvertedArgs,
ArrayRef<TemplateArgument> CanonicalConvertedArgs,
QualType Canon = QualType()) const;
QualType getTemplateSpecializationType(TemplateName T, TypeSourceInfo *getTemplateSpecializationTypeInfo(
ArrayRef<TemplateArgumentLoc> Args, TemplateName T, SourceLocation TLoc,
QualType Canon = QualType()) const; const TemplateArgumentListInfo &SpecifiedArgs,
ArrayRef<TemplateArgument> SugaredConvertedArgs,
TypeSourceInfo * ArrayRef<TemplateArgument> CanonicalConvertedArgs,
getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc, QualType Canon = QualType()) const;
const TemplateArgumentListInfo &Args,
QualType Canon = QualType()) const;
QualType getParenType(QualType NamedType) const; QualType getParenType(QualType NamedType) const;
@ -2939,6 +2941,12 @@ 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;
/// 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

@ -456,7 +456,7 @@ public:
Visit(T->getArgumentPack()); Visit(T->getArgumentPack());
} }
void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
for (const auto &Arg : T->template_arguments()) for (const auto &Arg : T->getSpecifiedArguments())
Visit(Arg); Visit(Arg);
} }
void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {

View File

@ -610,8 +610,10 @@ public:
Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs, Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs,
const ASTContext &Context) { const ASTContext &Context) {
ID.AddInteger(TemplateArgs.size()); ID.AddInteger(TemplateArgs.size());
// We allow instantiating deduction guides with non-canonical template
// arguments.
for (const TemplateArgument &TemplateArg : TemplateArgs) for (const TemplateArgument &TemplateArg : TemplateArgs)
TemplateArg.Profile(ID, Context); TemplateArg.Profile(ID, Context, /*Canonical=*/false);
} }
}; };
@ -2090,7 +2092,7 @@ public:
const ASTContext &Context) { const ASTContext &Context) {
ID.AddInteger(TemplateArgs.size()); ID.AddInteger(TemplateArgs.size());
for (const TemplateArgument &TemplateArg : TemplateArgs) for (const TemplateArgument &TemplateArg : TemplateArgs)
TemplateArg.Profile(ID, Context); TemplateArg.Profile(ID, Context, /*Canonical=*/true);
} }
static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@ -2864,7 +2866,7 @@ public:
const ASTContext &Context) { const ASTContext &Context) {
ID.AddInteger(TemplateArgs.size()); ID.AddInteger(TemplateArgs.size());
for (const TemplateArgument &TemplateArg : TemplateArgs) for (const TemplateArgument &TemplateArg : TemplateArgs)
TemplateArg.Profile(ID, Context); TemplateArg.Profile(ID, Context, /*Canonical=*/true);
} }
static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const Decl *D) { return classofKind(D->getKind()); }

View File

@ -1134,7 +1134,10 @@ DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {
DEF_TRAVERSE_TYPE(TemplateSpecializationType, { DEF_TRAVERSE_TYPE(TemplateSpecializationType, {
TRY_TO(TraverseTemplateName(T->getTemplateName())); TRY_TO(TraverseTemplateName(T->getTemplateName()));
TRY_TO(TraverseTemplateArguments(T->template_arguments())); if (T->isCanonicalUnqualified())
TRY_TO(TraverseTemplateArguments(T->getConvertedArguments()));
else
TRY_TO(TraverseTemplateArguments(T->getSpecifiedArguments()));
}) })
DEF_TRAVERSE_TYPE(InjectedClassNameType, {}) DEF_TRAVERSE_TYPE(InjectedClassNameType, {})

View File

@ -462,7 +462,8 @@ public:
void dump() const; void dump() const;
/// Used to insert TemplateArguments into FoldingSets. /// Used to insert TemplateArguments into FoldingSets.
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const; void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
bool Canonical) const;
}; };
/// Location information for a TemplateArgument. /// Location information for a TemplateArgument.

View File

@ -2199,10 +2199,9 @@ protected:
/// specialization, which is expected to be able to hold at least 1024 /// specialization, which is expected to be able to hold at least 1024
/// according to [implimits]. However, as this limit is somewhat easy to /// according to [implimits]. However, as this limit is somewhat easy to
/// hit with template metaprogramming we'd prefer to keep it as large /// hit with template metaprogramming we'd prefer to keep it as large
/// as possible. At the moment it has been left as a non-bitfield since /// as possible.
/// this type safely fits in 64 bits as an unsigned, so there is no reason unsigned NumSpecifiedArgs : 16;
/// to introduce the performance impact of a bitfield. unsigned NumConvertedArgs : 16;
unsigned NumArgs;
}; };
class DependentTemplateSpecializationTypeBitfields { class DependentTemplateSpecializationTypeBitfields {
@ -2821,6 +2820,18 @@ public:
/// immediately following this class. /// immediately following this class.
template <typename T> const T *getAs() const; template <typename T> const T *getAs() const;
/// Look through sugar for an instance of TemplateSpecializationType which
/// is not a type alias.
const TemplateSpecializationType *
getAsNonAliasTemplateSpecializationType() const;
const TemplateSpecializationType *
castAsNonAliasTemplateSpecializationType() const {
auto TST = getAsNonAliasTemplateSpecializationType();
assert(TST && "not a TemplateSpecializationType");
return TST;
}
/// Member-template getAsAdjusted<specific type>. Look through specific kinds /// Member-template getAsAdjusted<specific type>. Look through specific kinds
/// of sugar (parens, attributes, etc) for an instance of \<specific type>. /// of sugar (parens, attributes, etc) for an instance of \<specific type>.
/// This is used when you need to walk over sugar nodes that represent some /// This is used when you need to walk over sugar nodes that represent some
@ -6594,7 +6605,7 @@ public:
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, static void 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, bool Canonical);
static bool classof(const Type *T) { static bool classof(const Type *T) {
return T->getTypeClass() == Auto; return T->getTypeClass() == Auto;
@ -6672,10 +6683,10 @@ 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> SpecifiedArgs,
QualType Canon, ArrayRef<TemplateArgument> ConvertedArgs,
QualType Aliased); QualType Underlying);
public: public:
/// Determine whether any of the given template arguments are dependent. /// Determine whether any of the given template arguments are dependent.
@ -6728,11 +6739,13 @@ public:
/// Retrieve the name of the template that we are specializing. /// Retrieve the name of the template that we are specializing.
TemplateName getTemplateName() const { return Template; } TemplateName getTemplateName() const { return Template; }
ArrayRef<TemplateArgument> template_arguments() const { ArrayRef<TemplateArgument> getSpecifiedArguments() const {
return {reinterpret_cast<const TemplateArgument *>(this + 1), return {reinterpret_cast<const TemplateArgument *>(this + 1),
TemplateSpecializationTypeBits.NumArgs}; TemplateSpecializationTypeBits.NumSpecifiedArgs};
} }
ArrayRef<TemplateArgument> getConvertedArguments() const;
bool isSugared() const { bool isSugared() const {
return !isDependentType() || isCurrentInstantiation() || isTypeAlias(); return !isDependentType() || isCurrentInstantiation() || isTypeAlias();
} }
@ -6743,8 +6756,10 @@ 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> SpecifiedArgs,
const ASTContext &Context); ArrayRef<TemplateArgument> ConvertedArgs,
QualType Underlying, const ASTContext &Context,
bool Canonical);
static bool classof(const Type *T) { static bool classof(const Type *T) {
return T->getTypeClass() == TemplateSpecialization; return T->getTypeClass() == TemplateSpecialization;
@ -7099,13 +7114,14 @@ public:
QualType desugar() const { return QualType(this, 0); } QualType desugar() const { return QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
Profile(ID, Context, getKeyword(), Name, template_arguments()); Profile(ID, Context, getKeyword(), Name, template_arguments(),
isCanonicalUnqualified());
} }
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
ElaboratedTypeKeyword Keyword, ElaboratedTypeKeyword Keyword,
const DependentTemplateStorage &Name, const DependentTemplateStorage &Name,
ArrayRef<TemplateArgument> Args); ArrayRef<TemplateArgument> Args, bool IsCanonical);
static bool classof(const Type *T) { static bool classof(const Type *T) {
return T->getTypeClass() == DependentTemplateSpecialization; return T->getTypeClass() == DependentTemplateSpecialization;

View File

@ -1718,7 +1718,7 @@ public:
} }
unsigned getNumArgs() const { unsigned getNumArgs() const {
return getTypePtr()->template_arguments().size(); return getTypePtr()->getSpecifiedArguments().size();
} }
void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) { void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) {
@ -1730,7 +1730,7 @@ public:
} }
TemplateArgumentLoc getArgLoc(unsigned i) const { TemplateArgumentLoc getArgLoc(unsigned i) const {
return TemplateArgumentLoc(getTypePtr()->template_arguments()[i], return TemplateArgumentLoc(getTypePtr()->getSpecifiedArguments()[i],
getArgLocInfo(i)); getArgLocInfo(i));
} }
@ -1766,7 +1766,7 @@ public:
setTemplateNameLoc(Loc); setTemplateNameLoc(Loc);
setLAngleLoc(Loc); setLAngleLoc(Loc);
setRAngleLoc(Loc); setRAngleLoc(Loc);
initializeArgLocs(Context, getTypePtr()->template_arguments(), initializeArgLocs(Context, getTypePtr()->getSpecifiedArguments(),
getArgInfos(), Loc); getArgInfos(), Loc);
} }

View File

@ -743,29 +743,27 @@ let Class = TemplateSpecializationType in {
def : Property<"templateName", TemplateName> { def : Property<"templateName", TemplateName> {
let Read = [{ node->getTemplateName() }]; let Read = [{ node->getTemplateName() }];
} }
def : Property<"templateArguments", Array<TemplateArgument>> { def : Property<"specifiedArguments", Array<TemplateArgument>> {
let Read = [{ node->template_arguments() }]; let Read = [{ node->getSpecifiedArguments() }];
} }
def : Property<"underlyingType", Optional<QualType>> { def : Property<"convertedArguments", Array<TemplateArgument>> {
let Read = [{ node->getConvertedArguments() }];
}
def : Property<"underlyingType", QualType> {
let Read = [{ let Read = [{
node->isTypeAlias() node->isTypeAlias()
? std::optional<QualType>(node->getAliasedType()) ? node->getAliasedType()
: node->isCanonicalUnqualified() : node->isCanonicalUnqualified()
? std::nullopt ? QualType() : node->getCanonicalTypeInternal()
: std::optional<QualType>(node->getCanonicalTypeInternal())
}]; }];
} }
def : Creator<[{ def : Creator<[{
QualType result; QualType result = ctx.getTemplateSpecializationType(templateName,
if (!underlyingType) { specifiedArguments,
result = ctx.getCanonicalTemplateSpecializationType(templateName, convertedArguments,
templateArguments); /*CanonicalConvertedArguments=*/{},
} else { underlyingType);
result = ctx.getTemplateSpecializationType(templateName,
templateArguments,
*underlyingType);
}
if (dependent) if (dependent)
const_cast<Type *>(result.getTypePtr()) const_cast<Type *>(result.getTypePtr())
->addDependence(TypeDependence::DependentInstantiation); ->addDependence(TypeDependence::DependentInstantiation);

View File

@ -1949,7 +1949,7 @@ getTemplateSpecializationArgs(const VarTemplateSpecializationDecl &D) {
inline ArrayRef<TemplateArgument> inline ArrayRef<TemplateArgument>
getTemplateSpecializationArgs(const TemplateSpecializationType &T) { getTemplateSpecializationArgs(const TemplateSpecializationType &T) {
return T.template_arguments(); return T.getSpecifiedArguments();
} }
inline ArrayRef<TemplateArgument> inline ArrayRef<TemplateArgument>

View File

@ -6983,7 +6983,7 @@ def err_illegal_decl_mempointer_to_void : Error<
"'%0' declared as a member pointer to void">; "'%0' declared as a member pointer to void">;
def err_illegal_decl_mempointer_in_nonclass def err_illegal_decl_mempointer_in_nonclass
: Error<"%0 does not point into a class">; : Error<"%0 does not point into a class">;
def err_reference_to_void : Error<"cannot form a reference to 'void'">; def err_reference_to_void : Error<"cannot form a reference to %0">;
def err_nonfunction_block_type : Error< def err_nonfunction_block_type : Error<
"block pointer to non-function type is invalid">; "block pointer to non-function type is invalid">;
def err_return_block_has_expr : Error<"void block should not return a value">; def err_return_block_has_expr : Error<"void block should not return a value">;

View File

@ -49,9 +49,9 @@ struct alignas(ConstraintAlignment) AtomicConstraint {
for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I) { for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I) {
llvm::FoldingSetNodeID IDA, IDB; llvm::FoldingSetNodeID IDA, IDB;
C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument()) C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument())
.Profile(IDA, C); .Profile(IDA, C, /*Canonical=*/true);
C.getCanonicalTemplateArgument((*Other.ParameterMapping)[I].getArgument()) C.getCanonicalTemplateArgument((*Other.ParameterMapping)[I].getArgument())
.Profile(IDB, C); .Profile(IDB, C, /*Canonical=*/true);
if (IDA != IDB) if (IDA != IDB)
return false; return false;
} }

View File

@ -247,6 +247,10 @@ public:
void readTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs, void readTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs,
bool Canonicalize = false); bool Canonicalize = false);
/// Read a template argument list.
const TemplateArgumentList *
readTemplateArgumentList(bool Canonicalize = false);
/// Read a UnresolvedSet structure, advancing Idx. /// Read a UnresolvedSet structure, advancing Idx.
void readUnresolvedSet(LazyASTUnresolvedSet &Set); void readUnresolvedSet(LazyASTUnresolvedSet &Set);

View File

@ -80,7 +80,7 @@ void ConstraintSatisfaction::Profile(
ID.AddPointer(ConstraintOwner); ID.AddPointer(ConstraintOwner);
ID.AddInteger(TemplateArgs.size()); ID.AddInteger(TemplateArgs.size());
for (auto &Arg : TemplateArgs) for (auto &Arg : TemplateArgs)
Arg.Profile(ID, C); Arg.Profile(ID, C, /*Canonical=*/false);
} }
ConceptReference * ConceptReference *

View File

@ -3083,14 +3083,28 @@ 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);
TemplateArgument OrigArg = Arg;
Arg = C.getCanonicalTemplateArgument(Arg);
AnyNonCanonArgs |= !Arg.structurallyEquals(OrigArg);
}
return CanonArgs; return CanonArgs;
} }
bool ASTContext::canonicalizeTemplateArguments(
MutableArrayRef<TemplateArgument> Args) const {
bool AnyNonCanonArgs = false;
for (auto &Arg : Args) {
TemplateArgument OrigArg = Arg;
Arg = getCanonicalTemplateArgument(Arg);
if (Arg.getKind() == TemplateArgument::Expression) {
llvm::FoldingSetNodeID ID1, ID2;
OrigArg.getAsExpr()->Profile(ID1, *this, /*Canonical=*/false);
Arg.getAsExpr()->Profile(ID2, *this, /*Canonical=*/true);
AnyNonCanonArgs |= ID1 != ID2;
} else {
AnyNonCanonArgs |= !Arg.structurallyEquals(OrigArg);
}
}
return AnyNonCanonArgs;
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Type creation/memoization methods // Type creation/memoization methods
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -5538,41 +5552,41 @@ 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> SugaredConvertedArgs,
QualType Underlying) const { ArrayRef<TemplateArgument> CanonicalConvertedArgs,
assert(!Name.getAsDependentTemplateName() && QualType Underlying) const {
"No dependent template names here!"); QualType TST = getTemplateSpecializationType(
QualType TST = Name, SpecifiedArgs.arguments(), SugaredConvertedArgs,
getTemplateSpecializationType(Name, Args.arguments(), Underlying); CanonicalConvertedArgs, 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> SugaredConvertedArgs,
QualType Underlying) const { ArrayRef<TemplateArgument> CanonicalConvertedArgs,
assert(!Template.getAsDependentTemplateName() && QualType Underlying) const {
"No dependent template names here!"); SmallVector<TemplateArgument, 4> SpecifiedArgVec;
SpecifiedArgVec.reserve(SpecifiedArgs.size());
for (const TemplateArgumentLoc &Arg : SpecifiedArgs)
SpecifiedArgVec.push_back(Arg.getArgument());
SmallVector<TemplateArgument, 4> ArgVec; return getTemplateSpecializationType(Template, SpecifiedArgVec,
ArgVec.reserve(Args.size()); SugaredConvertedArgs,
for (const TemplateArgumentLoc &Arg : Args) CanonicalConvertedArgs, Underlying);
ArgVec.push_back(Arg.getArgument());
return getTemplateSpecializationType(Template, ArgVec, Underlying);
} }
#ifndef NDEBUG #ifndef NDEBUG
@ -5585,82 +5599,90 @@ static bool hasAnyPackExpansions(ArrayRef<TemplateArgument> Args) {
} }
#endif #endif
QualType QualType ASTContext::getTemplateSpecializationType(
ASTContext::getTemplateSpecializationType(TemplateName Template, TemplateName Template, ArrayRef<TemplateArgument> SpecifiedArgs,
ArrayRef<TemplateArgument> Args, ArrayRef<TemplateArgument> SugaredConvertedArgs,
QualType Underlying) const { ArrayRef<TemplateArgument> CanonicalConvertedArgs,
QualType Underlying) const {
assert(!Template.getAsDependentTemplateName() && assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!"); "No dependent template names here!");
SmallVector<TemplateArgument, 4> CanonArgsVec;
TemplateName CanonTemplate =
getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true);
bool NonCanonical = !SpecifiedArgs.empty() || !Underlying.isNull() ||
Template != CanonTemplate;
if (CanonicalConvertedArgs.size() != 0) {
if (SugaredConvertedArgs.empty()) {
SugaredConvertedArgs = CanonicalConvertedArgs;
} else if (!NonCanonical) {
for (unsigned I = 0; I < SugaredConvertedArgs.size(); ++I) {
TemplateArgument C = CanonicalConvertedArgs[I];
TemplateArgument S = SugaredConvertedArgs[I];
assert(C.getKind() == S.getKind());
if (C.getKind() == TemplateArgument::Expression) {
llvm::FoldingSetNodeID ID1, ID2;
C.getAsExpr()->Profile(ID1, *this, /*Canonical=*/true);
S.getAsExpr()->Profile(ID2, *this, /*Canonical=*/false);
if (ID1 != ID2) {
NonCanonical = true;
break;
}
} else if (!C.structurallyEquals(S)) {
NonCanonical = true;
break;
}
}
}
} else {
CanonArgsVec = ::getCanonicalTemplateArguments(*this, SugaredConvertedArgs,
NonCanonical);
CanonicalConvertedArgs = CanonArgsVec;
}
assert(SugaredConvertedArgs.size() == CanonicalConvertedArgs.size());
llvm::FoldingSetNodeID ID;
TemplateSpecializationType::Profile(ID, Template, SpecifiedArgs,
SugaredConvertedArgs, Underlying, *this,
/*Canonical=*/!NonCanonical);
void *InsertPos = nullptr;
if (auto *T = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(T, 0);
const auto *TD = Template.getAsTemplateDecl(/*IgnoreDeduced=*/true); const auto *TD = Template.getAsTemplateDecl(/*IgnoreDeduced=*/true);
bool IsTypeAlias = TD && TD->isTypeAlias(); bool IsTypeAlias = TD && TD->isTypeAlias();
QualType CanonType; if (Underlying.isNull()) {
if (!Underlying.isNull()) // We can get here with an alias template when the specialization
CanonType = getCanonicalType(Underlying); // contains a pack expansion that does not match up with a parameter
else { // pack.
// We can get here with an alias template when the specialization contains assert((!IsTypeAlias || hasAnyPackExpansions(CanonicalConvertedArgs)) &&
// a pack expansion that does not match up with a parameter pack.
assert((!IsTypeAlias || hasAnyPackExpansions(Args)) &&
"Caller must compute aliased type"); "Caller must compute aliased type");
IsTypeAlias = false; IsTypeAlias = false;
CanonType = getCanonicalTemplateSpecializationType(Template, Args);
if (NonCanonical) {
Underlying = getTemplateSpecializationType(
CanonTemplate, ArrayRef<TemplateArgument>(), std::nullopt,
CanonicalConvertedArgs, QualType());
assert(Underlying->isDependentType() &&
"Non-dependent template-id type must have a canonical type");
[[maybe_unused]] const auto *Found =
TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(!Found);
}
} }
// Allocate the (non-canonical) template specialization type, but don't void *Mem =
// try to unique it: these types typically have location information that Allocate(sizeof(TemplateSpecializationType) +
// we don't unique and don't want to lose. sizeof(TemplateArgument) *
void *Mem = Allocate(sizeof(TemplateSpecializationType) + (SpecifiedArgs.size() + SugaredConvertedArgs.size()) +
sizeof(TemplateArgument) * Args.size() + (IsTypeAlias ? sizeof(QualType) : 0),
(IsTypeAlias ? sizeof(QualType) : 0), alignof(TemplateSpecializationType));
alignof(TemplateSpecializationType)); auto *Spec = new (Mem) TemplateSpecializationType(
auto *Spec Template, IsTypeAlias, SpecifiedArgs, SugaredConvertedArgs, Underlying);
= new (Mem) TemplateSpecializationType(Template, Args, CanonType,
IsTypeAlias ? Underlying : QualType());
Types.push_back(Spec); Types.push_back(Spec);
return QualType(Spec, 0); TemplateSpecializationTypes.InsertNode(Spec, InsertPos);
}
QualType ASTContext::getCanonicalTemplateSpecializationType(
TemplateName Template, ArrayRef<TemplateArgument> Args) const {
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
// Build the canonical template specialization type.
// Any DeducedTemplateNames are ignored, because the effective name of a TST
// accounts for the TST arguments laid over any default arguments contained in
// its name.
TemplateName CanonTemplate =
getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true);
bool AnyNonCanonArgs = false;
auto CanonArgs =
::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs);
// Determine whether this canonical template specialization type already
// exists.
llvm::FoldingSetNodeID ID;
TemplateSpecializationType::Profile(ID, CanonTemplate,
CanonArgs, *this);
void *InsertPos = nullptr;
TemplateSpecializationType *Spec
= TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
if (!Spec) {
// Allocate a new canonical template specialization type.
void *Mem = Allocate((sizeof(TemplateSpecializationType) +
sizeof(TemplateArgument) * CanonArgs.size()),
alignof(TemplateSpecializationType));
Spec = new (Mem) TemplateSpecializationType(CanonTemplate,
CanonArgs,
QualType(), QualType());
Types.push_back(Spec);
TemplateSpecializationTypes.InsertNode(Spec, InsertPos);
}
assert(Spec->isDependentType() &&
"Non-dependent template-id type must have a canonical type");
return QualType(Spec, 0); return QualType(Spec, 0);
} }
@ -5773,7 +5795,8 @@ QualType ASTContext::getDependentTemplateSpecializationType(
ElaboratedTypeKeyword Keyword, const DependentTemplateStorage &Name, ElaboratedTypeKeyword Keyword, const DependentTemplateStorage &Name,
ArrayRef<TemplateArgument> Args, bool IsCanonical) const { ArrayRef<TemplateArgument> Args, bool IsCanonical) const {
llvm::FoldingSetNodeID ID; llvm::FoldingSetNodeID ID;
DependentTemplateSpecializationType::Profile(ID, *this, Keyword, Name, Args); DependentTemplateSpecializationType::Profile(ID, *this, Keyword, Name, Args,
IsCanonical);
void *InsertPos = nullptr; void *InsertPos = nullptr;
if (auto *T = DependentTemplateSpecializationTypes.FindNodeOrInsertPos( if (auto *T = DependentTemplateSpecializationTypes.FindNodeOrInsertPos(
@ -6448,7 +6471,7 @@ QualType ASTContext::getAutoTypeInternal(
!DeducedType.isNull() && DeducedType->isDependentType(); !DeducedType.isNull() && DeducedType->isDependentType();
AutoType::Profile(ID, *this, DeducedType, Keyword, AutoType::Profile(ID, *this, DeducedType, Keyword,
IsDependent || IsDeducedDependent, TypeConstraintConcept, IsDependent || IsDeducedDependent, TypeConstraintConcept,
TypeConstraintArgs); TypeConstraintArgs, /*Canonical=*/IsCanon);
if (auto const AT_iter = AutoTypes.find(ID); AT_iter != AutoTypes.end()) if (auto const AT_iter = AutoTypes.find(ID); AT_iter != AutoTypes.end())
return QualType(AT_iter->getSecond(), 0); return QualType(AT_iter->getSecond(), 0);
@ -6462,9 +6485,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);
} }
} }
} }
@ -7011,7 +7034,7 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name,
getCanonicalTemplateArgument(subst->getArgumentPack()); getCanonicalTemplateArgument(subst->getArgumentPack());
return getSubstTemplateTemplateParmPack( return getSubstTemplateTemplateParmPack(
canonArgPack, subst->getAssociatedDecl()->getCanonicalDecl(), canonArgPack, subst->getAssociatedDecl()->getCanonicalDecl(),
subst->getFinal(), subst->getIndex()); subst->getIndex(), subst->getFinal());
} }
case TemplateName::DeducedTemplate: { case TemplateName::DeducedTemplate: {
assert(IgnoreDeduced == false); assert(IgnoreDeduced == false);
@ -8200,8 +8223,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();
} }
@ -13981,13 +14003,16 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
case Type::TemplateSpecialization: { case Type::TemplateSpecialization: {
const auto *TX = cast<TemplateSpecializationType>(X), const auto *TX = cast<TemplateSpecializationType>(X),
*TY = cast<TemplateSpecializationType>(Y); *TY = cast<TemplateSpecializationType>(Y);
auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(), auto SpecAs = getCommonTemplateArguments(Ctx, TX->getSpecifiedArguments(),
TY->template_arguments()); TY->getSpecifiedArguments());
auto ConvAs = getCommonTemplateArguments(Ctx, TX->getConvertedArguments(),
TY->getConvertedArguments());
return Ctx.getTemplateSpecializationType( return Ctx.getTemplateSpecializationType(
::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(), ::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(),
TY->getTemplateName(), TY->getTemplateName(),
/*IgnoreDeduced=*/true), /*IgnoreDeduced=*/true),
As, X->getCanonicalTypeInternal()); SpecAs, ConvAs, /*CanonicalConvertedArgs=*/{},
X->getCanonicalTypeInternal());
} }
case Type::Decltype: { case Type::Decltype: {
const auto *DX = cast<DecltypeType>(X); const auto *DX = cast<DecltypeType>(X);
@ -14227,11 +14252,14 @@ 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> SpecAs;
if (getCommonTemplateArguments(Ctx, Args, TX->template_arguments(), if (getCommonTemplateArguments(Ctx, SpecAs, TX->getSpecifiedArguments(),
TY->template_arguments())) TY->getSpecifiedArguments()))
return QualType(); return QualType();
return Ctx.getTemplateSpecializationType(CTN, Args, auto ConvAs = getCommonTemplateArguments(Ctx, TX->getConvertedArguments(),
TY->getConvertedArguments());
return Ctx.getTemplateSpecializationType(CTN, SpecAs, ConvAs,
/*CanonicalConvertedArgs=*/{},
Ctx.getQualifiedType(Underlying)); Ctx.getQualifiedType(Underlying));
} }
case Type::Typedef: { case Type::Typedef: {

View File

@ -117,7 +117,7 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT,
if (!TST->isTypeAlias()) { if (!TST->isTypeAlias()) {
bool DesugarArgument = false; bool DesugarArgument = false;
SmallVector<TemplateArgument, 4> Args; SmallVector<TemplateArgument, 4> Args;
for (const TemplateArgument &Arg : TST->template_arguments()) { for (const TemplateArgument &Arg : TST->getSpecifiedArguments()) {
if (Arg.getKind() == TemplateArgument::Type) if (Arg.getKind() == TemplateArgument::Type)
Args.push_back(desugarForDiagnostic(Context, Arg.getAsType(), Args.push_back(desugarForDiagnostic(Context, Arg.getAsType(),
DesugarArgument)); DesugarArgument));
@ -128,7 +128,8 @@ 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, TST->getConvertedArguments(),
/*CanonicalConvertedArguments=*/std::nullopt, QT);
} }
break; break;
} }
@ -985,7 +986,7 @@ class TemplateDiff {
if (isEnd()) return; if (isEnd()) return;
// Set to first template argument. If not a parameter pack, done. // Set to first template argument. If not a parameter pack, done.
TemplateArgument TA = TST->template_arguments()[0]; TemplateArgument TA = TST->getSpecifiedArguments()[0];
if (TA.getKind() != TemplateArgument::Pack) return; if (TA.getKind() != TemplateArgument::Pack) return;
// Start looking into the parameter pack. // Start looking into the parameter pack.
@ -1006,7 +1007,7 @@ class TemplateDiff {
/// isEnd - Returns true if the iterator is one past the end. /// isEnd - Returns true if the iterator is one past the end.
bool isEnd() const { bool isEnd() const {
assert(TST && "InternalIterator is invalid with a null TST."); assert(TST && "InternalIterator is invalid with a null TST.");
return Index >= TST->template_arguments().size(); return Index >= TST->getSpecifiedArguments().size();
} }
/// &operator++ - Increment the iterator to the next template argument. /// &operator++ - Increment the iterator to the next template argument.
@ -1026,11 +1027,11 @@ class TemplateDiff {
// Loop until a template argument is found, or the end is reached. // Loop until a template argument is found, or the end is reached.
while (true) { while (true) {
// Advance to the next template argument. Break if reached the end. // Advance to the next template argument. Break if reached the end.
if (++Index == TST->template_arguments().size()) if (++Index == TST->getSpecifiedArguments().size())
break; break;
// If the TemplateArgument is not a parameter pack, done. // If the TemplateArgument is not a parameter pack, done.
TemplateArgument TA = TST->template_arguments()[Index]; TemplateArgument TA = TST->getSpecifiedArguments()[Index];
if (TA.getKind() != TemplateArgument::Pack) if (TA.getKind() != TemplateArgument::Pack)
break; break;
@ -1050,7 +1051,7 @@ class TemplateDiff {
assert(TST && "InternalIterator is invalid with a null TST."); assert(TST && "InternalIterator is invalid with a null TST.");
assert(!isEnd() && "Index exceeds number of arguments."); assert(!isEnd() && "Index exceeds number of arguments.");
if (CurrentTA == EndTA) if (CurrentTA == EndTA)
return TST->template_arguments()[Index]; return TST->getSpecifiedArguments()[Index];
else else
return *CurrentTA; return *CurrentTA;
} }
@ -1134,9 +1135,11 @@ class TemplateDiff {
return nullptr; return nullptr;
Ty = Context.getTemplateSpecializationType( Ty = Context.getTemplateSpecializationType(
TemplateName(CTSD->getSpecializedTemplate()), TemplateName(CTSD->getSpecializedTemplate()),
CTSD->getTemplateArgs().asArray(), /*SpecifiedArgs=*/CTSD->getTemplateArgs().asArray(),
Ty.getLocalUnqualifiedType().getCanonicalType()); /*SugaredConvertedArgs=*/CTSD->getTemplateArgs().asArray(),
/*CanonicalConvertedArgs=*/std::nullopt,
Ty.getLocalUnqualifiedType().getCanonicalType());
return Ty->getAs<TemplateSpecializationType>(); return Ty->getAs<TemplateSpecializationType>();
} }

View File

@ -1657,7 +1657,12 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType(
SmallVector<TemplateArgument, 2> ToTemplateArgs; SmallVector<TemplateArgument, 2> ToTemplateArgs;
if (Error Err = if (Error Err =
ImportTemplateArguments(T->template_arguments(), ToTemplateArgs)) ImportTemplateArguments(T->getSpecifiedArguments(), ToTemplateArgs))
return std::move(Err);
SmallVector<TemplateArgument, 2> ToConvertedArgs;
if (Error Err =
ImportTemplateArguments(T->getConvertedArguments(), ToConvertedArgs))
return std::move(Err); return std::move(Err);
QualType ToCanonType; QualType ToCanonType;
@ -1669,9 +1674,9 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType(
else else
return TyOrErr.takeError(); return TyOrErr.takeError();
} }
return Importer.getToContext().getTemplateSpecializationType(*ToTemplateOrErr, return Importer.getToContext().getTemplateSpecializationType(
ToTemplateArgs, *ToTemplateOrErr, ToTemplateArgs, ToConvertedArgs,
ToCanonType); /*CanonicalConvertedArgs=*/std::nullopt, ToCanonType);
} }
ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) {
@ -3634,7 +3639,7 @@ public:
std::optional<bool> std::optional<bool>
VisitTemplateSpecializationType(const TemplateSpecializationType *T) { VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
for (const auto &Arg : T->template_arguments()) for (const auto &Arg : T->getSpecifiedArguments())
if (checkTemplateArgument(Arg)) if (checkTemplateArgument(Arg))
return true; return true;
// This type is a "sugar" to a record type, it can have a desugared type. // This type is a "sugar" to a record type, it can have a desugared type.

View File

@ -1268,8 +1268,11 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(), if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(),
Spec2->getTemplateName())) Spec2->getTemplateName()))
return false; return false;
if (!IsStructurallyEquivalent(Context, Spec1->template_arguments(), if (!IsStructurallyEquivalent(Context, Spec1->getSpecifiedArguments(),
Spec2->template_arguments())) Spec2->getSpecifiedArguments()))
return false;
if (!IsStructurallyEquivalent(Context, Spec1->getConvertedArguments(),
Spec2->getConvertedArguments()))
return false; return false;
break; break;
} }

View File

@ -601,7 +601,7 @@ void ClassTemplatePartialSpecializationDecl::Profile(
TemplateParameterList *TPL, const ASTContext &Context) { TemplateParameterList *TPL, const ASTContext &Context) {
ID.AddInteger(TemplateArgs.size()); ID.AddInteger(TemplateArgs.size());
for (const TemplateArgument &TemplateArg : TemplateArgs) for (const TemplateArgument &TemplateArg : TemplateArgs)
TemplateArg.Profile(ID, Context); TemplateArg.Profile(ID, Context, /*Canonical=*/true);
TPL->Profile(ID, Context); TPL->Profile(ID, Context);
} }
@ -671,8 +671,12 @@ 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));
auto TemplateArgs = getTemplateParameters()->getInjectedTemplateArgs(Context);
CommonPtr->InjectedClassNameType = Context.getTemplateSpecializationType( CommonPtr->InjectedClassNameType = Context.getTemplateSpecializationType(
Name, getTemplateParameters()->getInjectedTemplateArgs(Context)); Name,
/*SpecifiedArgs=*/TemplateArgs,
/*SugaredConvertedArgs=*/TemplateArgs,
/*CanonicalConvertedArgs=*/std::nullopt);
return CommonPtr->InjectedClassNameType; return CommonPtr->InjectedClassNameType;
} }
@ -1363,7 +1367,7 @@ void VarTemplatePartialSpecializationDecl::Profile(
TemplateParameterList *TPL, const ASTContext &Context) { TemplateParameterList *TPL, const ASTContext &Context) {
ID.AddInteger(TemplateArgs.size()); ID.AddInteger(TemplateArgs.size());
for (const TemplateArgument &TemplateArg : TemplateArgs) for (const TemplateArgument &TemplateArg : TemplateArgs)
TemplateArg.Profile(ID, Context); TemplateArg.Profile(ID, Context, /*Canonical=*/true);
TPL->Profile(ID, Context); TPL->Profile(ID, Context);
} }

View File

@ -1320,7 +1320,9 @@ void CXXNameMangler::manglePrefix(QualType type) {
// FIXME: GCC does not appear to mangle the template arguments when // FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we // the template in question is a dependent template name. Should we
// emulate that badness? // emulate that badness?
mangleTemplateArgs(TST->getTemplateName(), TST->template_arguments()); auto Args = TST->isCanonicalUnqualified() ? TST->getConvertedArguments()
: TST->getSpecifiedArguments();
mangleTemplateArgs(TST->getTemplateName(), Args);
addSubstitution(QualType(TST, 0)); addSubstitution(QualType(TST, 0));
} }
} else if (const auto *DTST = } else if (const auto *DTST =
@ -2560,13 +2562,14 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
break; break;
} }
} }
auto Args = TST->isCanonicalUnqualified() ? TST->getConvertedArguments()
: TST->getSpecifiedArguments();
// Note: we don't pass in the template name here. We are mangling the // Note: we don't pass in the template name here. We are mangling the
// original source-level template arguments, so we shouldn't consider // original source-level template arguments, so we shouldn't consider
// conversions to the corresponding template parameter. // conversions to the corresponding template parameter.
// FIXME: Other compilers mangle partially-resolved template arguments in // FIXME: Other compilers mangle partially-resolved template arguments in
// unresolved-qualifier-levels. // unresolved-qualifier-levels.
mangleTemplateArgs(TemplateName(), TST->template_arguments()); mangleTemplateArgs(TemplateName(), Args);
break; break;
} }
@ -4438,8 +4441,10 @@ void CXXNameMangler::mangleType(const InjectedClassNameType *T) {
} }
void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
auto Args = T->isCanonicalUnqualified() ? T->getConvertedArguments()
: T->getSpecifiedArguments();
if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) { if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) {
mangleTemplateName(TD, T->template_arguments()); mangleTemplateName(TD, Args);
} else { } else {
if (mangleSubstitution(QualType(T, 0))) if (mangleSubstitution(QualType(T, 0)))
return; return;
@ -4449,7 +4454,7 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
// FIXME: GCC does not appear to mangle the template arguments when // FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we // the template in question is a dependent template name. Should we
// emulate that badness? // emulate that badness?
mangleTemplateArgs(T->getTemplateName(), T->template_arguments()); mangleTemplateArgs(T->getTemplateName(), Args);
addSubstitution(QualType(T, 0)); addSubstitution(QualType(T, 0));
} }
} }

View File

@ -1189,8 +1189,8 @@ public:
void VisitEnumType(const EnumType *T) { VisitTagType(T); } void VisitEnumType(const EnumType *T) { VisitTagType(T); }
void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
ID.AddInteger(T->template_arguments().size()); ID.AddInteger(T->getSpecifiedArguments().size());
for (const auto &TA : T->template_arguments()) { for (const auto &TA : T->getSpecifiedArguments()) {
Hash.AddTemplateArgument(TA); Hash.AddTemplateArgument(TA);
} }
Hash.AddTemplateName(T->getTemplateName()); Hash.AddTemplateName(T->getTemplateName());

View File

@ -129,7 +129,7 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
SmallVector<TemplateArgument, 4> FQArgs; SmallVector<TemplateArgument, 4> FQArgs;
// Cheap to copy and potentially modified by // Cheap to copy and potentially modified by
// getFullyQualifedTemplateArgument. // getFullyQualifedTemplateArgument.
for (TemplateArgument Arg : TST->template_arguments()) { for (TemplateArgument Arg : TST->getSpecifiedArguments()) {
MightHaveChanged |= getFullyQualifiedTemplateArgument( MightHaveChanged |= getFullyQualifiedTemplateArgument(
Ctx, Arg, WithGlobalNsPrefix); Ctx, Arg, WithGlobalNsPrefix);
FQArgs.push_back(Arg); FQArgs.push_back(Arg);
@ -139,7 +139,8 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
// allocate new type in the AST. // allocate new type in the AST.
if (MightHaveChanged) { if (MightHaveChanged) {
QualType QT = Ctx.getTemplateSpecializationType( QualType QT = Ctx.getTemplateSpecializationType(
TST->getTemplateName(), FQArgs, TST->getTemplateName(), FQArgs, TST->getConvertedArguments(),
/*CanonicalConvertedArgs=*/std::nullopt,
TST->getCanonicalTypeInternal()); TST->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
@ -171,7 +172,8 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
if (MightHaveChanged) { if (MightHaveChanged) {
TemplateName TN(TSTDecl->getSpecializedTemplate()); TemplateName TN(TSTDecl->getSpecializedTemplate());
QualType QT = Ctx.getTemplateSpecializationType( QualType QT = Ctx.getTemplateSpecializationType(
TN, FQArgs, TN, FQArgs, FQArgs,
/*CanonicalConvertedArgs=*/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

@ -378,21 +378,28 @@ QualType TemplateArgument::getNonTypeTemplateArgumentType() const {
} }
void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
const ASTContext &Context) const { const ASTContext &Context,
bool Canonical) const {
ID.AddInteger(getKind()); ID.AddInteger(getKind());
switch (getKind()) { switch (getKind()) {
case Null: case Null:
break; break;
case Type: case Type:
assert(!Canonical || getAsType().isCanonical());
getAsType().Profile(ID); getAsType().Profile(ID);
break; break;
case NullPtr: case NullPtr:
assert(!Canonical || getNullPtrType().isCanonical());
getNullPtrType().Profile(ID); getNullPtrType().Profile(ID);
break; break;
case Declaration: case Declaration:
if (Canonical) {
assert(getParamTypeForDecl().isCanonical());
assert(getAsDecl()->isCanonicalDecl());
}
getParamTypeForDecl().Profile(ID); getParamTypeForDecl().Profile(ID);
ID.AddPointer(getAsDecl()); ID.AddPointer(getAsDecl());
break; break;
@ -401,27 +408,33 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
ID.AddInteger(TemplateArg.NumExpansions.toInternalRepresentation()); ID.AddInteger(TemplateArg.NumExpansions.toInternalRepresentation());
[[fallthrough]]; [[fallthrough]];
case Template: case Template:
if (Canonical) {
TemplateName Name = TemplateName::getFromVoidPointer(TemplateArg.Name);
assert(Context.getCanonicalTemplateName(Name) == Name);
}
ID.AddPointer(TemplateArg.Name); ID.AddPointer(TemplateArg.Name);
break; break;
case Integral: case Integral:
assert(!Canonical || getIntegralType().isCanonical());
getIntegralType().Profile(ID); getIntegralType().Profile(ID);
getAsIntegral().Profile(ID); getAsIntegral().Profile(ID);
break; break;
case StructuralValue: case StructuralValue:
assert(!Canonical || getStructuralValueType().isCanonical());
getStructuralValueType().Profile(ID); getStructuralValueType().Profile(ID);
getAsStructuralValue().Profile(ID); getAsStructuralValue().Profile(ID);
break; break;
case Expression: case Expression:
getAsExpr()->Profile(ID, Context, true); getAsExpr()->Profile(ID, Context, Canonical);
break; break;
case Pack: case Pack:
ID.AddInteger(Args.NumArgs); ID.AddInteger(Args.NumArgs);
for (unsigned I = 0; I != Args.NumArgs; ++I) for (unsigned I = 0; I != Args.NumArgs; ++I)
Args.Args[I].Profile(ID, Context); Args.Args[I].Profile(ID, Context, Canonical);
} }
} }

View File

@ -54,7 +54,7 @@ void DeducedTemplateStorage::Profile(llvm::FoldingSetNodeID &ID,
ID.AddInteger(DefArgs.StartPos); ID.AddInteger(DefArgs.StartPos);
ID.AddInteger(DefArgs.Args.size()); ID.AddInteger(DefArgs.Args.size());
for (const TemplateArgument &Arg : DefArgs.Args) for (const TemplateArgument &Arg : DefArgs.Args)
Arg.Profile(ID, Context); Arg.Profile(ID, Context, /*Canonical=*/false);
} }
TemplateArgument TemplateArgument
@ -118,7 +118,7 @@ void SubstTemplateTemplateParmPackStorage::Profile(
llvm::FoldingSetNodeID &ID, ASTContext &Context, llvm::FoldingSetNodeID &ID, ASTContext &Context,
const TemplateArgument &ArgPack, Decl *AssociatedDecl, unsigned Index, const TemplateArgument &ArgPack, Decl *AssociatedDecl, unsigned Index,
bool Final) { bool Final) {
ArgPack.Profile(ID, Context); ArgPack.Profile(ID, Context, /*Canonical=*/false);
ID.AddPointer(AssociatedDecl); ID.AddPointer(AssociatedDecl);
ID.AddInteger(Index); ID.AddInteger(Index);
ID.AddBoolean(Final); ID.AddBoolean(Final);

View File

@ -1937,6 +1937,17 @@ TagDecl *Type::getAsTagDecl() const {
return nullptr; return nullptr;
} }
const TemplateSpecializationType *
Type::getAsNonAliasTemplateSpecializationType() const {
for (auto T = this; /**/; /**/) {
const TemplateSpecializationType *TST =
T->getAs<TemplateSpecializationType>();
if (!TST || !TST->isTypeAlias())
return TST;
T = TST->desugar().getTypePtr();
}
}
bool Type::hasAttr(attr::Kind AK) const { bool Type::hasAttr(attr::Kind AK) const {
const Type *Cur = this; const Type *Cur = this;
while (const auto *AT = Cur->getAs<AttributedType>()) { while (const auto *AT = Cur->getAs<AttributedType>()) {
@ -3289,11 +3300,11 @@ DependentTemplateSpecializationType::DependentTemplateSpecializationType(
void DependentTemplateSpecializationType::Profile( void DependentTemplateSpecializationType::Profile(
llvm::FoldingSetNodeID &ID, const ASTContext &Context, llvm::FoldingSetNodeID &ID, const ASTContext &Context,
ElaboratedTypeKeyword Keyword, const DependentTemplateStorage &Name, ElaboratedTypeKeyword Keyword, const DependentTemplateStorage &Name,
ArrayRef<TemplateArgument> Args) { ArrayRef<TemplateArgument> Args, bool IsCanonical) {
ID.AddInteger(llvm::to_underlying(Keyword)); ID.AddInteger(llvm::to_underlying(Keyword));
Name.Profile(ID); Name.Profile(ID);
for (const TemplateArgument &Arg : Args) for (const TemplateArgument &Arg : Args)
Arg.Profile(ID, Context); Arg.Profile(ID, Context, IsCanonical);
} }
bool Type::isElaboratedTypeSpecifier() const { bool Type::isElaboratedTypeSpecifier() const {
@ -4371,17 +4382,20 @@ bool TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
} }
TemplateSpecializationType::TemplateSpecializationType( TemplateSpecializationType::TemplateSpecializationType(
TemplateName T, ArrayRef<TemplateArgument> Args, QualType Canon, TemplateName T, bool IsAlias, ArrayRef<TemplateArgument> SpecifiedArgs,
QualType AliasedType) ArrayRef<TemplateArgument> ConvertedArgs, 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.NumSpecifiedArgs = SpecifiedArgs.size();
TemplateSpecializationTypeBits.TypeAlias = !AliasedType.isNull(); TemplateSpecializationTypeBits.NumConvertedArgs = ConvertedArgs.size();
TemplateSpecializationTypeBits.TypeAlias = IsAlias;
assert(!T.getAsDependentTemplateName() && assert(!T.getAsDependentTemplateName() &&
"Use DependentTemplateSpecializationType for dependent template-name"); "Use DependentTemplateSpecializationType for dependent template-name");
@ -4393,51 +4407,70 @@ 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 initArgs = [this](ArrayRef<TemplateArgument> Out,
for (const TemplateArgument &Arg : Args) { ArrayRef<TemplateArgument> In) {
// Update instantiation-dependent, variably-modified, and error bits. auto *Args = const_cast<TemplateArgument *>(Out.data());
// If the canonical type exists and is non-dependent, the template for (const TemplateArgument &Arg : In) {
// specialization type can be non-dependent even if one of the type // Update instantiation-dependent, variably-modified, and error bits.
// arguments is. Given: // If the canonical type exists and is non-dependent, the template
// template<typename T> using U = int; // specialization type can be non-dependent even if one of the type
// U<T> is always non-dependent, irrespective of the type T. // arguments is. Given:
// However, U<Ts> contains an unexpanded parameter pack, even though // template<typename T> using U = int;
// its expansion (and thus its desugared type) doesn't. // U<T> is always non-dependent, irrespective of the type T.
addDependence(toTypeDependence(Arg.getDependence()) & // However, U<Ts> contains an unexpanded parameter pack, even though
~TypeDependence::Dependent); // its expansion (and thus its desugared type) doesn't.
if (Arg.getKind() == TemplateArgument::Type) addDependence(toTypeDependence(Arg.getDependence()) &
addDependence(Arg.getAsType()->getDependence() & ~TypeDependence::Dependent);
TypeDependence::VariablyModified); if (Arg.getKind() == TemplateArgument::Type)
new (TemplateArgs++) TemplateArgument(Arg); addDependence(Arg.getAsType()->getDependence() &
} TypeDependence::VariablyModified);
new (Args++) TemplateArgument(Arg);
}
};
initArgs(getSpecifiedArguments(), SpecifiedArgs);
initArgs(getConvertedArguments(), ConvertedArgs);
// Store the aliased type if this is a type alias template specialization. // Store the aliased type if this is a type alias template specialization.
if (isTypeAlias()) { if (IsAlias)
auto *Begin = reinterpret_cast<TemplateArgument *>(this + 1); *reinterpret_cast<QualType *>(const_cast<TemplateArgument *>(
*reinterpret_cast<QualType *>(Begin + Args.size()) = AliasedType; getConvertedArguments().end())) = Underlying;
}
} }
QualType TemplateSpecializationType::getAliasedType() const { QualType TemplateSpecializationType::getAliasedType() const {
assert(isTypeAlias() && "not a type alias template specialization"); assert(isTypeAlias() && "not a type alias template specialization");
return *reinterpret_cast<const QualType *>(template_arguments().end()); return *reinterpret_cast<const QualType *>(getConvertedArguments().end());
}
ArrayRef<TemplateArgument>
TemplateSpecializationType::getConvertedArguments() const {
return {getSpecifiedArguments().end(),
TemplateSpecializationTypeBits.NumConvertedArgs};
} }
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, getSpecifiedArguments(), getConvertedArguments(),
if (isTypeAlias()) isSugared() ? desugar() : QualType(), Ctx, isCanonicalUnqualified());
getAliasedType().Profile(ID);
} }
void void TemplateSpecializationType::Profile(
TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, llvm::FoldingSetNodeID &ID, TemplateName T,
TemplateName T, ArrayRef<TemplateArgument> SpecifiedArgs,
ArrayRef<TemplateArgument> Args, ArrayRef<TemplateArgument> ConvertedArgs, QualType Underlying,
const ASTContext &Context) { const ASTContext &Context, bool Canonical) {
T.Profile(ID); T.Profile(ID);
for (const TemplateArgument &Arg : Args)
Arg.Profile(ID, Context); assert(!Canonical || SpecifiedArgs.size() == 0);
ID.AddInteger(SpecifiedArgs.size());
for (const TemplateArgument &Arg : SpecifiedArgs)
Arg.Profile(ID, Context, /*Canonical=*/false);
ID.AddInteger(ConvertedArgs.size());
for (const TemplateArgument &Arg : ConvertedArgs)
Arg.Profile(ID, Context, Canonical);
Underlying.Profile(ID);
} }
QualType QualType
@ -5247,20 +5280,21 @@ 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, bool Canonical) {
ID.AddPointer(Deduced.getAsOpaquePtr()); ID.AddPointer(Deduced.getAsOpaquePtr());
ID.AddInteger((unsigned)Keyword); ID.AddInteger((unsigned)Keyword);
ID.AddBoolean(IsDependent); ID.AddBoolean(IsDependent);
ID.AddPointer(CD); ID.AddPointer(CD);
for (const TemplateArgument &Arg : Arguments) for (const TemplateArgument &Arg : Arguments)
Arg.Profile(ID, Context); Arg.Profile(ID, Context, Canonical);
} }
void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(), Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(),
getTypeConstraintConcept(), getTypeConstraintArguments()); getTypeConstraintConcept(), getTypeConstraintArguments(),
isCanonicalUnqualified());
} }
FunctionEffect::Kind FunctionEffect::oppositeKind() const { FunctionEffect::Kind FunctionEffect::oppositeKind() const {

View File

@ -1669,7 +1669,10 @@ void TypePrinter::printTemplateId(const TemplateSpecializationType *T,
DefaultTemplateArgsPolicyRAII TemplateArgs(Policy); DefaultTemplateArgsPolicyRAII TemplateArgs(Policy);
const TemplateParameterList *TPL = TD ? TD->getTemplateParameters() : nullptr; const TemplateParameterList *TPL = TD ? TD->getTemplateParameters() : nullptr;
printTemplateArgumentList(OS, T->template_arguments(), Policy, TPL); ArrayRef<TemplateArgument> Args = T->isCanonicalUnqualified()
? T->getConvertedArguments()
: T->getSpecifiedArguments();
printTemplateArgumentList(OS, Args, Policy, TPL);
spaceBeforePlaceHolder(OS); spaceBeforePlaceHolder(OS);
} }
@ -2297,7 +2300,7 @@ static bool isSubstitutedType(ASTContext &Ctx, QualType T, QualType Pattern,
ArrayRef<TemplateArgument> TemplateArgs; ArrayRef<TemplateArgument> TemplateArgs;
if (auto *TTST = T->getAs<TemplateSpecializationType>()) { if (auto *TTST = T->getAs<TemplateSpecializationType>()) {
Template = TTST->getTemplateName(); Template = TTST->getTemplateName();
TemplateArgs = TTST->template_arguments(); TemplateArgs = TTST->getConvertedArguments();
} else if (auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>( } else if (auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
T->getAsCXXRecordDecl())) { T->getAsCXXRecordDecl())) {
Template = TemplateName(CTSD->getSpecializedTemplate()); Template = TemplateName(CTSD->getSpecializedTemplate());
@ -2309,11 +2312,12 @@ static bool isSubstitutedType(ASTContext &Ctx, QualType T, QualType Pattern,
if (!isSubstitutedTemplateArgument(Ctx, Template, PTST->getTemplateName(), if (!isSubstitutedTemplateArgument(Ctx, Template, PTST->getTemplateName(),
Args, Depth)) Args, Depth))
return false; return false;
if (TemplateArgs.size() != PTST->template_arguments().size()) ArrayRef<TemplateArgument> PArgs = PTST->getConvertedArguments();
if (TemplateArgs.size() != PArgs.size())
return false; return false;
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
if (!isSubstitutedTemplateArgument( if (!isSubstitutedTemplateArgument(Ctx, TemplateArgs[I], PArgs[I], Args,
Ctx, TemplateArgs[I], PTST->template_arguments()[I], Args, Depth)) Depth))
return false; return false;
return true; return true;
} }

View File

@ -1391,7 +1391,7 @@ GetTemplateArgs(const TemplateDecl *TD, const TemplateSpecializationType *Ty) {
// doesn't know the value of any defaulted args, so collect those now // doesn't know the value of any defaulted args, so collect those now
// too. // too.
SmallVector<TemplateArgument> SpecArgs; SmallVector<TemplateArgument> SpecArgs;
ArrayRef SubstArgs = Ty->template_arguments(); ArrayRef SubstArgs = Ty->getSpecifiedArguments();
for (const NamedDecl *Param : TD->getTemplateParameters()->asArray()) { for (const NamedDecl *Param : TD->getTemplateParameters()->asArray()) {
// If Param is a parameter pack, pack the remaining arguments. // If Param is a parameter pack, pack the remaining arguments.
if (Param->isParameterPack()) { if (Param->isParameterPack()) {
@ -1483,7 +1483,7 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
return AliasTy; return AliasTy;
} }
printTemplateArgumentList(OS, Ty->template_arguments(), PP, printTemplateArgumentList(OS, Ty->getSpecifiedArguments(), PP,
TD->getTemplateParameters()); TD->getTemplateParameters());
return DBuilder.createTypedef(Src, OS.str(), getOrCreateFile(Loc), return DBuilder.createTypedef(Src, OS.str(), getOrCreateFile(Loc),
getLineNumber(Loc), getLineNumber(Loc),

View File

@ -413,7 +413,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
.append(Str, DeclarationFragments::FragmentKind::TypeIdentifier, USR) .append(Str, DeclarationFragments::FragmentKind::TypeIdentifier, USR)
.append("<", DeclarationFragments::FragmentKind::Text) .append("<", DeclarationFragments::FragmentKind::Text)
.append(getFragmentsForTemplateArguments( .append(getFragmentsForTemplateArguments(
TemplSpecTy->template_arguments(), Context, std::nullopt)) TemplSpecTy->getSpecifiedArguments(), Context, std::nullopt))
.append(">", DeclarationFragments::FragmentKind::Text); .append(">", DeclarationFragments::FragmentKind::Text);
} }

View File

@ -935,8 +935,8 @@ void USRGenerator::VisitType(QualType T) {
= T->getAs<TemplateSpecializationType>()) { = T->getAs<TemplateSpecializationType>()) {
Out << '>'; Out << '>';
VisitTemplateName(Spec->getTemplateName()); VisitTemplateName(Spec->getTemplateName());
Out << Spec->template_arguments().size(); Out << Spec->getConvertedArguments().size();
for (const auto &Arg : Spec->template_arguments()) for (const TemplateArgument &Arg : Spec->getConvertedArguments())
VisitTemplateArgument(Arg); VisitTemplateArgument(Arg);
return; return;
} }

View File

@ -193,9 +193,9 @@ QualType HeuristicResolverImpl::getPointeeType(QualType T) {
auto *TST = T->getAs<TemplateSpecializationType>(); auto *TST = T->getAs<TemplateSpecializationType>();
if (!TST) if (!TST)
return QualType(); return QualType();
if (TST->template_arguments().size() == 0) if (TST->getSpecifiedArguments().size() == 0)
return QualType(); return QualType();
const TemplateArgument &FirstArg = TST->template_arguments()[0]; const TemplateArgument &FirstArg = TST->getSpecifiedArguments()[0];
if (FirstArg.getKind() != TemplateArgument::Type) if (FirstArg.getKind() != TemplateArgument::Type)
return QualType(); return QualType();
return FirstArg.getAsType(); return FirstArg.getAsType();

View File

@ -98,7 +98,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
if (L != TemplateParamLists.end()) { if (L != TemplateParamLists.end()) {
void *Pos = nullptr; void *Pos = nullptr;
PartialSpec = ClassTemplate->findPartialSpecialization( PartialSpec = ClassTemplate->findPartialSpecialization(
SpecType->template_arguments(), *L, Pos); SpecType->getConvertedArguments(), *L, Pos);
} }
} else { } else {
PartialSpec = ClassTemplate->findPartialSpecialization(ContextType); PartialSpec = ClassTemplate->findPartialSpecialization(ContextType);

View File

@ -4911,9 +4911,10 @@ static const FunctionProtoType *TryDeconstructFunctionLike(QualType T) {
// Note we only handle the sugared types, they closely match what users wrote. // Note we only handle the sugared types, they closely match what users wrote.
// We explicitly choose to not handle ClassTemplateSpecializationDecl. // We explicitly choose to not handle ClassTemplateSpecializationDecl.
if (auto *Specialization = T->getAs<TemplateSpecializationType>()) { if (auto *Specialization = T->getAs<TemplateSpecializationType>()) {
if (Specialization->template_arguments().size() != 1) if (Specialization->getSpecifiedArguments().size() != 1)
return nullptr; return nullptr;
const TemplateArgument &Argument = Specialization->template_arguments()[0]; const TemplateArgument &Argument =
Specialization->getSpecifiedArguments()[0];
if (Argument.getKind() != TemplateArgument::Type) if (Argument.getKind() != TemplateArgument::Type)
return nullptr; return nullptr;
return Argument.getAsType()->getAs<FunctionProtoType>(); return Argument.getAsType()->getAs<FunctionProtoType>();

View File

@ -183,7 +183,8 @@ DiagRecursiveConstraintEval(Sema &S, llvm::FoldingSetNodeID &ID,
E->Profile(ID, S.Context, /*Canonical=*/true); E->Profile(ID, S.Context, /*Canonical=*/true);
for (const auto &List : MLTAL) for (const auto &List : MLTAL)
for (const auto &TemplateArg : List.Args) for (const auto &TemplateArg : List.Args)
TemplateArg.Profile(ID, S.Context); S.Context.getCanonicalTemplateArgument(TemplateArg)
.Profile(ID, S.Context, /*Canonical=*/true);
// Note that we have to do this with our own collection, because there are // Note that we have to do this with our own collection, because there are
// times where a constraint-expression check can cause us to need to evaluate // times where a constraint-expression check can cause us to need to evaluate
@ -1924,7 +1925,7 @@ auto SubsumptionChecker::find(AtomicConstraint *Ori) -> Literal {
for (const TemplateArgumentLoc &TAL : *Mapping) { for (const TemplateArgumentLoc &TAL : *Mapping) {
SemaRef.getASTContext() SemaRef.getASTContext()
.getCanonicalTemplateArgument(TAL.getArgument()) .getCanonicalTemplateArgument(TAL.getArgument())
.Profile(ID, SemaRef.getASTContext()); .Profile(ID, SemaRef.getASTContext(), /*Canonical=*/true);
} }
} }
auto It = Elems.find(ID); auto It = Elems.find(ID);

View File

@ -12081,7 +12081,7 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) {
if (TST) { if (TST) {
Template = dyn_cast_or_null<ClassTemplateDecl>( Template = dyn_cast_or_null<ClassTemplateDecl>(
TST->getTemplateName().getAsTemplateDecl()); TST->getTemplateName().getAsTemplateDecl());
Arguments = TST->template_arguments().begin(); Arguments = TST->getConvertedArguments().begin();
} }
} }
if (!Template) if (!Template)

View File

@ -21086,8 +21086,10 @@ 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 = QualType TST = Context.getTemplateSpecializationType(
Context.getTemplateSpecializationType(TN, ULE->template_arguments()); TN, ULE->template_arguments(),
/*SugaredConvertedArgs=*/ArrayRef<TemplateArgument>{},
/*CanonicalConvertedArgs=*/{});
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

@ -3227,11 +3227,11 @@ static QualType builtinCommonTypeImpl(Sema &S, TemplateName BaseTemplate,
} }
} }
static QualType static QualType checkBuiltinTemplateIdType(
checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, Sema &SemaRef, TemplateName Name, BuiltinTemplateDecl *BTD,
ArrayRef<TemplateArgument> Converted, ArrayRef<TemplateArgument> SugaredConverted,
SourceLocation TemplateLoc, ArrayRef<TemplateArgument> CanonicalConverted, SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) { TemplateArgumentListInfo &TemplateArgs) {
ASTContext &Context = SemaRef.getASTContext(); ASTContext &Context = SemaRef.getASTContext();
switch (BTD->getBuiltinTemplateKind()) { switch (BTD->getBuiltinTemplateKind()) {
@ -3239,7 +3239,7 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
// Specializations of __make_integer_seq<S, T, N> are treated like // Specializations of __make_integer_seq<S, T, N> are treated like
// S<T, 0, ..., N-1>. // S<T, 0, ..., N-1>.
QualType OrigType = Converted[1].getAsType(); QualType OrigType = SugaredConverted[1].getAsType();
// C++14 [inteseq.intseq]p1: // C++14 [inteseq.intseq]p1:
// T shall be an integer type. // T shall be an integer type.
if (!OrigType->isDependentType() && !OrigType->isIntegralType(Context)) { if (!OrigType->isDependentType() && !OrigType->isIntegralType(Context)) {
@ -3248,10 +3248,11 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
return QualType(); return QualType();
} }
TemplateArgument NumArgsArg = Converted[2]; TemplateArgument NumArgsArg = SugaredConverted[2];
if (NumArgsArg.isDependent()) if (NumArgsArg.isDependent())
return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD), return SemaRef.Context.getTemplateSpecializationType(
Converted); TemplateName(BTD), TemplateArgs.arguments(), SugaredConverted,
CanonicalConverted);
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
@ -3279,21 +3280,26 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
// The first template argument will be reused as the template decl that // The first template argument will be reused as the template decl that
// our synthetic template arguments will be applied to. // our synthetic template arguments will be applied to.
return SemaRef.CheckTemplateIdType(Converted[0].getAsTemplate(), QualType Result =
TemplateLoc, SyntheticTemplateArgs); SemaRef.CheckTemplateIdType(SugaredConverted[0].getAsTemplate(),
TemplateLoc, SyntheticTemplateArgs);
return SemaRef.Context.getTemplateSpecializationType(
Name, TemplateArgs.arguments(), SugaredConverted, CanonicalConverted,
Result);
} }
case BTK__type_pack_element: { case BTK__type_pack_element: {
// Specializations of // Specializations of
// __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(SugaredConverted.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 = SugaredConverted[0], Ts = SugaredConverted[1];
if (IndexArg.isDependent() || Ts.isDependent()) if (IndexArg.isDependent() || Ts.isDependent())
return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD), return SemaRef.Context.getTemplateSpecializationType(
Converted); TemplateName(BTD), TemplateArgs.arguments(), SugaredConverted,
CanonicalConverted);
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 "
@ -3307,19 +3313,24 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
// We simply return the type at index `Index`. // We simply return the type at index `Index`.
int64_t N = Index.getExtValue(); int64_t N = Index.getExtValue();
return Ts.getPackAsArray()[N].getAsType(); return SemaRef.Context.getTemplateSpecializationType(
Name, TemplateArgs.arguments(), SugaredConverted, CanonicalConverted,
Ts.getPackAsArray()[N].getAsType());
} }
case BTK__builtin_common_type: { case BTK__builtin_common_type: {
assert(Converted.size() == 4); assert(CanonicalConverted.size() == 4);
if (llvm::any_of(Converted, [](auto &C) { return C.isDependent(); })) if (llvm::any_of(CanonicalConverted,
return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD), [](auto &C) { return C.isDependent(); }))
Converted); return Context.getTemplateSpecializationType(
TemplateName(BTD), TemplateArgs.arguments(), SugaredConverted,
CanonicalConverted);
TemplateName BaseTemplate = Converted[0].getAsTemplate(); TemplateName BaseTemplate = SugaredConverted[0].getAsTemplate();
TemplateName HasTypeMember = Converted[1].getAsTemplate(); TemplateName HasTypeMember = SugaredConverted[1].getAsTemplate();
QualType HasNoTypeMember = Converted[2].getAsType(); QualType HasNoTypeMember = SugaredConverted[2].getAsType();
ArrayRef<TemplateArgument> Ts = Converted[3].getPackAsArray(); ArrayRef<TemplateArgument> Ts = SugaredConverted[3].getPackAsArray();
QualType Result = HasNoTypeMember;
if (auto CT = builtinCommonTypeImpl(SemaRef, BaseTemplate, TemplateLoc, Ts); if (auto CT = builtinCommonTypeImpl(SemaRef, BaseTemplate, TemplateLoc, Ts);
!CT.isNull()) { !CT.isNull()) {
TemplateArgumentListInfo TAs; TemplateArgumentListInfo TAs;
@ -3327,9 +3338,11 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
TemplateArgument(CT), SemaRef.Context.getTrivialTypeSourceInfo( TemplateArgument(CT), SemaRef.Context.getTrivialTypeSourceInfo(
CT, TemplateArgs[1].getLocation()))); CT, TemplateArgs[1].getLocation())));
return SemaRef.CheckTemplateIdType(HasTypeMember, TemplateLoc, TAs); Result = SemaRef.CheckTemplateIdType(HasTypeMember, TemplateLoc, TAs);
} }
return HasNoTypeMember; return SemaRef.Context.getTemplateSpecializationType(
Name, TemplateArgs.arguments(), SugaredConverted, CanonicalConverted,
Result);
} }
} }
llvm_unreachable("unexpected BuiltinTemplateDecl!"); llvm_unreachable("unexpected BuiltinTemplateDecl!");
@ -3492,20 +3505,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 +3531,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();
@ -3589,8 +3604,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
return QualType(); return QualType();
} }
} else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) { } else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) {
CanonType = checkBuiltinTemplateIdType(*this, BTD, CTAI.SugaredConverted, return checkBuiltinTemplateIdType(*this, Name, BTD, CTAI.SugaredConverted,
TemplateLoc, TemplateArgs); CTAI.CanonicalConverted, TemplateLoc,
TemplateArgs);
} else if (Name.isDependent() || } else if (Name.isDependent() ||
TemplateSpecializationType::anyDependentTemplateArguments( TemplateSpecializationType::anyDependentTemplateArguments(
TemplateArgs, CTAI.CanonicalConverted)) { TemplateArgs, CTAI.CanonicalConverted)) {
@ -3601,8 +3617,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// A<T, T> have identical types when A is declared as: // A<T, T> have identical types when A is declared as:
// //
// template<typename T, typename U = T> struct A; // template<typename T, typename U = T> struct A;
CanonType = Context.getCanonicalTemplateSpecializationType( CanonType = Context.getTemplateSpecializationType(
Name, CTAI.CanonicalConverted); Context.getCanonicalTemplateName(Name), ArrayRef<TemplateArgument>(),
std::nullopt, CTAI.CanonicalConverted);
// 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 +3705,9 @@ 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.SugaredConverted,
CTAI.CanonicalConverted, CanonType);
} }
void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName, void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName,
@ -8473,17 +8491,35 @@ 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.SugaredConverted,
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:
@ -8510,7 +8546,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()) {
@ -8528,29 +8565,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:
@ -8640,8 +8654,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

@ -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();
} }
} }
@ -643,87 +646,61 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
if (const auto *TD = TNP.getAsTemplateDecl(); TD && TD->isTypeAlias()) if (const auto *TD = TNP.getAsTemplateDecl(); TD && TD->isTypeAlias())
return TemplateDeductionResult::Success; return TemplateDeductionResult::Success;
// FIXME: To preserve sugar, the TST needs to carry sugared resolved ArrayRef<TemplateArgument> PResolved = TP->getConvertedArguments();
// arguments.
ArrayRef<TemplateArgument> PResolved =
TP->getCanonicalTypeInternal()
->castAs<TemplateSpecializationType>()
->template_arguments();
QualType UA = A; QualType UA = A;
std::optional<NestedNameSpecifier *> NNS;
// Treat an injected-class-name as its underlying template-id. // Treat an injected-class-name as its underlying template-id.
if (const auto *Elaborated = A->getAs<ElaboratedType>()) { if (const auto *Injected = A->getAs<InjectedClassNameType>())
NNS = Elaborated->getQualifier();
} else if (const auto *Injected = A->getAs<InjectedClassNameType>()) {
UA = Injected->getInjectedSpecializationType(); UA = Injected->getInjectedSpecializationType();
NNS = nullptr;
const TemplateSpecializationType *TA = ::getLastTemplateSpecType(UA);
TemplateName TNA;
ArrayRef<TemplateArgument> AResolved;
if (TA) {
TNA = TA->getTemplateName();
AResolved = TA->getConvertedArguments();
} }
if (auto *SA = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
// Check whether the template argument is a dependent template-id. A->getAsCXXRecordDecl())) {
if (isa<TemplateSpecializationType>(UA.getCanonicalType())) { if (TA) {
const TemplateSpecializationType *SA = ::getLastTemplateSpecType(UA); // This could be a type alias to a class template specialization type
TemplateName TNA = SA->getTemplateName(); // which was desugared. If so, ignore it.
if (TNA.getAsTemplateDecl()->isTypeAlias())
TA = nullptr;
else
assert(isSameDeclaration(TNA.getAsTemplateDecl(),
SA->getSpecializedTemplate()));
}
if (!TA) {
// If the argument type is a class template specialization, we
// perform template argument deduction using its template
// arguments.
TNA = TemplateName(SA->getSpecializedTemplate());
AResolved = SA->getTemplateArgs().asArray();
}
} else if (isa<TemplateSpecializationType>(UA.getCanonicalType())) {
// If the argument is an alias template, there is nothing to deduce. // If the argument is an alias template, there is nothing to deduce.
if (const auto *TD = TNA.getAsTemplateDecl(); TD && TD->isTypeAlias()) if (const auto *TD = TNA.getAsTemplateDecl(); TD && TD->isTypeAlias())
return TemplateDeductionResult::Success; return TemplateDeductionResult::Success;
} else {
// FIXME: To preserve sugar, the TST needs to carry sugared resolved
// arguments.
ArrayRef<TemplateArgument> AResolved =
SA->getCanonicalTypeInternal()
->castAs<TemplateSpecializationType>()
->template_arguments();
// Perform template argument deduction for the template name.
if (auto Result = DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info,
/*DefaultArguments=*/AResolved,
PartialOrdering, Deduced,
HasDeducedAnyParam);
Result != TemplateDeductionResult::Success)
return Result;
// Perform template argument deduction on each template
// argument. Ignore any missing/extra arguments, since they could be
// filled in by default arguments.
return DeduceTemplateArguments(
S, TemplateParams, PResolved, AResolved, Info, Deduced,
/*NumberOfArgumentsMustMatch=*/false, PartialOrdering,
PackFold::ParameterToArgument, HasDeducedAnyParam);
}
// If the argument type is a class template specialization, we
// perform template argument deduction using its template
// arguments.
const auto *RA = UA->getAs<RecordType>();
const auto *SA =
RA ? dyn_cast<ClassTemplateSpecializationDecl>(RA->getDecl()) : nullptr;
if (!SA) {
Info.FirstArg = TemplateArgument(P); Info.FirstArg = TemplateArgument(P);
Info.SecondArg = TemplateArgument(A); Info.SecondArg = TemplateArgument(A);
return TemplateDeductionResult::NonDeducedMismatch; return TemplateDeductionResult::NonDeducedMismatch;
} }
TemplateName TNA = TemplateName(SA->getSpecializedTemplate());
if (NNS)
TNA = S.Context.getQualifiedTemplateName(
*NNS, false, TemplateName(SA->getSpecializedTemplate()));
// Perform template argument deduction for the template name. // Perform template argument deduction for the template name.
if (auto Result = DeduceTemplateArguments( if (auto Result =
S, TemplateParams, TNP, TNA, Info, DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info,
/*DefaultArguments=*/SA->getTemplateArgs().asArray(), PartialOrdering, /*DefaultArguments=*/AResolved,
Deduced, HasDeducedAnyParam); PartialOrdering, Deduced, HasDeducedAnyParam);
Result != TemplateDeductionResult::Success) Result != TemplateDeductionResult::Success)
return Result; return Result;
// Perform template argument deduction for the template arguments. // Perform template argument deduction for the template arguments.
return DeduceTemplateArguments(S, TemplateParams, PResolved, return DeduceTemplateArguments(
SA->getTemplateArgs().asArray(), Info, Deduced, S, TemplateParams, PResolved, AResolved, Info, Deduced,
/*NumberOfArgumentsMustMatch=*/true, /*NumberOfArgumentsMustMatch=*/true, PartialOrdering,
PartialOrdering, PackFold::ParameterToArgument, PackFold::ParameterToArgument, HasDeducedAnyParam);
HasDeducedAnyParam);
} }
static bool IsPossiblyOpaquelyQualifiedTypeInternal(const Type *T) { static bool IsPossiblyOpaquelyQualifiedTypeInternal(const Type *T) {
@ -5894,8 +5871,8 @@ static MoreSpecializedTrailingPackTieBreakerResult
getMoreSpecializedTrailingPackTieBreaker( getMoreSpecializedTrailingPackTieBreaker(
const TemplateSpecializationType *TST1, const TemplateSpecializationType *TST1,
const TemplateSpecializationType *TST2) { const TemplateSpecializationType *TST2) {
ArrayRef<TemplateArgument> As1 = TST1->template_arguments(), ArrayRef<TemplateArgument> As1 = TST1->getConvertedArguments(),
As2 = TST2->template_arguments(); As2 = TST2->getConvertedArguments();
const TemplateArgument &TA1 = As1.back(), &TA2 = As2.back(); const TemplateArgument &TA1 = As1.back(), &TA2 = As2.back();
bool IsPack = TA1.getKind() == TemplateArgument::Pack; bool IsPack = TA1.getKind() == TemplateArgument::Pack;
assert(IsPack == (TA2.getKind() == TemplateArgument::Pack)); assert(IsPack == (TA2.getKind() == TemplateArgument::Pack));
@ -6302,8 +6279,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
TemplateDeductionResult Result; TemplateDeductionResult Result;
S.runWithSufficientStackSpace(Info.getLocation(), [&] { S.runWithSufficientStackSpace(Info.getLocation(), [&] {
Result = ::FinishTemplateArgumentDeduction( Result = ::FinishTemplateArgumentDeduction(
S, P2, /*IsPartialOrdering=*/true, TST1->template_arguments(), Deduced, S, P2, /*IsPartialOrdering=*/true, TST1->getConvertedArguments(),
Info); Deduced, Info);
}); });
if (Result != TemplateDeductionResult::Success) if (Result != TemplateDeductionResult::Success)
@ -6347,8 +6324,10 @@ struct TemplateArgumentListAreEqual {
// because canonicalization can't do the right thing for dependent // because canonicalization can't do the right thing for dependent
// expressions. // expressions.
llvm::FoldingSetNodeID IDA, IDB; llvm::FoldingSetNodeID IDA, IDB;
Args1[I].Profile(IDA, Ctx); Ctx.getCanonicalTemplateArgument(Args1[I]).Profile(IDA, Ctx,
Args2[I].Profile(IDB, Ctx); /*Canonical=*/true);
Ctx.getCanonicalTemplateArgument(Args2[I]).Profile(IDB, Ctx,
/*Canonical=*/true);
if (IDA != IDB) if (IDA != IDB)
return false; return false;
} }
@ -6366,10 +6345,10 @@ struct TemplateArgumentListAreEqual {
// because canonicalization can't do the right thing for dependent // because canonicalization can't do the right thing for dependent
// expressions. // expressions.
llvm::FoldingSetNodeID IDA, IDB; llvm::FoldingSetNodeID IDA, IDB;
Args1[I].Profile(IDA, Ctx); Ctx.getCanonicalTemplateArgument(Args1[I]).Profile(IDA, Ctx,
// Unlike the specialization arguments, the injected arguments are not /*Canonical=*/true);
// always canonical. Ctx.getCanonicalTemplateArgument(Args2[I]).Profile(IDB, Ctx,
Ctx.getCanonicalTemplateArgument(Args2[I]).Profile(IDB, Ctx); /*Canonical=*/true);
if (IDA != IDB) if (IDA != IDB)
return false; return false;
} }
@ -6512,9 +6491,11 @@ Sema::getMoreSpecializedPartialSpecialization(
" the same template."); " the same template.");
TemplateName Name(PS1->getSpecializedTemplate()); TemplateName Name(PS1->getSpecializedTemplate());
QualType PT1 = Context.getTemplateSpecializationType( QualType PT1 = Context.getTemplateSpecializationType(
Name, PS1->getTemplateArgs().asArray()); Name, ArrayRef<TemplateArgument>(), std::nullopt,
PS1->getTemplateArgs().asArray());
QualType PT2 = Context.getTemplateSpecializationType( QualType PT2 = Context.getTemplateSpecializationType(
Name, PS2->getTemplateArgs().asArray()); Name, ArrayRef<TemplateArgument>(), std::nullopt,
PS2->getTemplateArgs().asArray());
TemplateDeductionInfo Info(Loc); TemplateDeductionInfo Info(Loc);
return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info); return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info);
@ -6525,9 +6506,11 @@ bool Sema::isMoreSpecializedThanPrimary(
VarTemplateDecl *Primary = Spec->getSpecializedTemplate(); VarTemplateDecl *Primary = Spec->getSpecializedTemplate();
TemplateName Name(Primary); TemplateName Name(Primary);
QualType PrimaryT = Context.getTemplateSpecializationType( QualType PrimaryT = Context.getTemplateSpecializationType(
Name, Primary->getInjectedTemplateArgs(Context)); Name, ArrayRef<TemplateArgument>(),
Primary->getInjectedTemplateArgs(Context), std::nullopt);
QualType PartialT = Context.getTemplateSpecializationType( QualType PartialT = Context.getTemplateSpecializationType(
Name, Spec->getTemplateArgs().asArray()); Name, ArrayRef<TemplateArgument>(), std::nullopt,
Spec->getTemplateArgs().asArray());
VarTemplatePartialSpecializationDecl *MaybeSpec = VarTemplatePartialSpecializationDecl *MaybeSpec =
getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info); getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info);
@ -6989,11 +6972,10 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
// If the template argument list of P contains a pack expansion that is // If the template argument list of P contains a pack expansion that is
// not the last template argument, the entire template argument list is a // not the last template argument, the entire template argument list is a
// non-deduced context. // non-deduced context.
if (OnlyDeduced && if (OnlyDeduced && hasPackExpansionBeforeEnd(Spec->getConvertedArguments()))
hasPackExpansionBeforeEnd(Spec->template_arguments()))
break; break;
for (const auto &Arg : Spec->template_arguments()) for (const TemplateArgument &Arg : Spec->getConvertedArguments())
MarkUsedTemplateParameters(Ctx, Arg, OnlyDeduced, Depth, Used); MarkUsedTemplateParameters(Ctx, Arg, OnlyDeduced, Depth, Used);
break; break;
} }

View File

@ -959,7 +959,7 @@ getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) {
// template<typename T> // template<typename T>
// using AliasFoo1 = Foo<T>; // a class/type alias template specialization // using AliasFoo1 = Foo<T>; // a class/type alias template specialization
Template = TST->getTemplateName().getAsTemplateDecl(); Template = TST->getTemplateName().getAsTemplateDecl();
AliasRhsTemplateArgs = TST->template_arguments(); AliasRhsTemplateArgs = TST->getSpecifiedArguments();
} else if (const auto *RT = RhsType->getAs<RecordType>()) { } else if (const auto *RT = RhsType->getAs<RecordType>()) {
// Cases where template arguments in the RHS of the alias are not // Cases where template arguments in the RHS of the alias are not
// dependent. e.g. // dependent. e.g.
@ -1045,7 +1045,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
// performing deduction for rest of arguments to align with the C++ // performing deduction for rest of arguments to align with the C++
// standard. // standard.
SemaRef.DeduceTemplateArguments( SemaRef.DeduceTemplateArguments(
F->getTemplateParameters(), FReturnType->template_arguments(), F->getTemplateParameters(), FReturnType->getSpecifiedArguments(),
AliasRhsTemplateArgs, TDeduceInfo, DeduceResults, AliasRhsTemplateArgs, TDeduceInfo, DeduceResults,
/*NumberOfArgumentsMustMatch=*/false); /*NumberOfArgumentsMustMatch=*/false);

View File

@ -345,7 +345,7 @@ Response HandleFunctionTemplateDecl(Sema &SemaRef,
while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) { while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) {
if (NNS->isInstantiationDependent()) { if (NNS->isInstantiationDependent()) {
if (const auto *TSTy = Ty->getAs<TemplateSpecializationType>()) { if (const auto *TSTy = Ty->getAs<TemplateSpecializationType>()) {
ArrayRef<TemplateArgument> Arguments = TSTy->template_arguments(); ArrayRef<TemplateArgument> Arguments = TSTy->getConvertedArguments();
// Prefer template arguments from the injected-class-type if possible. // Prefer template arguments from the injected-class-type if possible.
// For example, // For example,
// ```cpp // ```cpp

View File

@ -4785,17 +4785,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.SugaredConverted, 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

@ -1889,7 +1889,7 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
// A declarator that specifies the type "reference to cv void" // A declarator that specifies the type "reference to cv void"
// is ill-formed. // is ill-formed.
if (T->isVoidType()) { if (T->isVoidType()) {
Diag(Loc, diag::err_reference_to_void); Diag(Loc, diag::err_reference_to_void) << T;
return QualType(); return QualType();
} }

View File

@ -7358,12 +7358,24 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
TemplateArgumentListInfo NewTemplateArgs; TemplateArgumentListInfo NewTemplateArgs;
NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc());
NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc());
typedef TemplateArgumentLocContainerIterator<TemplateSpecializationTypeLoc>
ArgIterator; const auto *T = cast<TemplateSpecializationType>(TL.getType());
if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0), if (T->isCanonicalUnqualified()) {
ArgIterator(TL, TL.getNumArgs()), ArrayRef<TemplateArgument> ConvertedArgs = T->getConvertedArguments();
NewTemplateArgs)) using ArgIterator =
return QualType(); TemplateArgumentLocInventIterator<Derived, const TemplateArgument *>;
if (getDerived().TransformTemplateArguments(
ArgIterator(*this, ConvertedArgs.begin()),
ArgIterator(*this, ConvertedArgs.end()), NewTemplateArgs))
return QualType();
} else {
using ArgIterator =
TemplateArgumentLocContainerIterator<TemplateSpecializationTypeLoc>;
if (getDerived().TransformTemplateArguments(
ArgIterator(TL, 0), ArgIterator(TL, TL.getNumArgs()),
NewTemplateArgs))
return QualType();
}
// This needs to be rebuilt if either the arguments changed, or if the // This needs to be rebuilt if either the arguments changed, or if the
// original template changed. If the template changed, and even if the // original template changed. If the template changed, and even if the

View File

@ -7305,9 +7305,9 @@ void TypeLocReader::VisitTemplateSpecializationTypeLoc(
TL.setLAngleLoc(readSourceLocation()); TL.setLAngleLoc(readSourceLocation());
TL.setRAngleLoc(readSourceLocation()); TL.setRAngleLoc(readSourceLocation());
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
TL.setArgLocInfo(i, TL.setArgLocInfo(
Reader.readTemplateArgumentLocInfo( i, Reader.readTemplateArgumentLocInfo(
TL.getTypePtr()->template_arguments()[i].getKind())); TL.getTypePtr()->getSpecifiedArguments()[i].getKind()));
} }
void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) { void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) {

View File

@ -361,8 +361,8 @@ public:
void VisitEnumType(const EnumType *T) { VisitTagType(T); } void VisitEnumType(const EnumType *T) { VisitTagType(T); }
void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
Hash.AddInteger(T->template_arguments().size()); Hash.AddInteger(T->getSpecifiedArguments().size());
for (const auto &TA : T->template_arguments()) { for (const auto &TA : T->getSpecifiedArguments()) {
Hash.AddTemplateArgument(TA); Hash.AddTemplateArgument(TA);
} }
Hash.AddTemplateName(T->getTemplateName()); Hash.AddTemplateName(T->getTemplateName());

View File

@ -95,7 +95,7 @@ getTemplateArgsFromVariant(const Type *VariantType) {
if (!TempSpecType) if (!TempSpecType)
return {}; return {};
return TempSpecType->template_arguments(); return TempSpecType->getSpecifiedArguments();
} }
static std::optional<QualType> static std::optional<QualType>

View File

@ -191,12 +191,8 @@ void foo() {
// CHECK-NEXT: | | | | `-TemplateArgument pack '<Packs<type-parameter-0-1...>>' // CHECK-NEXT: | | | | `-TemplateArgument pack '<Packs<type-parameter-0-1...>>'
// CHECK-NEXT: | | | | `-TemplateArgument type 'Packs<type-parameter-0-1...>' // CHECK-NEXT: | | | | `-TemplateArgument type 'Packs<type-parameter-0-1...>'
// CHECK-NEXT: | | | | `-TemplateSpecializationType {{.*}} 'Packs<type-parameter-0-1...>' dependent // CHECK-NEXT: | | | | `-TemplateSpecializationType {{.*}} 'Packs<type-parameter-0-1...>' dependent
// CHECK-NEXT: | | | | |-name: 'GH124715::Packs' // CHECK-NEXT: | | | | `-name: 'GH124715::Packs'
// CHECK-NEXT: | | | | | `-ClassTemplateDecl {{.*}} Packs // CHECK-NEXT: | | | | `-ClassTemplateDecl {{.*}} Packs
// CHECK-NEXT: | | | | `-TemplateArgument pack '<type-parameter-0-1...>'
// CHECK-NEXT: | | | | `-TemplateArgument type 'type-parameter-0-1...'
// CHECK-NEXT: | | | | `-PackExpansionType {{.*}} 'type-parameter-0-1...' dependent
// CHECK-NEXT: | | | | `-TemplateTypeParmType {{.*}} 'type-parameter-0-1' dependent contains_unexpanded_pack depth 0 index 1 pack
// CHECK-NEXT: | | | |-TemplateArgument {{.*}} type 'U':'type-parameter-0-2' // CHECK-NEXT: | | | |-TemplateArgument {{.*}} type 'U':'type-parameter-0-2'
// CHECK-NEXT: | | | | `-TemplateTypeParmType {{.*}} 'U' dependent depth 0 index 2 // CHECK-NEXT: | | | | `-TemplateTypeParmType {{.*}} 'U' dependent depth 0 index 2
// CHECK-NEXT: | | | | `-TemplateTypeParm {{.*}} 'U' // CHECK-NEXT: | | | | `-TemplateTypeParm {{.*}} 'U'

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 @@ namespace cwg1512 { // cwg1512: 4
template<typename A, typename B, typename C> void composite_pointer_type_is_ord() { template<typename A, typename B, typename C> void composite_pointer_type_is_ord() {
composite_pointer_type_is_base<A, B, C>(); composite_pointer_type_is_base<A, B, C>();
typedef __typeof(val<A>() < val<B>()) cmp; // #cwg1512-lt typedef __typeof(val<A>() < val<B>()) cmp; // #cwg1512-lt
// since-cxx17-warning@#cwg1512-lt {{ordered comparison of function pointers ('int (*)() noexcept' and 'int (*)()')}} // since-cxx17-warning@#cwg1512-lt {{ordered comparison of function pointers ('int (*)() noexcept' and 'int (*)()')}}
// since-cxx17-note@#cwg1512-noexcept-1st {{in instantiation of function template specialization 'cwg1512::composite_pointer_type_is_ord<int (*)() noexcept, int (*)(), int (*)()>' requested here}} // since-cxx17-note@#cwg1512-noexcept-1st {{in instantiation of function template specialization 'cwg1512::composite_pointer_type_is_ord<int (*)() noexcept, int (*)(), int (*)()>' requested here}}
// since-cxx17-warning@#cwg1512-lt {{ordered comparison of function pointers ('int (*)()' and 'int (*)() noexcept')}} // since-cxx17-warning@#cwg1512-lt {{ordered comparison of function pointers ('int (*)()' and 'int (*)() noexcept')}}
@ -140,13 +140,13 @@ namespace cwg1512 { // cwg1512: 4
void(Wrap<nullptr_t>() == Wrap<nullptr_t>()); void(Wrap<nullptr_t>() == Wrap<nullptr_t>());
void(Wrap<nullptr_t>() != Wrap<nullptr_t>()); void(Wrap<nullptr_t>() != Wrap<nullptr_t>());
void(Wrap<nullptr_t>() < Wrap<nullptr_t>()); void(Wrap<nullptr_t>() < Wrap<nullptr_t>());
// since-cxx11-error@-1 {{invalid operands to binary expression ('Wrap<nullptr_t>' (aka 'Wrap<std::nullptr_t>') and 'Wrap<nullptr_t>' (aka 'Wrap<std::nullptr_t>'))}} // since-cxx11-error@-1 {{invalid operands to binary expression ('Wrap<nullptr_t>' (aka 'Wrap<std::nullptr_t>') and 'Wrap<nullptr_t>')}}
void(Wrap<nullptr_t>() > Wrap<nullptr_t>()); void(Wrap<nullptr_t>() > Wrap<nullptr_t>());
// since-cxx11-error@-1 {{invalid operands to binary expression ('Wrap<nullptr_t>' (aka 'Wrap<std::nullptr_t>') and 'Wrap<nullptr_t>' (aka 'Wrap<std::nullptr_t>'))}} // since-cxx11-error@-1 {{invalid operands to binary expression ('Wrap<nullptr_t>' (aka 'Wrap<std::nullptr_t>') and 'Wrap<nullptr_t>')}}
void(Wrap<nullptr_t>() <= Wrap<nullptr_t>()); void(Wrap<nullptr_t>() <= Wrap<nullptr_t>());
// since-cxx11-error@-1 {{invalid operands to binary expression ('Wrap<nullptr_t>' (aka 'Wrap<std::nullptr_t>') and 'Wrap<nullptr_t>' (aka 'Wrap<std::nullptr_t>'))}} // since-cxx11-error@-1 {{invalid operands to binary expression ('Wrap<nullptr_t>' (aka 'Wrap<std::nullptr_t>') and 'Wrap<nullptr_t>')}}
void(Wrap<nullptr_t>() >= Wrap<nullptr_t>()); void(Wrap<nullptr_t>() >= Wrap<nullptr_t>());
// since-cxx11-error@-1 {{invalid operands to binary expression ('Wrap<nullptr_t>' (aka 'Wrap<std::nullptr_t>') and 'Wrap<nullptr_t>' (aka 'Wrap<std::nullptr_t>'))}} // since-cxx11-error@-1 {{invalid operands to binary expression ('Wrap<nullptr_t>' (aka 'Wrap<std::nullptr_t>') and 'Wrap<nullptr_t>')}}
// Under cwg1213, this is ill-formed: we select the builtin operator<(int*, int*) // Under cwg1213, this is ill-formed: we select the builtin operator<(int*, int*)
// but then only convert as far as 'nullptr_t', which we then can't convert to 'int*'. // but then only convert as far as 'nullptr_t', which we then can't convert to 'int*'.
@ -332,7 +332,7 @@ namespace cwg1550 { // cwg1550: 3.4
namespace cwg1558 { // cwg1558: 12 namespace cwg1558 { // cwg1558: 12
#if __cplusplus >= 201103L #if __cplusplus >= 201103L
template<class T, class...> using first_of = T; template<class T, class...> using first_of = T;
template<class T> first_of<void, typename T::type> f(int); // #cwg1558-f template<class T> first_of<void, typename T::type> f(int); // #cwg1558-f
template<class T> void f(...) = delete; // #cwg1558-f-deleted template<class T> void f(...) = delete; // #cwg1558-f-deleted
struct X { typedef void type; }; struct X { typedef void type; };
@ -639,7 +639,7 @@ namespace cwg1591 { //cwg1591. Deducing array bound and element type from initi
#if __cplusplus >= 201103L #if __cplusplus >= 201103L
template<class T, int N> int h(T const(&)[N]); template<class T, int N> int h(T const(&)[N]);
int X = h({1,2,3}); // T deduced to int, N deduced to 3 int X = h({1,2,3}); // T deduced to int, N deduced to 3
template<class T> int j(T const(&)[3]); template<class T> int j(T const(&)[3]);
int Y = j({42}); // T deduced to int, array bound not considered int Y = j({42}); // T deduced to int, array bound not considered
@ -655,12 +655,12 @@ namespace cwg1591 { //cwg1591. Deducing array bound and element type from initi
template<class T, int N> int n(T const(&)[N], T); template<class T, int N> int n(T const(&)[N], T);
int X1 = n({{1},{2},{3}},Aggr()); // OK, T is Aggr, N is 3 int X1 = n({{1},{2},{3}},Aggr()); // OK, T is Aggr, N is 3
namespace check_multi_dim_arrays { namespace check_multi_dim_arrays {
template<class T, int N, int M, int O> int ***f(const T (&a)[N][M][O]); // #cwg1591-f-3 template<class T, int N, int M, int O> int ***f(const T (&a)[N][M][O]); // #cwg1591-f-3
template<class T, int N, int M> int **f(const T (&a)[N][M]); // #cwg1591-f-2 template<class T, int N, int M> int **f(const T (&a)[N][M]); // #cwg1591-f-2
template<class T, int N> int *f(const T (&a)[N]); // #cwg1591-f-1 template<class T, int N> int *f(const T (&a)[N]); // #cwg1591-f-1
int ***p3 = f({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12} } }); int ***p3 = f({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12} } });
int ***p33 = f({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12, 13} } }); int ***p33 = f({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12, 13} } });
@ -675,7 +675,7 @@ namespace cwg1591 { //cwg1591. Deducing array bound and element type from initi
namespace check_multi_dim_arrays_rref { namespace check_multi_dim_arrays_rref {
template<class T, int N, int M, int O> int ***g(T (&&a)[N][M][O]); // #cwg1591-g-3 template<class T, int N, int M, int O> int ***g(T (&&a)[N][M][O]); // #cwg1591-g-3
template<class T, int N, int M> int **g(T (&&a)[N][M]); // #cwg1591-g-2 template<class T, int N, int M> int **g(T (&&a)[N][M]); // #cwg1591-g-2
template<class T, int N> int *g(T (&&a)[N]); // #cwg1591-g-1 template<class T, int N> int *g(T (&&a)[N]); // #cwg1591-g-1
int ***p3 = g({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12} } }); int ***p3 = g({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12} } });
int ***p33 = g({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12, 13} } }); int ***p33 = g({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12, 13} } });
@ -687,7 +687,7 @@ namespace cwg1591 { //cwg1591. Deducing array bound and element type from initi
int **p22 = g({ {1,2}, {3, 4} }); int **p22 = g({ {1,2}, {3, 4} });
int *p1 = g({1, 2, 3}); int *p1 = g({1, 2, 3});
} }
namespace check_arrays_of_init_list { namespace check_arrays_of_init_list {
template<class T, int N> float *h(const std::initializer_list<T> (&)[N]); template<class T, int N> float *h(const std::initializer_list<T> (&)[N]);
template<class T, int N> double *h(const T(&)[N]); template<class T, int N> double *h(const T(&)[N]);
@ -695,7 +695,7 @@ namespace cwg1591 { //cwg1591. Deducing array bound and element type from initi
float *fp = h({{1}, {1, 2}, {1, 2, 3}}); float *fp = h({{1}, {1, 2}, {1, 2, 3}});
} }
namespace core_reflector_28543 { namespace core_reflector_28543 {
template<class T, int N> int *i(T (&&)[N]); // #1 template<class T, int N> int *i(T (&&)[N]); // #1
template<class T> char *i(std::initializer_list<T> &&); // #2 template<class T> char *i(std::initializer_list<T> &&); // #2
template<class T, int N, int M> int **i(T (&&)[N][M]); // #3 #cwg1591-i-2 template<class T, int N, int M> int **i(T (&&)[N][M]); // #3 #cwg1591-i-2
@ -704,13 +704,13 @@ namespace cwg1591 { //cwg1591. Deducing array bound and element type from initi
template<class T> short *i(T (&&)[2]); // #5 template<class T> short *i(T (&&)[2]); // #5
template<class T> using Arr = T[]; template<class T> using Arr = T[];
char *pc = i({1, 2, 3}); // OK prefer #2 via 13.3.3.2 [over.ics.rank] char *pc = i({1, 2, 3}); // OK prefer #2 via 13.3.3.2 [over.ics.rank]
char *pc2 = i({1, 2}); // #2 also char *pc2 = i({1, 2}); // #2 also
int *pi = i(Arr<int>{1, 2, 3}); // OK prefer #1 int *pi = i(Arr<int>{1, 2, 3}); // OK prefer #1
void *pv1 = i({ {1, 2, 3}, {4, 5, 6} }); // ambiguous btw 3 & 4 void *pv1 = i({ {1, 2, 3}, {4, 5, 6} }); // ambiguous btw 3 & 4
// since-cxx11-error@-1 {{call to 'i' is ambiguous}} // since-cxx11-error@-1 {{call to 'i' is ambiguous}}
// since-cxx11-note@#cwg1591-i-2 {{candidate function [with T = int, N = 2, M = 3]}} // since-cxx11-note@#cwg1591-i-2 {{candidate function [with T = int, N = 2, M = 3]}}
// since-cxx11-note@#cwg1591-i-1 {{candidate function [with T = int, N = 2]}} // since-cxx11-note@#cwg1591-i-1 {{candidate function [with T = int, N = 2]}}
char **pcc = i({ {1}, {2, 3} }); // OK #4 char **pcc = i({ {1}, {2, 3} }); // OK #4

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

@ -69,20 +69,16 @@ int main() {
Bar<short> barShort; Bar<short> barShort;
// LLDB: !DILocalVariable(name: "barShort", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_SHORT_TY_2:[0-9]+]]) // LLDB: !DILocalVariable(name: "barShort", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_SHORT_TY:[0-9]+]])
// GDB: !DILocalVariable(name: "barShort", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_SHORT_TYPEDEF:[0-9]+]]) // GDB: !DILocalVariable(name: "barShort", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_SHORT_TYPEDEF:[0-9]+]])
// GDB: ![[BAR_SHORT_TYPEDEF]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar<short>" // GDB: ![[BAR_SHORT_TYPEDEF]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar<short>"
Bar<char> barChar; Bar<char> barChar;
// LLDB: ![[BAR_SHORT_TY_2]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar<short>", file: ![[#]], line: [[#]], baseType: ![[BAR_SHORT_TY]]) // LLDB: !DILocalVariable(name: "barChar", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_CHAR_TY:[0-9]+]])
// LLDB: !DILocalVariable(name: "barChar", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_CHAR_TY_2:[0-9]+]])
// GDB: !DILocalVariable(name: "barChar", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_CHAR_TYPEDEF:[0-9]+]]) // GDB: !DILocalVariable(name: "barChar", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_CHAR_TYPEDEF:[0-9]+]])
// GDB: ![[BAR_CHAR_TYPEDEF]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar<char>" // GDB: ![[BAR_CHAR_TYPEDEF]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar<char>"
// LLDB: ![[BAR_CHAR_TY_2]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar<char>", file: ![[#]], line: [[#]], baseType: ![[BAR_CHAR_TY]])
return 0; return 0;
} }

View File

@ -1,5 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s // RUN: %clang_cc1 -fsyntax-only -std=c++11 %s
// XFAIL: asserts
// FIXME: With deduction changes to better preserve
// type sugar, the bug that this test case used to
// expose is harder to reproduce.
template <class> struct Pair; template <class> struct Pair;
template <class...> struct Tuple { template <class...> struct Tuple {

View File

@ -98,7 +98,7 @@ void test7(C& c) {
// C++ [dcl.ref]p1, C++ [dcl.ref]p4 // C++ [dcl.ref]p1, C++ [dcl.ref]p4
void test8(int& const,// expected-error{{'const' qualifier may not be applied to a reference}} void test8(int& const,// expected-error{{'const' qualifier may not be applied to a reference}}
void&, // expected-error{{cannot form a reference to 'void'}} void&, // expected-error{{cannot form a reference to 'void'}}
int& &) // expected-error{{type name declared as a reference to a reference}} int& &) // expected-error{{type name declared as a reference to a reference}}
{ {
@ -131,7 +131,7 @@ class string {
char *Data; char *Data;
unsigned Length; unsigned Length;
public: public:
string(); string();
~string(); ~string();
}; };
@ -144,11 +144,11 @@ void test9() {
void test10() { void test10() {
__attribute((vector_size(16))) typedef int vec4; __attribute((vector_size(16))) typedef int vec4;
typedef __attribute__(( ext_vector_type(4) )) int ext_vec4; typedef __attribute__(( ext_vector_type(4) )) int ext_vec4;
vec4 v; vec4 v;
int &a = v[0]; // expected-error{{non-const reference cannot bind to vector element}} int &a = v[0]; // expected-error{{non-const reference cannot bind to vector element}}
const int &b = v[0]; const int &b = v[0];
ext_vec4 ev; ext_vec4 ev;
int &c = ev.x; // expected-error{{non-const reference cannot bind to vector element}} int &c = ev.x; // expected-error{{non-const reference cannot bind to vector element}}
const int &d = ev.x; const int &d = ev.x;
@ -216,3 +216,15 @@ namespace PR45521 {
int *d; int *d;
const a &r = d; const a &r = d;
} }
namespace with_sugar {
template <template <class> class TT, class T, class = T&> void f(TT<T>);
// expected-note@-1 {{cannot form a reference to 'Void' (aka 'void')}}
template <class> struct B {};
using Void = void;
void g() {
f(B<Void>()); // expected-error {{no matching function for call}}
}
}

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

@ -130,16 +130,12 @@ namespace ttp_defaults {
template <template <class T1> class TT1> struct A {}; template <template <class T1> class TT1> struct A {};
template <template <class T2> class TT2> void f(A<TT2>); template <template <class T2> class TT2> void f(A<TT2>);
// expected-note@-1 {{explicit instantiation candidate}}
// FIXME: The default arguments on the TTP are not available during partial ordering.
template <template <class T3, class T4 = float> class TT3> void f(A<TT3>) {}; template <template <class T3, class T4 = float> class TT3> void f(A<TT3>) {};
// expected-note@-1 {{explicit instantiation candidate}}
template <class T5, class T6 = int> struct B; template <class T5, class T6 = int> struct B;
template void f<B>(A<B>); template void f<B>(A<B>);
// expected-error@-1 {{partial ordering for explicit instantiation of 'f' is ambiguous}}
} // namespace ttp_defaults } // namespace ttp_defaults
namespace ttp_only { namespace ttp_only {

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,73 +17,46 @@ 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'
// 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'
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element // CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element
// CHECK-NEXT: |-TemplateArgument expr '0' // CHECK-NEXT: |-TemplateArgument expr '0'
// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' // CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long'
// 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'
// 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

@ -188,7 +188,7 @@ static std::optional<ArrayRef<TemplateArgument>>
GetTemplateArguments(QualType Type) { GetTemplateArguments(QualType Type) {
assert(!Type.isNull()); assert(!Type.isNull());
if (const auto *Specialization = Type->getAs<TemplateSpecializationType>()) if (const auto *Specialization = Type->getAs<TemplateSpecializationType>())
return Specialization->template_arguments(); return Specialization->getSpecifiedArguments();
if (const auto *RecordDecl = Type->getAsCXXRecordDecl()) { if (const auto *RecordDecl = Type->getAsCXXRecordDecl()) {
const auto *TemplateDecl = const auto *TemplateDecl =

View File

@ -39,10 +39,10 @@ int main(int, char**)
optional<void()> opt4; optional<void()> opt4;
} }
{ {
// expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with a non-object type is undefined behavior}} // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with a non-object type is undefined behavior}}
// expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with a non-destructible type is ill-formed}} // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with a non-destructible type is ill-formed}}
// expected-error@optional:* 1+ {{cannot form a reference to 'void'}} // expected-error@optional:* 1+ {{cannot form a reference to}}
optional<const void> opt4; optional<const void> opt4;
} }
// FIXME these are garbage diagnostics that Clang should not produce // FIXME these are garbage diagnostics that Clang should not produce
// expected-error@optional:* 0+ {{is not a base class}} // expected-error@optional:* 0+ {{is not a base class}}