[clang] [clang-tools-extra] [libcxx] WIP: [clang] store sugared converted arguments on TemplateSpecializationType (PR #132439)
Matheus Izvekov via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 21 11:07:44 PDT 2025
https://github.com/mizvekov created https://github.com/llvm/llvm-project/pull/132439
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
>From 6f705031ce3646a5699a8cfdeeeb32569409be49 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Sat, 17 Sep 2022 18:07:28 +0200
Subject: [PATCH] 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
---
.../modernize/UseTransparentFunctorsCheck.cpp | 6 +-
.../clang-tidy/mpi/TypeMismatchCheck.cpp | 2 +-
clang-tools-extra/clangd/AST.cpp | 10 +-
clang/include/clang/AST/ASTContext.h | 43 +--
clang/include/clang/AST/ASTNodeTraverser.h | 2 +-
clang/include/clang/AST/DeclTemplate.h | 8 +-
clang/include/clang/AST/RecursiveASTVisitor.h | 5 +-
clang/include/clang/AST/TemplateBase.h | 3 +-
clang/include/clang/AST/Type.h | 49 +--
clang/include/clang/AST/TypeLoc.h | 6 +-
clang/include/clang/AST/TypeProperties.td | 28 +-
.../clang/ASTMatchers/ASTMatchersInternal.h | 2 +-
.../clang/Basic/DiagnosticSemaKinds.td | 2 +-
clang/include/clang/Sema/SemaConcept.h | 4 +-
.../clang/Serialization/ASTRecordReader.h | 4 +
clang/lib/AST/ASTConcept.cpp | 2 +-
clang/lib/AST/ASTContext.cpp | 283 ++++++++++--------
clang/lib/AST/ASTDiagnostic.cpp | 23 +-
clang/lib/AST/ASTImporter.cpp | 15 +-
clang/lib/AST/ASTStructuralEquivalence.cpp | 7 +-
clang/lib/AST/DeclTemplate.cpp | 10 +-
clang/lib/AST/ItaniumMangle.cpp | 15 +-
clang/lib/AST/NestedNameSpecifier.cpp | 5 +-
clang/lib/AST/ODRHash.cpp | 4 +-
clang/lib/AST/QualTypeNames.cpp | 8 +-
clang/lib/AST/TemplateBase.cpp | 19 +-
clang/lib/AST/TemplateName.cpp | 4 +-
clang/lib/AST/Type.cpp | 136 +++++----
clang/lib/AST/TypePrinter.cpp | 14 +-
clang/lib/CodeGen/CGDebugInfo.cpp | 4 +-
clang/lib/ExtractAPI/DeclarationFragments.cpp | 2 +-
clang/lib/Index/USRGeneration.cpp | 4 +-
clang/lib/Sema/HeuristicResolver.cpp | 4 +-
clang/lib/Sema/SemaCXXScopeSpec.cpp | 2 +-
clang/lib/Sema/SemaCodeComplete.cpp | 5 +-
clang/lib/Sema/SemaConcept.cpp | 3 +-
clang/lib/Sema/SemaDeclCXX.cpp | 2 +-
clang/lib/Sema/SemaExpr.cpp | 6 +-
clang/lib/Sema/SemaTemplate.cpp | 182 +++++------
clang/lib/Sema/SemaTemplateDeduction.cpp | 144 ++++-----
clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 4 +-
clang/lib/Sema/SemaTemplateInstantiate.cpp | 2 +-
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 11 +-
clang/lib/Sema/SemaType.cpp | 2 +-
clang/lib/Sema/TreeTransform.h | 24 +-
clang/lib/Serialization/ASTReader.cpp | 6 +-
.../Serialization/TemplateArgumentHasher.cpp | 4 +-
.../Checkers/StdVariantChecker.cpp | 2 +-
clang/test/AST/ast-dump-ctad-alias.cpp | 8 +-
.../class.derived.general/p2.cpp | 2 +-
clang/test/CXX/drs/cwg15xx.cpp | 32 +-
.../temp/temp.decls/temp.class.spec/p6.cpp | 4 +-
clang/test/CodeGen/preferred_name.cpp | 8 +-
clang/test/SemaCXX/pr100095.cpp | 5 +-
clang/test/SemaCXX/references.cpp | 20 +-
.../undefined-partial-specialization.cpp | 2 +-
clang/test/SemaTemplate/cwg2398.cpp | 4 -
clang/test/SemaTemplate/make_integer_seq.cpp | 71 ++---
clang/test/SemaTemplate/type_pack_element.cpp | 63 ++--
clang/tools/libclang/CXType.cpp | 2 +-
...al_requires_destructible_object.verify.cpp | 8 +-
61 files changed, 726 insertions(+), 635 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp
index 2223a1999f736..a7f4adc8be944 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp
@@ -94,9 +94,9 @@ void UseTransparentFunctorsCheck::check(
unsigned ArgNum = 0;
const auto *FunctorParentType =
FunctorParentLoc.getType()->castAs<TemplateSpecializationType>();
- for (; ArgNum < FunctorParentType->template_arguments().size(); ++ArgNum) {
+ for (; ArgNum < FunctorParentType->getSpecifiedArguments().size(); ++ArgNum) {
const TemplateArgument &Arg =
- FunctorParentType->template_arguments()[ArgNum];
+ FunctorParentType->getSpecifiedArguments()[ArgNum];
if (Arg.getKind() != TemplateArgument::Type)
continue;
QualType ParentArgType = Arg.getAsType();
@@ -106,7 +106,7 @@ void UseTransparentFunctorsCheck::check(
break;
}
// Functor is a default template argument.
- if (ArgNum == FunctorParentType->template_arguments().size())
+ if (ArgNum == FunctorParentType->getSpecifiedArguments().size())
return;
TemplateArgumentLoc FunctorLoc = FunctorParentLoc.getArgLoc(ArgNum);
auto FunctorTypeLoc = getInnerTypeLocAs<TemplateSpecializationTypeLoc>(
diff --git a/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp b/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp
index 5abe4f77d6598..5384b0fe3c45e 100644
--- a/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp
+++ b/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp
@@ -181,7 +181,7 @@ isCXXComplexTypeMatching(const TemplateSpecializationType *const Template,
if (Template->getAsCXXRecordDecl()->getName() != "complex")
return true;
- const auto *Builtin = Template->template_arguments()[0]
+ const auto *Builtin = Template->getSpecifiedArguments()[0]
.getAsType()
.getTypePtr()
->getAs<BuiltinType>();
diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp
index f3eee1c6335f9..4b97cceb6a46d 100644
--- a/clang-tools-extra/clangd/AST.cpp
+++ b/clang-tools-extra/clangd/AST.cpp
@@ -438,9 +438,15 @@ bool hasReservedScope(const DeclContext &DC) {
QualType declaredType(const TypeDecl *D) {
ASTContext &Context = D->getASTContext();
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(
- TemplateName(CTSD->getSpecializedTemplate()), Args->arguments());
+ TemplateName(CTSD->getSpecializedTemplate()), Args,
+ /*SugaredConvertedArgs=*/std::nullopt,
+ /*CanonicalConvertedArgs=*/std::nullopt);
+ }
return Context.getTypeDeclType(D);
}
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index af8c49e99a7ce..ef596f99262be 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1810,22 +1810,24 @@ class ASTContext : public RefCountedBase<ASTContext> {
bool ParameterPack,
TemplateTypeParmDecl *ParmDecl = nullptr) const;
- QualType getTemplateSpecializationType(TemplateName T,
- ArrayRef<TemplateArgument> Args,
- QualType Canon = QualType()) const;
-
- QualType
- getCanonicalTemplateSpecializationType(TemplateName T,
- ArrayRef<TemplateArgument> Args) const;
-
- QualType getTemplateSpecializationType(TemplateName T,
- ArrayRef<TemplateArgumentLoc> Args,
- QualType Canon = QualType()) const;
-
- TypeSourceInfo *
- getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc,
- const TemplateArgumentListInfo &Args,
- QualType Canon = QualType()) const;
+ QualType getTemplateSpecializationType(
+ TemplateName T, ArrayRef<TemplateArgument> SpecifiedArgs,
+ ArrayRef<TemplateArgument> SugaredConvertedArgs,
+ ArrayRef<TemplateArgument> CanonicalConvertedArgs,
+ QualType Canon = QualType()) const;
+
+ QualType getTemplateSpecializationType(
+ TemplateName T, ArrayRef<TemplateArgumentLoc> SpecifiedArgs,
+ ArrayRef<TemplateArgument> SugaredConvertedArgs,
+ ArrayRef<TemplateArgument> CanonicalConvertedArgs,
+ QualType Canon = QualType()) const;
+
+ TypeSourceInfo *getTemplateSpecializationTypeInfo(
+ TemplateName T, SourceLocation TLoc,
+ const TemplateArgumentListInfo &SpecifiedArgs,
+ ArrayRef<TemplateArgument> SugaredConvertedArgs,
+ ArrayRef<TemplateArgument> CanonicalConvertedArgs,
+ QualType Canon = QualType()) const;
QualType getParenType(QualType NamedType) const;
@@ -1845,7 +1847,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
const IdentifierInfo *Name, ArrayRef<TemplateArgumentLoc> Args) const;
QualType getDependentTemplateSpecializationType(
ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
- const IdentifierInfo *Name, ArrayRef<TemplateArgument> Args) const;
+ const IdentifierInfo *Name, ArrayRef<TemplateArgument> Args,
+ bool Canonical = false) const;
TemplateArgument getInjectedTemplateArg(NamedDecl *ParamDecl) const;
@@ -2936,6 +2939,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg)
const;
+ /// Canonicalize the given template argument list.
+ ///
+ /// Returns true if any arguments were non-canonical, false otherwise.
+ bool
+ canonicalizeTemplateArguments(MutableArrayRef<TemplateArgument> Args) const;
+
/// Type Query functions. If the type is an instance of the specified class,
/// return the Type pointer for the underlying maximally pretty type. This
/// is a member of ASTContext because this may need to do some amount of
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index f557555e96e59..b428212243a04 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -452,7 +452,7 @@ class ASTNodeTraverser
Visit(T->getArgumentPack());
}
void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
- for (const auto &Arg : T->template_arguments())
+ for (const auto &Arg : T->getSpecifiedArguments())
Visit(Arg);
}
void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index b27e698236c02..3364d736bf886 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -608,8 +608,10 @@ class FunctionTemplateSpecializationInfo final
Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs,
const ASTContext &Context) {
ID.AddInteger(TemplateArgs.size());
+ // We allow instantiating deduction guides with non-canonical template
+ // arguments.
for (const TemplateArgument &TemplateArg : TemplateArgs)
- TemplateArg.Profile(ID, Context);
+ TemplateArg.Profile(ID, Context, /*Canonical=*/false);
}
};
@@ -2096,7 +2098,7 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
const ASTContext &Context) {
ID.AddInteger(TemplateArgs.size());
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()); }
@@ -2869,7 +2871,7 @@ class VarTemplateSpecializationDecl : public VarDecl,
const ASTContext &Context) {
ID.AddInteger(TemplateArgs.size());
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()); }
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index e93d1d8eab56f..59a705370fae0 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1134,7 +1134,10 @@ DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {
DEF_TRAVERSE_TYPE(TemplateSpecializationType, {
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, {})
diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h
index 9d0ee24a4f5e3..9fc35192e3ba1 100644
--- a/clang/include/clang/AST/TemplateBase.h
+++ b/clang/include/clang/AST/TemplateBase.h
@@ -465,7 +465,8 @@ class TemplateArgument {
void dump() const;
/// 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.
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 65756203f2073..642881f185c07 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2208,10 +2208,9 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
/// specialization, which is expected to be able to hold at least 1024
/// according to [implimits]. However, as this limit is somewhat easy to
/// 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
- /// this type safely fits in 64 bits as an unsigned, so there is no reason
- /// to introduce the performance impact of a bitfield.
- unsigned NumArgs;
+ /// as possible.
+ unsigned NumSpecifiedArgs : 16;
+ unsigned NumConvertedArgs : 16;
};
class DependentTemplateSpecializationTypeBitfields {
@@ -2830,6 +2829,18 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
/// immediately following this class.
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
/// 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
@@ -6601,7 +6612,7 @@ class AutoType : public DeducedType {
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
QualType Deduced, AutoTypeKeyword Keyword,
bool IsDependent, ConceptDecl *CD,
- ArrayRef<TemplateArgument> Arguments);
+ ArrayRef<TemplateArgument> Arguments, bool Canonical);
static bool classof(const Type *T) {
return T->getTypeClass() == Auto;
@@ -6679,10 +6690,10 @@ class TemplateSpecializationType : public Type, public llvm::FoldingSetNode {
/// replacement must, recursively, be one of these).
TemplateName Template;
- TemplateSpecializationType(TemplateName T,
- ArrayRef<TemplateArgument> Args,
- QualType Canon,
- QualType Aliased);
+ TemplateSpecializationType(TemplateName T, bool IsAlias,
+ ArrayRef<TemplateArgument> SpecifiedArgs,
+ ArrayRef<TemplateArgument> ConvertedArgs,
+ QualType Underlying);
public:
/// Determine whether any of the given template arguments are dependent.
@@ -6735,11 +6746,13 @@ class TemplateSpecializationType : public Type, public llvm::FoldingSetNode {
/// Retrieve the name of the template that we are specializing.
TemplateName getTemplateName() const { return Template; }
- ArrayRef<TemplateArgument> template_arguments() const {
+ ArrayRef<TemplateArgument> getSpecifiedArguments() const {
return {reinterpret_cast<const TemplateArgument *>(this + 1),
- TemplateSpecializationTypeBits.NumArgs};
+ TemplateSpecializationTypeBits.NumSpecifiedArgs};
}
+ ArrayRef<TemplateArgument> getConvertedArguments() const;
+
bool isSugared() const {
return !isDependentType() || isCurrentInstantiation() || isTypeAlias();
}
@@ -6750,8 +6763,10 @@ class TemplateSpecializationType : public Type, public llvm::FoldingSetNode {
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx);
static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T,
- ArrayRef<TemplateArgument> Args,
- const ASTContext &Context);
+ ArrayRef<TemplateArgument> SpecifiedArgs,
+ ArrayRef<TemplateArgument> ConvertedArgs,
+ QualType Underlying, const ASTContext &Context,
+ bool Canonical);
static bool classof(const Type *T) {
return T->getTypeClass() == TemplateSpecialization;
@@ -7110,15 +7125,15 @@ class DependentTemplateSpecializationType : public TypeWithKeyword,
QualType desugar() const { return QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
- Profile(ID, Context, getKeyword(), NNS, Name, template_arguments());
+ Profile(ID, Context, getKeyword(), NNS, Name, template_arguments(),
+ isCanonicalUnqualified());
}
- static void Profile(llvm::FoldingSetNodeID &ID,
- const ASTContext &Context,
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *Qualifier,
const IdentifierInfo *Name,
- ArrayRef<TemplateArgument> Args);
+ ArrayRef<TemplateArgument> Args, bool Canonical);
static bool classof(const Type *T) {
return T->getTypeClass() == DependentTemplateSpecialization;
diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h
index 17ce09fa5da4f..64866df499c31 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -1718,7 +1718,7 @@ class TemplateSpecializationTypeLoc :
}
unsigned getNumArgs() const {
- return getTypePtr()->template_arguments().size();
+ return getTypePtr()->getSpecifiedArguments().size();
}
void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) {
@@ -1730,7 +1730,7 @@ class TemplateSpecializationTypeLoc :
}
TemplateArgumentLoc getArgLoc(unsigned i) const {
- return TemplateArgumentLoc(getTypePtr()->template_arguments()[i],
+ return TemplateArgumentLoc(getTypePtr()->getSpecifiedArguments()[i],
getArgLocInfo(i));
}
@@ -1766,7 +1766,7 @@ class TemplateSpecializationTypeLoc :
setTemplateNameLoc(Loc);
setLAngleLoc(Loc);
setRAngleLoc(Loc);
- initializeArgLocs(Context, getTypePtr()->template_arguments(),
+ initializeArgLocs(Context, getTypePtr()->getSpecifiedArguments(),
getArgInfos(), Loc);
}
diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td
index 27f71bf5cc62f..c4f9ea6e70a05 100644
--- a/clang/include/clang/AST/TypeProperties.td
+++ b/clang/include/clang/AST/TypeProperties.td
@@ -743,29 +743,27 @@ let Class = TemplateSpecializationType in {
def : Property<"templateName", TemplateName> {
let Read = [{ node->getTemplateName() }];
}
- def : Property<"templateArguments", Array<TemplateArgument>> {
- let Read = [{ node->template_arguments() }];
+ def : Property<"specifiedArguments", Array<TemplateArgument>> {
+ let Read = [{ node->getSpecifiedArguments() }];
}
- def : Property<"underlyingType", Optional<QualType>> {
+ def : Property<"convertedArguments", Array<TemplateArgument>> {
+ let Read = [{ node->getConvertedArguments() }];
+ }
+ def : Property<"underlyingType", QualType> {
let Read = [{
node->isTypeAlias()
- ? std::optional<QualType>(node->getAliasedType())
+ ? node->getAliasedType()
: node->isCanonicalUnqualified()
- ? std::nullopt
- : std::optional<QualType>(node->getCanonicalTypeInternal())
+ ? QualType() : node->getCanonicalTypeInternal()
}];
}
def : Creator<[{
- QualType result;
- if (!underlyingType) {
- result = ctx.getCanonicalTemplateSpecializationType(templateName,
- templateArguments);
- } else {
- result = ctx.getTemplateSpecializationType(templateName,
- templateArguments,
- *underlyingType);
- }
+ QualType result = ctx.getTemplateSpecializationType(templateName,
+ specifiedArguments,
+ convertedArguments,
+ /*CanonicalConvertedArguments=*/{},
+ underlyingType);
if (dependent)
const_cast<Type *>(result.getTypePtr())
->addDependence(TypeDependence::DependentInstantiation);
diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
index 55a925bf86909..03cc39421b2be 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1949,7 +1949,7 @@ getTemplateSpecializationArgs(const VarTemplateSpecializationDecl &D) {
inline ArrayRef<TemplateArgument>
getTemplateSpecializationArgs(const TemplateSpecializationType &T) {
- return T.template_arguments();
+ return T.getSpecifiedArguments();
}
inline ArrayRef<TemplateArgument>
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0cee58d8de513..cc42f5fd24caa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6977,7 +6977,7 @@ def err_illegal_decl_mempointer_to_void : Error<
"'%0' declared as a member pointer to void">;
def err_illegal_decl_mempointer_in_nonclass
: 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<
"block pointer to non-function type is invalid">;
def err_return_block_has_expr : Error<"void block should not return a value">;
diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h
index 5c599a70532f6..c59b7dff5bc35 100644
--- a/clang/include/clang/Sema/SemaConcept.h
+++ b/clang/include/clang/Sema/SemaConcept.h
@@ -48,9 +48,9 @@ struct alignas(ConstraintAlignment) AtomicConstraint {
for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I) {
llvm::FoldingSetNodeID IDA, IDB;
C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument())
- .Profile(IDA, C);
+ .Profile(IDA, C, /*Canonical=*/true);
C.getCanonicalTemplateArgument((*Other.ParameterMapping)[I].getArgument())
- .Profile(IDB, C);
+ .Profile(IDB, C, /*Canonical=*/true);
if (IDA != IDB)
return false;
}
diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h
index 7117b7246739b..d935ec50ce147 100644
--- a/clang/include/clang/Serialization/ASTRecordReader.h
+++ b/clang/include/clang/Serialization/ASTRecordReader.h
@@ -247,6 +247,10 @@ class ASTRecordReader
void readTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs,
bool Canonicalize = false);
+ /// Read a template argument list.
+ const TemplateArgumentList *
+ readTemplateArgumentList(bool Canonicalize = false);
+
/// Read a UnresolvedSet structure, advancing Idx.
void readUnresolvedSet(LazyASTUnresolvedSet &Set);
diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp
index f7ee0fb3ee92d..3b8883fa5cbbe 100644
--- a/clang/lib/AST/ASTConcept.cpp
+++ b/clang/lib/AST/ASTConcept.cpp
@@ -80,7 +80,7 @@ void ConstraintSatisfaction::Profile(
ID.AddPointer(ConstraintOwner);
ID.AddInteger(TemplateArgs.size());
for (auto &Arg : TemplateArgs)
- Arg.Profile(ID, C);
+ Arg.Profile(ID, C, /*Canonical=*/false);
}
ConceptReference *
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index de868ac821745..7a44fd4a5dd0e 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3088,12 +3088,26 @@ static auto getCanonicalTemplateArguments(const ASTContext &C,
ArrayRef<TemplateArgument> Args,
bool &AnyNonCanonArgs) {
SmallVector<TemplateArgument, 16> CanonArgs(Args);
- for (auto &Arg : CanonArgs) {
+ AnyNonCanonArgs |= C.canonicalizeTemplateArguments(CanonArgs);
+ return CanonArgs;
+}
+
+bool ASTContext::canonicalizeTemplateArguments(
+ MutableArrayRef<TemplateArgument> Args) const {
+ bool AnyNonCanonArgs = false;
+ for (auto &Arg : Args) {
TemplateArgument OrigArg = Arg;
- Arg = C.getCanonicalTemplateArgument(Arg);
- AnyNonCanonArgs |= !Arg.structurallyEquals(OrigArg);
+ 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 CanonArgs;
+ return AnyNonCanonArgs;
}
//===----------------------------------------------------------------------===//
@@ -5544,41 +5558,41 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
return QualType(TypeParm, 0);
}
-TypeSourceInfo *
-ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
- SourceLocation NameLoc,
- const TemplateArgumentListInfo &Args,
- QualType Underlying) const {
- assert(!Name.getAsDependentTemplateName() &&
- "No dependent template names here!");
- QualType TST =
- getTemplateSpecializationType(Name, Args.arguments(), Underlying);
+TypeSourceInfo *ASTContext::getTemplateSpecializationTypeInfo(
+ TemplateName Name, SourceLocation NameLoc,
+ const TemplateArgumentListInfo &SpecifiedArgs,
+ ArrayRef<TemplateArgument> SugaredConvertedArgs,
+ ArrayRef<TemplateArgument> CanonicalConvertedArgs,
+ QualType Underlying) const {
+ QualType TST = getTemplateSpecializationType(
+ Name, SpecifiedArgs.arguments(), SugaredConvertedArgs,
+ CanonicalConvertedArgs, Underlying);
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
TemplateSpecializationTypeLoc TL =
DI->getTypeLoc().castAs<TemplateSpecializationTypeLoc>();
TL.setTemplateKeywordLoc(SourceLocation());
TL.setTemplateNameLoc(NameLoc);
- TL.setLAngleLoc(Args.getLAngleLoc());
- TL.setRAngleLoc(Args.getRAngleLoc());
+ TL.setLAngleLoc(SpecifiedArgs.getLAngleLoc());
+ TL.setRAngleLoc(SpecifiedArgs.getRAngleLoc());
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
- TL.setArgLocInfo(i, Args[i].getLocInfo());
+ TL.setArgLocInfo(i, SpecifiedArgs[i].getLocInfo());
return DI;
}
-QualType
-ASTContext::getTemplateSpecializationType(TemplateName Template,
- ArrayRef<TemplateArgumentLoc> Args,
- QualType Underlying) const {
- assert(!Template.getAsDependentTemplateName() &&
- "No dependent template names here!");
+QualType ASTContext::getTemplateSpecializationType(
+ TemplateName Template, ArrayRef<TemplateArgumentLoc> SpecifiedArgs,
+ ArrayRef<TemplateArgument> SugaredConvertedArgs,
+ ArrayRef<TemplateArgument> CanonicalConvertedArgs,
+ QualType Underlying) const {
+ SmallVector<TemplateArgument, 4> SpecifiedArgVec;
+ SpecifiedArgVec.reserve(SpecifiedArgs.size());
+ for (const TemplateArgumentLoc &Arg : SpecifiedArgs)
+ SpecifiedArgVec.push_back(Arg.getArgument());
- SmallVector<TemplateArgument, 4> ArgVec;
- ArgVec.reserve(Args.size());
- for (const TemplateArgumentLoc &Arg : Args)
- ArgVec.push_back(Arg.getArgument());
-
- return getTemplateSpecializationType(Template, ArgVec, Underlying);
+ return getTemplateSpecializationType(Template, SpecifiedArgVec,
+ SugaredConvertedArgs,
+ CanonicalConvertedArgs, Underlying);
}
#ifndef NDEBUG
@@ -5591,82 +5605,90 @@ static bool hasAnyPackExpansions(ArrayRef<TemplateArgument> Args) {
}
#endif
-QualType
-ASTContext::getTemplateSpecializationType(TemplateName Template,
- ArrayRef<TemplateArgument> Args,
- QualType Underlying) const {
+QualType ASTContext::getTemplateSpecializationType(
+ TemplateName Template, ArrayRef<TemplateArgument> SpecifiedArgs,
+ ArrayRef<TemplateArgument> SugaredConvertedArgs,
+ ArrayRef<TemplateArgument> CanonicalConvertedArgs,
+ QualType Underlying) const {
assert(!Template.getAsDependentTemplateName() &&
"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);
bool IsTypeAlias = TD && TD->isTypeAlias();
- QualType CanonType;
- if (!Underlying.isNull())
- CanonType = getCanonicalType(Underlying);
- else {
- // We can get here with an alias template when the specialization contains
- // a pack expansion that does not match up with a parameter pack.
- assert((!IsTypeAlias || hasAnyPackExpansions(Args)) &&
+ if (Underlying.isNull()) {
+ // We can get here with an alias template when the specialization
+ // contains a pack expansion that does not match up with a parameter
+ // pack.
+ assert((!IsTypeAlias || hasAnyPackExpansions(CanonicalConvertedArgs)) &&
"Caller must compute aliased type");
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
- // try to unique it: these types typically have location information that
- // we don't unique and don't want to lose.
- void *Mem = Allocate(sizeof(TemplateSpecializationType) +
- sizeof(TemplateArgument) * Args.size() +
- (IsTypeAlias ? sizeof(QualType) : 0),
- alignof(TemplateSpecializationType));
- auto *Spec
- = new (Mem) TemplateSpecializationType(Template, Args, CanonType,
- IsTypeAlias ? Underlying : QualType());
+ void *Mem =
+ Allocate(sizeof(TemplateSpecializationType) +
+ sizeof(TemplateArgument) *
+ (SpecifiedArgs.size() + SugaredConvertedArgs.size()) +
+ (IsTypeAlias ? sizeof(QualType) : 0),
+ alignof(TemplateSpecializationType));
+ auto *Spec = new (Mem) TemplateSpecializationType(
+ Template, IsTypeAlias, SpecifiedArgs, SugaredConvertedArgs, Underlying);
Types.push_back(Spec);
- return QualType(Spec, 0);
-}
-
-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");
+ TemplateSpecializationTypes.InsertNode(Spec, InsertPos);
return QualType(Spec, 0);
}
@@ -5773,18 +5795,26 @@ QualType ASTContext::getDependentTemplateSpecializationType(
return getDependentTemplateSpecializationType(Keyword, NNS, Name, ArgCopy);
}
-QualType
-ASTContext::getDependentTemplateSpecializationType(
- ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *NNS,
- const IdentifierInfo *Name,
- ArrayRef<TemplateArgument> Args) const {
+QualType ASTContext::getDependentTemplateSpecializationType(
+ ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name, ArrayRef<TemplateArgument> Args,
+ bool Canonical) const {
assert((!NNS || NNS->isDependent()) &&
"nested-name-specifier must be dependent");
+ ElaboratedTypeKeyword CanonKeyword = Keyword;
+ if (Keyword == ElaboratedTypeKeyword::None)
+ CanonKeyword = ElaboratedTypeKeyword::Typename;
+ NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
+ bool NonCanonical = NNS != CanonNNS || Keyword != CanonKeyword;
+ SmallVector<TemplateArgument, 16> CanonArgs(Args);
+ assert(!(Canonical && NonCanonical));
+ if (!Canonical)
+ NonCanonical |= canonicalizeTemplateArguments(CanonArgs);
+
llvm::FoldingSetNodeID ID;
- DependentTemplateSpecializationType::Profile(ID, *this, Keyword, NNS,
- Name, Args);
+ DependentTemplateSpecializationType::Profile(
+ ID, *this, Keyword, NNS, Name, Args, /*Canonical=*/!NonCanonical);
void *InsertPos = nullptr;
DependentTemplateSpecializationType *T
@@ -5792,22 +5822,10 @@ ASTContext::getDependentTemplateSpecializationType(
if (T)
return QualType(T, 0);
- NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
-
- ElaboratedTypeKeyword CanonKeyword = Keyword;
- if (Keyword == ElaboratedTypeKeyword::None)
- CanonKeyword = ElaboratedTypeKeyword::Typename;
-
- bool AnyNonCanonArgs = false;
- auto CanonArgs =
- ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs);
-
QualType Canon;
- if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) {
- Canon = getDependentTemplateSpecializationType(CanonKeyword, CanonNNS,
- Name,
- CanonArgs);
-
+ if (NonCanonical) {
+ Canon = getDependentTemplateSpecializationType(
+ CanonKeyword, CanonNNS, Name, CanonArgs, /*Canonical=*/true);
// Find the insert position again.
[[maybe_unused]] auto *Nothing =
DependentTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -6450,7 +6468,7 @@ QualType ASTContext::getAutoTypeInternal(
!DeducedType.isNull() && DeducedType->isDependentType();
AutoType::Profile(ID, *this, DeducedType, Keyword,
IsDependent || IsDeducedDependent, TypeConstraintConcept,
- TypeConstraintArgs);
+ TypeConstraintArgs, /*Canonical=*/IsCanon);
if (auto const AT_iter = AutoTypes.find(ID); AT_iter != AutoTypes.end())
return QualType(AT_iter->getSecond(), 0);
@@ -6464,9 +6482,9 @@ QualType ASTContext::getAutoTypeInternal(
auto CanonicalConceptArgs = ::getCanonicalTemplateArguments(
*this, TypeConstraintArgs, AnyNonCanonArgs);
if (CanonicalConcept != TypeConstraintConcept || AnyNonCanonArgs) {
- Canon =
- getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack,
- CanonicalConcept, CanonicalConceptArgs, true);
+ Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack,
+ CanonicalConcept, CanonicalConceptArgs,
+ /*IsCanon=*/true);
}
}
}
@@ -7006,7 +7024,7 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name,
getCanonicalTemplateArgument(subst->getArgumentPack());
return getSubstTemplateTemplateParmPack(
canonArgPack, subst->getAssociatedDecl()->getCanonicalDecl(),
- subst->getFinal(), subst->getIndex());
+ subst->getIndex(), subst->getFinal());
}
case TemplateName::DeducedTemplate: {
assert(IgnoreDeduced == false);
@@ -8180,8 +8198,7 @@ QualType ASTContext::getObjCSuperType() const {
void ASTContext::setCFConstantStringType(QualType T) {
const auto *TD = T->castAs<TypedefType>();
CFConstantStringTypeDecl = cast<TypedefDecl>(TD->getDecl());
- const auto *TagType =
- CFConstantStringTypeDecl->getUnderlyingType()->castAs<RecordType>();
+ const auto *TagType = TD->castAs<RecordType>();
CFConstantStringTagDecl = TagType->getDecl();
}
@@ -14017,13 +14034,16 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
case Type::TemplateSpecialization: {
const auto *TX = cast<TemplateSpecializationType>(X),
*TY = cast<TemplateSpecializationType>(Y);
- auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(),
- TY->template_arguments());
+ auto SpecAs = getCommonTemplateArguments(Ctx, TX->getSpecifiedArguments(),
+ TY->getSpecifiedArguments());
+ auto ConvAs = getCommonTemplateArguments(Ctx, TX->getConvertedArguments(),
+ TY->getConvertedArguments());
return Ctx.getTemplateSpecializationType(
::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(),
TY->getTemplateName(),
/*IgnoreDeduced=*/true),
- As, X->getCanonicalTypeInternal());
+ SpecAs, ConvAs, /*CanonicalConvertedArgs=*/{},
+ X->getCanonicalTypeInternal());
}
case Type::Decltype: {
const auto *DX = cast<DecltypeType>(X);
@@ -14260,11 +14280,14 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
TY->getTemplateName(), /*IgnoreDeduced=*/true);
if (!CTN.getAsVoidPointer())
return QualType();
- SmallVector<TemplateArgument, 8> Args;
- if (getCommonTemplateArguments(Ctx, Args, TX->template_arguments(),
- TY->template_arguments()))
+ SmallVector<TemplateArgument, 8> SpecAs;
+ if (getCommonTemplateArguments(Ctx, SpecAs, TX->getSpecifiedArguments(),
+ TY->getSpecifiedArguments()))
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));
}
case Type::Typedef: {
diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp
index b4e7360e126fb..4916fb44c7ad0 100644
--- a/clang/lib/AST/ASTDiagnostic.cpp
+++ b/clang/lib/AST/ASTDiagnostic.cpp
@@ -117,7 +117,7 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT,
if (!TST->isTypeAlias()) {
bool DesugarArgument = false;
SmallVector<TemplateArgument, 4> Args;
- for (const TemplateArgument &Arg : TST->template_arguments()) {
+ for (const TemplateArgument &Arg : TST->getSpecifiedArguments()) {
if (Arg.getKind() == TemplateArgument::Type)
Args.push_back(desugarForDiagnostic(Context, Arg.getAsType(),
DesugarArgument));
@@ -128,7 +128,8 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT,
if (DesugarArgument) {
ShouldAKA = true;
QT = Context.getTemplateSpecializationType(
- TST->getTemplateName(), Args, QT);
+ TST->getTemplateName(), Args, TST->getConvertedArguments(),
+ /*CanonicalConvertedArguments=*/std::nullopt, QT);
}
break;
}
@@ -985,7 +986,7 @@ class TemplateDiff {
if (isEnd()) return;
// 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;
// Start looking into the parameter pack.
@@ -1006,7 +1007,7 @@ class TemplateDiff {
/// isEnd - Returns true if the iterator is one past the end.
bool isEnd() const {
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.
@@ -1026,11 +1027,11 @@ class TemplateDiff {
// Loop until a template argument is found, or the end is reached.
while (true) {
// Advance to the next template argument. Break if reached the end.
- if (++Index == TST->template_arguments().size())
+ if (++Index == TST->getSpecifiedArguments().size())
break;
// 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)
break;
@@ -1050,7 +1051,7 @@ class TemplateDiff {
assert(TST && "InternalIterator is invalid with a null TST.");
assert(!isEnd() && "Index exceeds number of arguments.");
if (CurrentTA == EndTA)
- return TST->template_arguments()[Index];
+ return TST->getSpecifiedArguments()[Index];
else
return *CurrentTA;
}
@@ -1134,9 +1135,11 @@ class TemplateDiff {
return nullptr;
Ty = Context.getTemplateSpecializationType(
- TemplateName(CTSD->getSpecializedTemplate()),
- CTSD->getTemplateArgs().asArray(),
- Ty.getLocalUnqualifiedType().getCanonicalType());
+ TemplateName(CTSD->getSpecializedTemplate()),
+ /*SpecifiedArgs=*/CTSD->getTemplateArgs().asArray(),
+ /*SugaredConvertedArgs=*/CTSD->getTemplateArgs().asArray(),
+ /*CanonicalConvertedArgs=*/std::nullopt,
+ Ty.getLocalUnqualifiedType().getCanonicalType());
return Ty->getAs<TemplateSpecializationType>();
}
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 1db30b3f3f76f..672175e1e0d49 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1657,7 +1657,12 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType(
SmallVector<TemplateArgument, 2> ToTemplateArgs;
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);
QualType ToCanonType;
@@ -1669,9 +1674,9 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType(
else
return TyOrErr.takeError();
}
- return Importer.getToContext().getTemplateSpecializationType(*ToTemplateOrErr,
- ToTemplateArgs,
- ToCanonType);
+ return Importer.getToContext().getTemplateSpecializationType(
+ *ToTemplateOrErr, ToTemplateArgs, ToConvertedArgs,
+ /*CanonicalConvertedArgs=*/std::nullopt, ToCanonType);
}
ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) {
@@ -3642,7 +3647,7 @@ class IsTypeDeclaredInsideVisitor
std::optional<bool>
VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
- for (const auto &Arg : T->template_arguments())
+ for (const auto &Arg : T->getSpecifiedArguments())
if (checkTemplateArgument(Arg))
return true;
// This type is a "sugar" to a record type, it can have a desugared type.
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index 2c2c8fd677500..c56348c3d73ef 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -1264,8 +1264,11 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(),
Spec2->getTemplateName()))
return false;
- if (!IsStructurallyEquivalent(Context, Spec1->template_arguments(),
- Spec2->template_arguments()))
+ if (!IsStructurallyEquivalent(Context, Spec1->getSpecifiedArguments(),
+ Spec2->getSpecifiedArguments()))
+ return false;
+ if (!IsStructurallyEquivalent(Context, Spec1->getConvertedArguments(),
+ Spec2->getConvertedArguments()))
return false;
break;
}
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index c0f5be51db5f3..bd625846bde0a 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -600,7 +600,7 @@ void ClassTemplatePartialSpecializationDecl::Profile(
TemplateParameterList *TPL, const ASTContext &Context) {
ID.AddInteger(TemplateArgs.size());
for (const TemplateArgument &TemplateArg : TemplateArgs)
- TemplateArg.Profile(ID, Context);
+ TemplateArg.Profile(ID, Context, /*Canonical=*/true);
TPL->Profile(ID, Context);
}
@@ -670,8 +670,12 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
ASTContext &Context = getASTContext();
TemplateName Name = Context.getQualifiedTemplateName(
/*NNS=*/nullptr, /*TemplateKeyword=*/false, TemplateName(this));
+ auto TemplateArgs = getTemplateParameters()->getInjectedTemplateArgs(Context);
CommonPtr->InjectedClassNameType = Context.getTemplateSpecializationType(
- Name, getTemplateParameters()->getInjectedTemplateArgs(Context));
+ Name,
+ /*SpecifiedArgs=*/TemplateArgs,
+ /*SugaredConvertedArgs=*/TemplateArgs,
+ /*CanonicalConvertedArgs=*/std::nullopt);
return CommonPtr->InjectedClassNameType;
}
@@ -1361,7 +1365,7 @@ void VarTemplatePartialSpecializationDecl::Profile(
TemplateParameterList *TPL, const ASTContext &Context) {
ID.AddInteger(TemplateArgs.size());
for (const TemplateArgument &TemplateArg : TemplateArgs)
- TemplateArg.Profile(ID, Context);
+ TemplateArg.Profile(ID, Context, /*Canonical=*/true);
TPL->Profile(ID, Context);
}
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 917402544d4f6..fdf8e9a52ce21 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -1320,7 +1320,9 @@ void CXXNameMangler::manglePrefix(QualType type) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// 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));
}
} else if (const auto *DTST =
@@ -2549,13 +2551,14 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
break;
}
}
-
+ auto Args = TST->isCanonicalUnqualified() ? TST->getConvertedArguments()
+ : TST->getSpecifiedArguments();
// Note: we don't pass in the template name here. We are mangling the
// original source-level template arguments, so we shouldn't consider
// conversions to the corresponding template parameter.
// FIXME: Other compilers mangle partially-resolved template arguments in
// unresolved-qualifier-levels.
- mangleTemplateArgs(TemplateName(), TST->template_arguments());
+ mangleTemplateArgs(TemplateName(), Args);
break;
}
@@ -4427,8 +4430,10 @@ void CXXNameMangler::mangleType(const InjectedClassNameType *T) {
}
void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
+ auto Args = T->isCanonicalUnqualified() ? T->getConvertedArguments()
+ : T->getSpecifiedArguments();
if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) {
- mangleTemplateName(TD, T->template_arguments());
+ mangleTemplateName(TD, Args);
} else {
if (mangleSubstitution(QualType(T, 0)))
return;
@@ -4438,7 +4443,7 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(T->getTemplateName(), T->template_arguments());
+ mangleTemplateArgs(T->getTemplateName(), Args);
addSubstitution(QualType(T, 0));
}
}
diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp
index a256a87695afc..ba17d5fdd15d1 100644
--- a/clang/lib/AST/NestedNameSpecifier.cpp
+++ b/clang/lib/AST/NestedNameSpecifier.cpp
@@ -316,7 +316,10 @@ void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
TemplateName::Qualified::None);
// Print the template argument list.
- printTemplateArgumentList(OS, SpecType->template_arguments(),
+ printTemplateArgumentList(OS,
+ SpecType->isCanonicalUnqualified()
+ ? SpecType->getConvertedArguments()
+ : SpecType->getSpecifiedArguments(),
InnerPolicy);
} else if (const auto *DepSpecType =
dyn_cast<DependentTemplateSpecializationType>(T)) {
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 4c428cce32475..bfcc20f5567c9 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -1177,8 +1177,8 @@ class ODRTypeVisitor : public TypeVisitor<ODRTypeVisitor> {
void VisitEnumType(const EnumType *T) { VisitTagType(T); }
void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
- ID.AddInteger(T->template_arguments().size());
- for (const auto &TA : T->template_arguments()) {
+ ID.AddInteger(T->getSpecifiedArguments().size());
+ for (const auto &TA : T->getSpecifiedArguments()) {
Hash.AddTemplateArgument(TA);
}
Hash.AddTemplateName(T->getTemplateName());
diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp
index 3c814b777f8ab..cb1eee8a4e554 100644
--- a/clang/lib/AST/QualTypeNames.cpp
+++ b/clang/lib/AST/QualTypeNames.cpp
@@ -128,7 +128,7 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
SmallVector<TemplateArgument, 4> FQArgs;
// Cheap to copy and potentially modified by
// getFullyQualifedTemplateArgument.
- for (TemplateArgument Arg : TST->template_arguments()) {
+ for (TemplateArgument Arg : TST->getSpecifiedArguments()) {
MightHaveChanged |= getFullyQualifiedTemplateArgument(
Ctx, Arg, WithGlobalNsPrefix);
FQArgs.push_back(Arg);
@@ -138,7 +138,8 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
// allocate new type in the AST.
if (MightHaveChanged) {
QualType QT = Ctx.getTemplateSpecializationType(
- TST->getTemplateName(), FQArgs,
+ TST->getTemplateName(), FQArgs, TST->getConvertedArguments(),
+ /*CanonicalConvertedArgs=*/std::nullopt,
TST->getCanonicalTypeInternal());
// getTemplateSpecializationType returns a fully qualified
// version of the specialization itself, so no need to qualify
@@ -170,7 +171,8 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
if (MightHaveChanged) {
TemplateName TN(TSTDecl->getSpecializedTemplate());
QualType QT = Ctx.getTemplateSpecializationType(
- TN, FQArgs,
+ TN, FQArgs, FQArgs,
+ /*CanonicalConvertedArgs=*/std::nullopt,
TSTRecord->getCanonicalTypeInternal());
// getTemplateSpecializationType returns a fully qualified
// version of the specialization itself, so no need to qualify
diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index 0eef8f305fcb3..d0bb04cdf589d 100644
--- a/clang/lib/AST/TemplateBase.cpp
+++ b/clang/lib/AST/TemplateBase.cpp
@@ -381,21 +381,28 @@ QualType TemplateArgument::getNonTypeTemplateArgumentType() const {
}
void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
- const ASTContext &Context) const {
+ const ASTContext &Context,
+ bool Canonical) const {
ID.AddInteger(getKind());
switch (getKind()) {
case Null:
break;
case Type:
+ assert(!Canonical || getAsType().isCanonical());
getAsType().Profile(ID);
break;
case NullPtr:
+ assert(!Canonical || getNullPtrType().isCanonical());
getNullPtrType().Profile(ID);
break;
case Declaration:
+ if (Canonical) {
+ assert(getParamTypeForDecl().isCanonical());
+ assert(getAsDecl()->isCanonicalDecl());
+ }
getParamTypeForDecl().Profile(ID);
ID.AddPointer(getAsDecl());
break;
@@ -404,27 +411,33 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
ID.AddInteger(TemplateArg.NumExpansions);
[[fallthrough]];
case Template:
+ if (Canonical) {
+ TemplateName Name = TemplateName::getFromVoidPointer(TemplateArg.Name);
+ assert(Context.getCanonicalTemplateName(Name) == Name);
+ }
ID.AddPointer(TemplateArg.Name);
break;
case Integral:
+ assert(!Canonical || getIntegralType().isCanonical());
getIntegralType().Profile(ID);
getAsIntegral().Profile(ID);
break;
case StructuralValue:
+ assert(!Canonical || getStructuralValueType().isCanonical());
getStructuralValueType().Profile(ID);
getAsStructuralValue().Profile(ID);
break;
case Expression:
- getAsExpr()->Profile(ID, Context, true);
+ getAsExpr()->Profile(ID, Context, Canonical);
break;
case Pack:
ID.AddInteger(Args.NumArgs);
for (unsigned I = 0; I != Args.NumArgs; ++I)
- Args.Args[I].Profile(ID, Context);
+ Args.Args[I].Profile(ID, Context, Canonical);
}
}
diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp
index 9e0a7dc2b8cdc..a6a8456185244 100644
--- a/clang/lib/AST/TemplateName.cpp
+++ b/clang/lib/AST/TemplateName.cpp
@@ -54,7 +54,7 @@ void DeducedTemplateStorage::Profile(llvm::FoldingSetNodeID &ID,
ID.AddInteger(DefArgs.StartPos);
ID.AddInteger(DefArgs.Args.size());
for (const TemplateArgument &Arg : DefArgs.Args)
- Arg.Profile(ID, Context);
+ Arg.Profile(ID, Context, /*Canonical=*/false);
}
TemplateArgument
@@ -116,7 +116,7 @@ void SubstTemplateTemplateParmPackStorage::Profile(
llvm::FoldingSetNodeID &ID, ASTContext &Context,
const TemplateArgument &ArgPack, Decl *AssociatedDecl, unsigned Index,
bool Final) {
- ArgPack.Profile(ID, Context);
+ ArgPack.Profile(ID, Context, /*Canonical=*/false);
ID.AddPointer(AssociatedDecl);
ID.AddInteger(Index);
ID.AddBoolean(Final);
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 08798219c0b83..8486ffcfb4fe9 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -1937,6 +1937,17 @@ TagDecl *Type::getAsTagDecl() const {
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 {
const Type *Cur = this;
while (const auto *AT = Cur->getAs<AttributedType>()) {
@@ -3289,18 +3300,16 @@ DependentTemplateSpecializationType::DependentTemplateSpecializationType(
}
}
-void
-DependentTemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
- const ASTContext &Context,
- ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *Qualifier,
- const IdentifierInfo *Name,
- ArrayRef<TemplateArgument> Args) {
+void DependentTemplateSpecializationType::Profile(
+ llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ ElaboratedTypeKeyword Keyword, NestedNameSpecifier *Qualifier,
+ const IdentifierInfo *Name, ArrayRef<TemplateArgument> Args,
+ bool Canonical) {
ID.AddInteger(llvm::to_underlying(Keyword));
ID.AddPointer(Qualifier);
ID.AddPointer(Name);
for (const TemplateArgument &Arg : Args)
- Arg.Profile(ID, Context);
+ Arg.Profile(ID, Context, Canonical);
}
bool Type::isElaboratedTypeSpecifier() const {
@@ -4366,17 +4375,20 @@ bool TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
}
TemplateSpecializationType::TemplateSpecializationType(
- TemplateName T, ArrayRef<TemplateArgument> Args, QualType Canon,
- QualType AliasedType)
- : Type(TemplateSpecialization, Canon.isNull() ? QualType(this, 0) : Canon,
- (Canon.isNull()
+ TemplateName T, bool IsAlias, ArrayRef<TemplateArgument> SpecifiedArgs,
+ ArrayRef<TemplateArgument> ConvertedArgs, QualType Underlying)
+ : Type(TemplateSpecialization,
+ Underlying.isNull() ? QualType(this, 0)
+ : Underlying.getCanonicalType(),
+ (Underlying.isNull()
? TypeDependence::DependentInstantiation
- : toSemanticDependence(Canon->getDependence())) |
+ : toSemanticDependence(Underlying->getDependence())) |
(toTypeDependence(T.getDependence()) &
TypeDependence::UnexpandedPack)),
Template(T) {
- TemplateSpecializationTypeBits.NumArgs = Args.size();
- TemplateSpecializationTypeBits.TypeAlias = !AliasedType.isNull();
+ TemplateSpecializationTypeBits.NumSpecifiedArgs = SpecifiedArgs.size();
+ TemplateSpecializationTypeBits.NumConvertedArgs = ConvertedArgs.size();
+ TemplateSpecializationTypeBits.TypeAlias = IsAlias;
assert(!T.getAsDependentTemplateName() &&
"Use DependentTemplateSpecializationType for dependent template-name");
@@ -4388,51 +4400,70 @@ TemplateSpecializationType::TemplateSpecializationType(
T.getKind() == TemplateName::DeducedTemplate) &&
"Unexpected template name for TemplateSpecializationType");
- auto *TemplateArgs = reinterpret_cast<TemplateArgument *>(this + 1);
- for (const TemplateArgument &Arg : Args) {
- // Update instantiation-dependent, variably-modified, and error bits.
- // If the canonical type exists and is non-dependent, the template
- // specialization type can be non-dependent even if one of the type
- // arguments is. Given:
- // template<typename T> using U = int;
- // U<T> is always non-dependent, irrespective of the type T.
- // However, U<Ts> contains an unexpanded parameter pack, even though
- // its expansion (and thus its desugared type) doesn't.
- addDependence(toTypeDependence(Arg.getDependence()) &
- ~TypeDependence::Dependent);
- if (Arg.getKind() == TemplateArgument::Type)
- addDependence(Arg.getAsType()->getDependence() &
- TypeDependence::VariablyModified);
- new (TemplateArgs++) TemplateArgument(Arg);
- }
+ auto initArgs = [this](ArrayRef<TemplateArgument> Out,
+ ArrayRef<TemplateArgument> In) {
+ auto *Args = const_cast<TemplateArgument *>(Out.data());
+ for (const TemplateArgument &Arg : In) {
+ // Update instantiation-dependent, variably-modified, and error bits.
+ // If the canonical type exists and is non-dependent, the template
+ // specialization type can be non-dependent even if one of the type
+ // arguments is. Given:
+ // template<typename T> using U = int;
+ // U<T> is always non-dependent, irrespective of the type T.
+ // However, U<Ts> contains an unexpanded parameter pack, even though
+ // its expansion (and thus its desugared type) doesn't.
+ addDependence(toTypeDependence(Arg.getDependence()) &
+ ~TypeDependence::Dependent);
+ if (Arg.getKind() == TemplateArgument::Type)
+ 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.
- if (isTypeAlias()) {
- auto *Begin = reinterpret_cast<TemplateArgument *>(this + 1);
- *reinterpret_cast<QualType *>(Begin + Args.size()) = AliasedType;
- }
+ if (IsAlias)
+ *reinterpret_cast<QualType *>(const_cast<TemplateArgument *>(
+ getConvertedArguments().end())) = Underlying;
}
QualType TemplateSpecializationType::getAliasedType() const {
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,
const ASTContext &Ctx) {
- Profile(ID, Template, template_arguments(), Ctx);
- if (isTypeAlias())
- getAliasedType().Profile(ID);
+ Profile(ID, Template, getSpecifiedArguments(), getConvertedArguments(),
+ isSugared() ? desugar() : QualType(), Ctx, isCanonicalUnqualified());
}
-void
-TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
- TemplateName T,
- ArrayRef<TemplateArgument> Args,
- const ASTContext &Context) {
+void TemplateSpecializationType::Profile(
+ llvm::FoldingSetNodeID &ID, TemplateName T,
+ ArrayRef<TemplateArgument> SpecifiedArgs,
+ ArrayRef<TemplateArgument> ConvertedArgs, QualType Underlying,
+ const ASTContext &Context, bool Canonical) {
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
@@ -5242,20 +5273,21 @@ AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
}
void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
- QualType Deduced, AutoTypeKeyword Keyword,
- bool IsDependent, ConceptDecl *CD,
- ArrayRef<TemplateArgument> Arguments) {
+ QualType Deduced, AutoTypeKeyword Keyword,
+ bool IsDependent, ConceptDecl *CD,
+ ArrayRef<TemplateArgument> Arguments, bool Canonical) {
ID.AddPointer(Deduced.getAsOpaquePtr());
ID.AddInteger((unsigned)Keyword);
ID.AddBoolean(IsDependent);
ID.AddPointer(CD);
for (const TemplateArgument &Arg : Arguments)
- Arg.Profile(ID, Context);
+ Arg.Profile(ID, Context, Canonical);
}
void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(),
- getTypeConstraintConcept(), getTypeConstraintArguments());
+ getTypeConstraintConcept(), getTypeConstraintArguments(),
+ isCanonicalUnqualified());
}
FunctionEffect::Kind FunctionEffect::oppositeKind() const {
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 3982ca3b50604..be0adcdc54945 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1669,7 +1669,10 @@ void TypePrinter::printTemplateId(const TemplateSpecializationType *T,
DefaultTemplateArgsPolicyRAII TemplateArgs(Policy);
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);
}
@@ -2299,7 +2302,7 @@ static bool isSubstitutedType(ASTContext &Ctx, QualType T, QualType Pattern,
ArrayRef<TemplateArgument> TemplateArgs;
if (auto *TTST = T->getAs<TemplateSpecializationType>()) {
Template = TTST->getTemplateName();
- TemplateArgs = TTST->template_arguments();
+ TemplateArgs = TTST->getConvertedArguments();
} else if (auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
T->getAsCXXRecordDecl())) {
Template = TemplateName(CTSD->getSpecializedTemplate());
@@ -2311,11 +2314,12 @@ static bool isSubstitutedType(ASTContext &Ctx, QualType T, QualType Pattern,
if (!isSubstitutedTemplateArgument(Ctx, Template, PTST->getTemplateName(),
Args, Depth))
return false;
- if (TemplateArgs.size() != PTST->template_arguments().size())
+ ArrayRef<TemplateArgument> PArgs = PTST->getConvertedArguments();
+ if (TemplateArgs.size() != PArgs.size())
return false;
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
- if (!isSubstitutedTemplateArgument(
- Ctx, TemplateArgs[I], PTST->template_arguments()[I], Args, Depth))
+ if (!isSubstitutedTemplateArgument(Ctx, TemplateArgs[I], PArgs[I], Args,
+ Depth))
return false;
return true;
}
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index dcccbc0835d95..509146d53381c 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -1391,7 +1391,7 @@ GetTemplateArgs(const TemplateDecl *TD, const TemplateSpecializationType *Ty) {
// doesn't know the value of any defaulted args, so collect those now
// too.
SmallVector<TemplateArgument> SpecArgs;
- ArrayRef SubstArgs = Ty->template_arguments();
+ ArrayRef SubstArgs = Ty->getSpecifiedArguments();
for (const NamedDecl *Param : TD->getTemplateParameters()->asArray()) {
// If Param is a parameter pack, pack the remaining arguments.
if (Param->isParameterPack()) {
@@ -1483,7 +1483,7 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
return AliasTy;
}
- printTemplateArgumentList(OS, Ty->template_arguments(), PP,
+ printTemplateArgumentList(OS, Ty->getSpecifiedArguments(), PP,
TD->getTemplateParameters());
return DBuilder.createTypedef(Src, OS.str(), getOrCreateFile(Loc),
getLineNumber(Loc),
diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp
index 66c03863293c2..8795ef89f749d 100644
--- a/clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -420,7 +420,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
.append(Str, DeclarationFragments::FragmentKind::TypeIdentifier, USR)
.append("<", DeclarationFragments::FragmentKind::Text)
.append(getFragmentsForTemplateArguments(
- TemplSpecTy->template_arguments(), Context, std::nullopt))
+ TemplSpecTy->getSpecifiedArguments(), Context, std::nullopt))
.append(">", DeclarationFragments::FragmentKind::Text);
}
diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp
index 0a5a1bcc74865..0465f25211d2e 100644
--- a/clang/lib/Index/USRGeneration.cpp
+++ b/clang/lib/Index/USRGeneration.cpp
@@ -935,8 +935,8 @@ void USRGenerator::VisitType(QualType T) {
= T->getAs<TemplateSpecializationType>()) {
Out << '>';
VisitTemplateName(Spec->getTemplateName());
- Out << Spec->template_arguments().size();
- for (const auto &Arg : Spec->template_arguments())
+ Out << Spec->getConvertedArguments().size();
+ for (const TemplateArgument &Arg : Spec->getConvertedArguments())
VisitTemplateArgument(Arg);
return;
}
diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp
index 7aecd2a73b539..082de1ca8b830 100644
--- a/clang/lib/Sema/HeuristicResolver.cpp
+++ b/clang/lib/Sema/HeuristicResolver.cpp
@@ -192,9 +192,9 @@ QualType HeuristicResolverImpl::getPointeeType(QualType T) {
auto *TST = T->getAs<TemplateSpecializationType>();
if (!TST)
return QualType();
- if (TST->template_arguments().size() == 0)
+ if (TST->getSpecifiedArguments().size() == 0)
return QualType();
- const TemplateArgument &FirstArg = TST->template_arguments()[0];
+ const TemplateArgument &FirstArg = TST->getSpecifiedArguments()[0];
if (FirstArg.getKind() != TemplateArgument::Type)
return QualType();
return FirstArg.getAsType();
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index f04f7f9929442..02cd699addd75 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -98,7 +98,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
if (L != TemplateParamLists.end()) {
void *Pos = nullptr;
PartialSpec = ClassTemplate->findPartialSpecialization(
- SpecType->template_arguments(), *L, Pos);
+ SpecType->getConvertedArguments(), *L, Pos);
}
} else {
PartialSpec = ClassTemplate->findPartialSpecialization(ContextType);
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 2003701b65654..3835f2bde1741 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -4911,9 +4911,10 @@ static const FunctionProtoType *TryDeconstructFunctionLike(QualType T) {
// Note we only handle the sugared types, they closely match what users wrote.
// We explicitly choose to not handle ClassTemplateSpecializationDecl.
if (auto *Specialization = T->getAs<TemplateSpecializationType>()) {
- if (Specialization->template_arguments().size() != 1)
+ if (Specialization->getSpecifiedArguments().size() != 1)
return nullptr;
- const TemplateArgument &Argument = Specialization->template_arguments()[0];
+ const TemplateArgument &Argument =
+ Specialization->getSpecifiedArguments()[0];
if (Argument.getKind() != TemplateArgument::Type)
return nullptr;
return Argument.getAsType()->getAs<FunctionProtoType>();
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 57dc4154a537f..dc1c71ad7226c 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -412,7 +412,8 @@ DiagRecursiveConstraintEval(Sema &S, llvm::FoldingSetNodeID &ID,
E->Profile(ID, S.Context, /*Canonical=*/true);
for (const auto &List : MLTAL)
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
// times where a constraint-expression check can cause us to need to evaluate
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 478e92f7ffa01..c90ef04bbbe0a 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -12102,7 +12102,7 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) {
if (TST) {
Template = dyn_cast_or_null<ClassTemplateDecl>(
TST->getTemplateName().getAsTemplateDecl());
- Arguments = TST->template_arguments().begin();
+ Arguments = TST->getConvertedArguments().begin();
}
}
if (!Template)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index bb86b087980aa..8dbaae6004f20 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -21056,8 +21056,10 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
Diag(Temp->getLocation(), diag::note_referenced_type_template)
<< IsTypeAliasTemplateDecl;
- QualType TST =
- Context.getTemplateSpecializationType(TN, ULE->template_arguments());
+ QualType TST = Context.getTemplateSpecializationType(
+ TN, ULE->template_arguments(),
+ /*SugaredConvertedArgs=*/ArrayRef<TemplateArgument>{},
+ /*CanonicalConvertedArgs=*/{});
QualType ET =
Context.getElaboratedType(ElaboratedTypeKeyword::None, NNS, TST);
return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {},
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index be81b6a46b2c0..7fe38402300a9 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -3231,11 +3231,11 @@ static QualType builtinCommonTypeImpl(Sema &S, TemplateName BaseTemplate,
}
}
-static QualType
-checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
- ArrayRef<TemplateArgument> Converted,
- SourceLocation TemplateLoc,
- TemplateArgumentListInfo &TemplateArgs) {
+static QualType checkBuiltinTemplateIdType(
+ Sema &SemaRef, TemplateName Name, BuiltinTemplateDecl *BTD,
+ ArrayRef<TemplateArgument> SugaredConverted,
+ ArrayRef<TemplateArgument> CanonicalConverted, SourceLocation TemplateLoc,
+ TemplateArgumentListInfo &TemplateArgs) {
ASTContext &Context = SemaRef.getASTContext();
switch (BTD->getBuiltinTemplateKind()) {
@@ -3243,7 +3243,7 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
// Specializations of __make_integer_seq<S, T, N> are treated like
// S<T, 0, ..., N-1>.
- QualType OrigType = Converted[1].getAsType();
+ QualType OrigType = SugaredConverted[1].getAsType();
// C++14 [inteseq.intseq]p1:
// T shall be an integer type.
if (!OrigType->isDependentType() && !OrigType->isIntegralType(Context)) {
@@ -3252,10 +3252,11 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
return QualType();
}
- TemplateArgument NumArgsArg = Converted[2];
+ TemplateArgument NumArgsArg = SugaredConverted[2];
if (NumArgsArg.isDependent())
- return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
- Converted);
+ return SemaRef.Context.getTemplateSpecializationType(
+ TemplateName(BTD), TemplateArgs.arguments(), SugaredConverted,
+ CanonicalConverted);
TemplateArgumentListInfo SyntheticTemplateArgs;
// The type argument, wrapped in substitution sugar, gets reused as the
@@ -3283,21 +3284,26 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
// The first template argument will be reused as the template decl that
// our synthetic template arguments will be applied to.
- return SemaRef.CheckTemplateIdType(Converted[0].getAsTemplate(),
- TemplateLoc, SyntheticTemplateArgs);
+ QualType Result =
+ SemaRef.CheckTemplateIdType(SugaredConverted[0].getAsTemplate(),
+ TemplateLoc, SyntheticTemplateArgs);
+ return SemaRef.Context.getTemplateSpecializationType(
+ Name, TemplateArgs.arguments(), SugaredConverted, CanonicalConverted,
+ Result);
}
case BTK__type_pack_element: {
// Specializations of
// __type_pack_element<Index, T_1, ..., T_N>
// are treated like T_Index.
- assert(Converted.size() == 2 &&
- "__type_pack_element should be given an index and a parameter pack");
+ assert(SugaredConverted.size() == 2 &&
+ "__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())
- return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
- Converted);
+ return SemaRef.Context.getTemplateSpecializationType(
+ TemplateName(BTD), TemplateArgs.arguments(), SugaredConverted,
+ CanonicalConverted);
llvm::APSInt Index = IndexArg.getAsIntegral();
assert(Index >= 0 && "the index used with __type_pack_element should be of "
@@ -3311,19 +3317,24 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
// We simply return the type at index `Index`.
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: {
- assert(Converted.size() == 4);
- if (llvm::any_of(Converted, [](auto &C) { return C.isDependent(); }))
- return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
- Converted);
-
- TemplateName BaseTemplate = Converted[0].getAsTemplate();
- TemplateName HasTypeMember = Converted[1].getAsTemplate();
- QualType HasNoTypeMember = Converted[2].getAsType();
- ArrayRef<TemplateArgument> Ts = Converted[3].getPackAsArray();
+ assert(CanonicalConverted.size() == 4);
+ if (llvm::any_of(CanonicalConverted,
+ [](auto &C) { return C.isDependent(); }))
+ return Context.getTemplateSpecializationType(
+ TemplateName(BTD), TemplateArgs.arguments(), SugaredConverted,
+ CanonicalConverted);
+
+ TemplateName BaseTemplate = SugaredConverted[0].getAsTemplate();
+ TemplateName HasTypeMember = SugaredConverted[1].getAsTemplate();
+ QualType HasNoTypeMember = SugaredConverted[2].getAsType();
+ ArrayRef<TemplateArgument> Ts = SugaredConverted[3].getPackAsArray();
+ QualType Result = HasNoTypeMember;
if (auto CT = builtinCommonTypeImpl(SemaRef, BaseTemplate, TemplateLoc, Ts);
!CT.isNull()) {
TemplateArgumentListInfo TAs;
@@ -3331,9 +3342,11 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
TemplateArgument(CT), SemaRef.Context.getTrivialTypeSourceInfo(
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!");
@@ -3495,20 +3508,19 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
resolveAssumedTemplateNameAsType(/*Scope=*/nullptr, Name, TemplateLoc))
return QualType();
- auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs();
-
- if (!Template || isa<FunctionTemplateDecl>(Template) ||
- isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) {
- // We might have a substituted template template parameter pack. If so,
- // build a template specialization type for it.
- if (Name.getAsSubstTemplateTemplateParmPack())
- return Context.getTemplateSpecializationType(Name,
- TemplateArgs.arguments());
-
- Diag(TemplateLoc, diag::err_template_id_not_a_type)
- << Name;
- NoteAllFoundTemplates(Name);
- return QualType();
+ TemplateDecl *Template;
+ DefaultArguments DefaultArgs;
+ if (const SubstTemplateTemplateParmPackStorage *S =
+ Name.getAsSubstTemplateTemplateParmPack()) {
+ Template = S->getParameterPack();
+ } else {
+ std::tie(Template, DefaultArgs) = Name.getTemplateDeclAndDefaultArgs();
+ if (!Template || isa<FunctionTemplateDecl>(Template) ||
+ isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) {
+ Diag(TemplateLoc, diag::err_template_id_not_a_type) << Name;
+ NoteAllFoundTemplates(Name);
+ return QualType();
+ }
}
// Check that the template argument list is well-formed for this
@@ -3522,8 +3534,11 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
QualType CanonType;
- if (TypeAliasTemplateDecl *AliasTemplate =
- dyn_cast<TypeAliasTemplateDecl>(Template)) {
+ if (isa<TemplateTemplateParmDecl>(Template)) {
+ // We might have a substituted template template parameter pack. If so,
+ // build a template specialization type for it.
+ } else if (TypeAliasTemplateDecl *AliasTemplate =
+ dyn_cast<TypeAliasTemplateDecl>(Template)) {
// Find the canonical type for this type alias template specialization.
TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl();
@@ -3598,8 +3613,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
return QualType();
}
} else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) {
- CanonType = checkBuiltinTemplateIdType(*this, BTD, CTAI.SugaredConverted,
- TemplateLoc, TemplateArgs);
+ return checkBuiltinTemplateIdType(*this, Name, BTD, CTAI.SugaredConverted,
+ CTAI.CanonicalConverted, TemplateLoc,
+ TemplateArgs);
} else if (Name.isDependent() ||
TemplateSpecializationType::anyDependentTemplateArguments(
TemplateArgs, CTAI.CanonicalConverted)) {
@@ -3610,8 +3626,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// A<T, T> have identical types when A is declared as:
//
// template<typename T, typename U = T> struct A;
- CanonType = Context.getCanonicalTemplateSpecializationType(
- Name, CTAI.CanonicalConverted);
+ CanonType = Context.getTemplateSpecializationType(
+ Context.getCanonicalTemplateName(Name), ArrayRef<TemplateArgument>(),
+ std::nullopt, CTAI.CanonicalConverted);
// This might work out to be a current instantiation, in which
// case the canonical type needs to be the InjectedClassNameType.
@@ -3697,8 +3714,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// Build the fully-sugared type for this class template
// specialization, which refers back to the class template
// specialization we created or found.
- return Context.getTemplateSpecializationType(Name, TemplateArgs.arguments(),
- CanonType);
+ return Context.getTemplateSpecializationType(
+ Name, TemplateArgs.arguments(), CTAI.SugaredConverted,
+ CTAI.CanonicalConverted, CanonType);
}
void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName,
@@ -8490,17 +8508,35 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
isPartialSpecialization))
return true;
- // The canonical type
QualType CanonType;
+ if (!isPartialSpecialization) {
+ // Create a new class template specialization declaration node for
+ // this explicit specialization or friend declaration.
+ Specialization = ClassTemplateSpecializationDecl::Create(
+ Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
+ ClassTemplate, CTAI.CanonicalConverted, CTAI.StrictPackMatch, PrevDecl);
+ Specialization->setTemplateArgsAsWritten(TemplateArgs);
+ SetNestedNameSpecifier(*this, Specialization, SS);
+ if (TemplateParameterLists.size() > 0) {
+ Specialization->setTemplateParameterListsInfo(Context,
+ TemplateParameterLists);
+ }
+
+ if (!PrevDecl)
+ ClassTemplate->AddSpecialization(Specialization, InsertPos);
+
+ if (!CurContext->isDependentContext())
+ CanonType = Context.getTypeDeclType(Specialization);
+ }
+
+ TypeSourceInfo *WrittenTy = Context.getTemplateSpecializationTypeInfo(
+ Name, TemplateNameLoc, TemplateArgs, CTAI.SugaredConverted,
+ CTAI.CanonicalConverted, CanonType);
+
if (isPartialSpecialization) {
- // Build the canonical type that describes the converted template
- // arguments of the class template partial specialization.
- TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
- CanonType = Context.getTemplateSpecializationType(CanonTemplate,
- CTAI.CanonicalConverted);
-
- if (Context.hasSameType(CanonType,
- ClassTemplate->getInjectedClassNameSpecialization()) &&
+ if (Context.hasSameType(
+ WrittenTy->getType(),
+ ClassTemplate->getInjectedClassNameSpecialization()) &&
(!Context.getLangOpts().CPlusPlus20 ||
!TemplateParams->hasAssociatedConstraints())) {
// C++ [temp.class.spec]p9b3:
@@ -8527,7 +8563,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
ClassTemplatePartialSpecializationDecl *Partial =
ClassTemplatePartialSpecializationDecl::Create(
Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams,
- ClassTemplate, CTAI.CanonicalConverted, CanonType, PrevPartial);
+ ClassTemplate, CTAI.CanonicalConverted, WrittenTy->getType(),
+ PrevPartial);
Partial->setTemplateArgsAsWritten(TemplateArgs);
SetNestedNameSpecifier(*this, Partial, SS);
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
@@ -8545,29 +8582,6 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
PrevPartial->setMemberSpecialization();
CheckTemplatePartialSpecialization(Partial);
- } else {
- // Create a new class template specialization declaration node for
- // this explicit specialization or friend declaration.
- Specialization = ClassTemplateSpecializationDecl::Create(
- Context, Kind, DC, KWLoc, TemplateNameLoc, ClassTemplate,
- CTAI.CanonicalConverted, CTAI.StrictPackMatch, PrevDecl);
- Specialization->setTemplateArgsAsWritten(TemplateArgs);
- SetNestedNameSpecifier(*this, Specialization, SS);
- if (TemplateParameterLists.size() > 0) {
- Specialization->setTemplateParameterListsInfo(Context,
- TemplateParameterLists);
- }
-
- if (!PrevDecl)
- ClassTemplate->AddSpecialization(Specialization, InsertPos);
-
- if (CurContext->isDependentContext()) {
- TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
- CanonType = Context.getTemplateSpecializationType(
- CanonTemplate, CTAI.CanonicalConverted);
- } else {
- CanonType = Context.getTypeDeclType(Specialization);
- }
}
// C++ [temp.expl.spec]p6:
@@ -8657,8 +8671,6 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// actually wrote the specialization, rather than formatting the
// name based on the "canonical" representation used to store the
// template arguments in the specialization.
- TypeSourceInfo *WrittenTy = Context.getTemplateSpecializationTypeInfo(
- Name, TemplateNameLoc, TemplateArgs, CanonType);
FriendDecl *Friend = FriendDecl::Create(Context, CurContext,
TemplateNameLoc,
WrittenTy,
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index c3bec6bdebbcf..c0dda828d4977 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -615,12 +615,15 @@ static TemplateDeductionResult DeduceTemplateArguments(
/// but it may still fail, later, for other reasons.
static const TemplateSpecializationType *getLastTemplateSpecType(QualType QT) {
+ const TemplateSpecializationType *LastTST = nullptr;
for (const Type *T = QT.getTypePtr(); /**/; /**/) {
const TemplateSpecializationType *TST =
T->getAs<TemplateSpecializationType>();
- assert(TST && "Expected a TemplateSpecializationType");
+ if (!TST)
+ return LastTST;
if (!TST->isSugared())
return TST;
+ LastTST = TST;
T = TST->desugar().getTypePtr();
}
}
@@ -643,87 +646,61 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
if (const auto *TD = TNP.getAsTemplateDecl(); TD && TD->isTypeAlias())
return TemplateDeductionResult::Success;
- // FIXME: To preserve sugar, the TST needs to carry sugared resolved
- // arguments.
- ArrayRef<TemplateArgument> PResolved =
- TP->getCanonicalTypeInternal()
- ->castAs<TemplateSpecializationType>()
- ->template_arguments();
+ ArrayRef<TemplateArgument> PResolved = TP->getConvertedArguments();
QualType UA = A;
- std::optional<NestedNameSpecifier *> NNS;
// Treat an injected-class-name as its underlying template-id.
- if (const auto *Elaborated = A->getAs<ElaboratedType>()) {
- NNS = Elaborated->getQualifier();
- } else if (const auto *Injected = A->getAs<InjectedClassNameType>()) {
+ if (const auto *Injected = A->getAs<InjectedClassNameType>())
UA = Injected->getInjectedSpecializationType();
- NNS = nullptr;
- }
-
- // Check whether the template argument is a dependent template-id.
- if (isa<TemplateSpecializationType>(UA.getCanonicalType())) {
- const TemplateSpecializationType *SA = ::getLastTemplateSpecType(UA);
- TemplateName TNA = SA->getTemplateName();
+ 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>(
+ A->getAsCXXRecordDecl())) {
+ if (TA) {
+ // This could be a type alias to a class template specialization type
+ // 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 (const auto *TD = TNA.getAsTemplateDecl(); TD && TD->isTypeAlias())
return TemplateDeductionResult::Success;
-
- // 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) {
+ } else {
Info.FirstArg = TemplateArgument(P);
Info.SecondArg = TemplateArgument(A);
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.
- if (auto Result = DeduceTemplateArguments(
- S, TemplateParams, TNP, TNA, Info,
- /*DefaultArguments=*/SA->getTemplateArgs().asArray(), PartialOrdering,
- Deduced, HasDeducedAnyParam);
+ if (auto Result =
+ DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info,
+ /*DefaultArguments=*/AResolved,
+ PartialOrdering, Deduced, HasDeducedAnyParam);
Result != TemplateDeductionResult::Success)
return Result;
// Perform template argument deduction for the template arguments.
- return DeduceTemplateArguments(S, TemplateParams, PResolved,
- SA->getTemplateArgs().asArray(), Info, Deduced,
- /*NumberOfArgumentsMustMatch=*/true,
- PartialOrdering, PackFold::ParameterToArgument,
- HasDeducedAnyParam);
+ return DeduceTemplateArguments(
+ S, TemplateParams, PResolved, AResolved, Info, Deduced,
+ /*NumberOfArgumentsMustMatch=*/true, PartialOrdering,
+ PackFold::ParameterToArgument, HasDeducedAnyParam);
}
static bool IsPossiblyOpaquelyQualifiedTypeInternal(const Type *T) {
@@ -5880,8 +5857,8 @@ static MoreSpecializedTrailingPackTieBreakerResult
getMoreSpecializedTrailingPackTieBreaker(
const TemplateSpecializationType *TST1,
const TemplateSpecializationType *TST2) {
- ArrayRef<TemplateArgument> As1 = TST1->template_arguments(),
- As2 = TST2->template_arguments();
+ ArrayRef<TemplateArgument> As1 = TST1->getConvertedArguments(),
+ As2 = TST2->getConvertedArguments();
const TemplateArgument &TA1 = As1.back(), &TA2 = As2.back();
bool IsPack = TA1.getKind() == TemplateArgument::Pack;
assert(IsPack == (TA2.getKind() == TemplateArgument::Pack));
@@ -6288,8 +6265,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
TemplateDeductionResult Result;
S.runWithSufficientStackSpace(Info.getLocation(), [&] {
Result = ::FinishTemplateArgumentDeduction(
- S, P2, /*IsPartialOrdering=*/true, TST1->template_arguments(), Deduced,
- Info);
+ S, P2, /*IsPartialOrdering=*/true, TST1->getConvertedArguments(),
+ Deduced, Info);
});
if (Result != TemplateDeductionResult::Success)
@@ -6333,8 +6310,10 @@ struct TemplateArgumentListAreEqual {
// because canonicalization can't do the right thing for dependent
// expressions.
llvm::FoldingSetNodeID IDA, IDB;
- Args1[I].Profile(IDA, Ctx);
- Args2[I].Profile(IDB, Ctx);
+ Ctx.getCanonicalTemplateArgument(Args1[I]).Profile(IDA, Ctx,
+ /*Canonical=*/true);
+ Ctx.getCanonicalTemplateArgument(Args2[I]).Profile(IDB, Ctx,
+ /*Canonical=*/true);
if (IDA != IDB)
return false;
}
@@ -6352,10 +6331,10 @@ struct TemplateArgumentListAreEqual {
// because canonicalization can't do the right thing for dependent
// expressions.
llvm::FoldingSetNodeID IDA, IDB;
- Args1[I].Profile(IDA, Ctx);
- // Unlike the specialization arguments, the injected arguments are not
- // always canonical.
- Ctx.getCanonicalTemplateArgument(Args2[I]).Profile(IDB, Ctx);
+ Ctx.getCanonicalTemplateArgument(Args1[I]).Profile(IDA, Ctx,
+ /*Canonical=*/true);
+ Ctx.getCanonicalTemplateArgument(Args2[I]).Profile(IDB, Ctx,
+ /*Canonical=*/true);
if (IDA != IDB)
return false;
}
@@ -6498,9 +6477,11 @@ Sema::getMoreSpecializedPartialSpecialization(
" the same template.");
TemplateName Name(PS1->getSpecializedTemplate());
QualType PT1 = Context.getTemplateSpecializationType(
- Name, PS1->getTemplateArgs().asArray());
+ Name, ArrayRef<TemplateArgument>(), std::nullopt,
+ PS1->getTemplateArgs().asArray());
QualType PT2 = Context.getTemplateSpecializationType(
- Name, PS2->getTemplateArgs().asArray());
+ Name, ArrayRef<TemplateArgument>(), std::nullopt,
+ PS2->getTemplateArgs().asArray());
TemplateDeductionInfo Info(Loc);
return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info);
@@ -6511,9 +6492,11 @@ bool Sema::isMoreSpecializedThanPrimary(
VarTemplateDecl *Primary = Spec->getSpecializedTemplate();
TemplateName Name(Primary);
QualType PrimaryT = Context.getTemplateSpecializationType(
- Name, Primary->getInjectedTemplateArgs(Context));
+ Name, ArrayRef<TemplateArgument>(),
+ Primary->getInjectedTemplateArgs(Context), std::nullopt);
QualType PartialT = Context.getTemplateSpecializationType(
- Name, Spec->getTemplateArgs().asArray());
+ Name, ArrayRef<TemplateArgument>(), std::nullopt,
+ Spec->getTemplateArgs().asArray());
VarTemplatePartialSpecializationDecl *MaybeSpec =
getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info);
@@ -6975,11 +6958,10 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
// 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
// non-deduced context.
- if (OnlyDeduced &&
- hasPackExpansionBeforeEnd(Spec->template_arguments()))
+ if (OnlyDeduced && hasPackExpansionBeforeEnd(Spec->getConvertedArguments()))
break;
- for (const auto &Arg : Spec->template_arguments())
+ for (const TemplateArgument &Arg : Spec->getConvertedArguments())
MarkUsedTemplateParameters(Ctx, Arg, OnlyDeduced, Depth, Used);
break;
}
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index ee89ee8594bc4..a56b8614dab22 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -995,7 +995,7 @@ getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) {
// template<typename T>
// using AliasFoo1 = Foo<T>; // a class/type alias template specialization
Template = TST->getTemplateName().getAsTemplateDecl();
- AliasRhsTemplateArgs = TST->template_arguments();
+ AliasRhsTemplateArgs = TST->getSpecifiedArguments();
} else if (const auto *RT = RhsType->getAs<RecordType>()) {
// Cases where template arguments in the RHS of the alias are not
// dependent. e.g.
@@ -1068,7 +1068,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
// performing deduction for rest of arguments to align with the C++
// standard.
SemaRef.DeduceTemplateArguments(
- F->getTemplateParameters(), FReturnType->template_arguments(),
+ F->getTemplateParameters(), FReturnType->getSpecifiedArguments(),
AliasRhsTemplateArgs, TDeduceInfo, DeduceResults,
/*NumberOfArgumentsMustMatch=*/false);
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index ad49d6f6cce89..c178b3f850120 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -345,7 +345,7 @@ Response HandleFunctionTemplateDecl(Sema &SemaRef,
while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) {
if (NNS->isInstantiationDependent()) {
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.
// For example,
// ```cpp
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 8aaaea0bcdd66..9c1eb3f4c88b5 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4783,17 +4783,18 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
ClassTemplate->findPartialSpecialization(CTAI.CanonicalConverted,
InstParams, InsertPos);
- // Build the canonical type that describes the converted template
- // arguments of the class template partial specialization.
- QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
- TemplateName(ClassTemplate), CTAI.CanonicalConverted);
+ // Build the type that describes the converted template arguments of the class
+ // template partial specialization.
+ TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo(
+ TemplateName(ClassTemplate), TemplArgInfo->getLAngleLoc(),
+ InstTemplateArgs, CTAI.SugaredConverted, CTAI.CanonicalConverted);
// Create the class template partial specialization declaration.
ClassTemplatePartialSpecializationDecl *InstPartialSpec =
ClassTemplatePartialSpecializationDecl::Create(
SemaRef.Context, PartialSpec->getTagKind(), Owner,
PartialSpec->getBeginLoc(), PartialSpec->getLocation(), InstParams,
- ClassTemplate, CTAI.CanonicalConverted, CanonType,
+ ClassTemplate, CTAI.CanonicalConverted, WrittenTy->getType(),
/*PrevDecl=*/nullptr);
InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs);
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 39717386b0d08..59cd7ffadfeb4 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1891,7 +1891,7 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
// A declarator that specifies the type "reference to cv void"
// is ill-formed.
if (T->isVoidType()) {
- Diag(Loc, diag::err_reference_to_void);
+ Diag(Loc, diag::err_reference_to_void) << T;
return QualType();
}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 71fc0f30845cb..4ee943ea5597e 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -7359,12 +7359,24 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
TemplateArgumentListInfo NewTemplateArgs;
NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc());
NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc());
- typedef TemplateArgumentLocContainerIterator<TemplateSpecializationTypeLoc>
- ArgIterator;
- if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0),
- ArgIterator(TL, TL.getNumArgs()),
- NewTemplateArgs))
- return QualType();
+
+ const auto *T = cast<TemplateSpecializationType>(TL.getType());
+ if (T->isCanonicalUnqualified()) {
+ ArrayRef<TemplateArgument> ConvertedArgs = T->getConvertedArguments();
+ using ArgIterator =
+ 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
// original template changed. If the template changed, and even if the
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 46a84bbfaaaef..bd77ad8aebfc5 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -7304,9 +7304,9 @@ void TypeLocReader::VisitTemplateSpecializationTypeLoc(
TL.setLAngleLoc(readSourceLocation());
TL.setRAngleLoc(readSourceLocation());
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
- TL.setArgLocInfo(i,
- Reader.readTemplateArgumentLocInfo(
- TL.getTypePtr()->template_arguments()[i].getKind()));
+ TL.setArgLocInfo(
+ i, Reader.readTemplateArgumentLocInfo(
+ TL.getTypePtr()->getSpecifiedArguments()[i].getKind()));
}
void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) {
diff --git a/clang/lib/Serialization/TemplateArgumentHasher.cpp b/clang/lib/Serialization/TemplateArgumentHasher.cpp
index 3c7177b83ba52..04c8652bfa04c 100644
--- a/clang/lib/Serialization/TemplateArgumentHasher.cpp
+++ b/clang/lib/Serialization/TemplateArgumentHasher.cpp
@@ -361,8 +361,8 @@ class TypeVisitorHelper : public TypeVisitor<TypeVisitorHelper> {
void VisitEnumType(const EnumType *T) { VisitTagType(T); }
void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
- Hash.AddInteger(T->template_arguments().size());
- for (const auto &TA : T->template_arguments()) {
+ Hash.AddInteger(T->getSpecifiedArguments().size());
+ for (const auto &TA : T->getSpecifiedArguments()) {
Hash.AddTemplateArgument(TA);
}
Hash.AddTemplateName(T->getTemplateName());
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp
index a026735bc107f..9a1bf303867a5 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp
@@ -95,7 +95,7 @@ getTemplateArgsFromVariant(const Type *VariantType) {
if (!TempSpecType)
return {};
- return TempSpecType->template_arguments();
+ return TempSpecType->getSpecifiedArguments();
}
static std::optional<QualType>
diff --git a/clang/test/AST/ast-dump-ctad-alias.cpp b/clang/test/AST/ast-dump-ctad-alias.cpp
index f39a4cee518ce..4b2a8210cc21c 100644
--- a/clang/test/AST/ast-dump-ctad-alias.cpp
+++ b/clang/test/AST/ast-dump-ctad-alias.cpp
@@ -191,12 +191,8 @@ void foo() {
// CHECK-NEXT: | | | | `-TemplateArgument pack '<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: | | | | |-name: 'GH124715::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: | | | | `-name: 'GH124715::Packs'
+// CHECK-NEXT: | | | | `-ClassTemplateDecl {{.*}} Packs
// CHECK-NEXT: | | | |-TemplateArgument {{.*}} type 'U':'type-parameter-0-2'
// CHECK-NEXT: | | | | `-TemplateTypeParmType {{.*}} 'U' dependent depth 0 index 2
// CHECK-NEXT: | | | | `-TemplateTypeParm {{.*}} 'U'
diff --git a/clang/test/CXX/class.derived/class.derived.general/p2.cpp b/clang/test/CXX/class.derived/class.derived.general/p2.cpp
index 888d9cd7a939d..1423eeabebf59 100644
--- a/clang/test/CXX/class.derived/class.derived.general/p2.cpp
+++ b/clang/test/CXX/class.derived/class.derived.general/p2.cpp
@@ -63,7 +63,7 @@ namespace CurrentInstantiation {
struct A0<T>::B5<U>::C3 : A0, B5 { };
template<typename T>
- struct A0<T*> { // expected-note 2{{definition of 'A0<type-parameter-0-0 *>' is not complete until the closing '}'}}
+ struct A0<T*> { // expected-note 2{{definition of 'A0<T *>' is not complete until the closing '}'}}
struct B0 : A0 { }; // expected-error {{base class has incomplete type}}
template<typename U>
diff --git a/clang/test/CXX/drs/cwg15xx.cpp b/clang/test/CXX/drs/cwg15xx.cpp
index 30ec63999ca28..b4788024bb75d 100644
--- a/clang/test/CXX/drs/cwg15xx.cpp
+++ b/clang/test/CXX/drs/cwg15xx.cpp
@@ -38,7 +38,7 @@ namespace cwg1512 { // cwg1512: 4
template<typename A, typename B, typename C> void composite_pointer_type_is_ord() {
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-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')}}
@@ -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>());
- // since-cxx11-error at -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 at -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>());
- // since-cxx11-error at -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 at -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>());
- // since-cxx11-error at -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 at -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>());
- // since-cxx11-error at -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 at -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*)
// 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
#if __cplusplus >= 201103L
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
struct X { typedef void type; };
@@ -639,7 +639,7 @@ namespace cwg1591 { //cwg1591. Deducing array bound and element type from initi
#if __cplusplus >= 201103L
template<class T, int N> int h(T const(&)[N]);
int X = h({1,2,3}); // T deduced to int, N deduced to 3
-
+
template<class T> int j(T const(&)[3]);
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);
int X1 = n({{1},{2},{3}},Aggr()); // OK, T is Aggr, N is 3
-
-
+
+
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 **f(const T (&a)[N][M]); // #cwg1591-f-2
-
+
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 ***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 {
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 *g(T (&&a)[N]); // #cwg1591-g-1
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} } });
@@ -687,7 +687,7 @@ namespace cwg1591 { //cwg1591. Deducing array bound and element type from initi
int **p22 = g({ {1,2}, {3, 4} });
int *p1 = g({1, 2, 3});
}
-
+
namespace check_arrays_of_init_list {
template<class T, int N> float *h(const std::initializer_list<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}});
}
namespace core_reflector_28543 {
-
+
template<class T, int N> int *i(T (&&)[N]); // #1
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
@@ -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> using Arr = T[];
-
+
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
void *pv1 = i({ {1, 2, 3}, {4, 5, 6} }); // ambiguous btw 3 & 4
- // since-cxx11-error at -1 {{call to 'i' is ambiguous}}
+ // since-cxx11-error at -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-1 {{candidate function [with T = int, N = 2]}}
char **pcc = i({ {1}, {2, 3} }); // OK #4
diff --git a/clang/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp b/clang/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp
index 871bdc2a58c7b..05295cc7b0c9f 100644
--- a/clang/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp
@@ -38,7 +38,7 @@ A<short>::C::B<int*> absip;
template<typename T, typename U>
struct Outer {
template<typename X, typename Y> struct Inner;
- template<typename Y> struct Inner<T, Y> {}; // expected-note{{previous declaration of class template partial specialization 'Inner<int, type-parameter-0-0>' is here}}
+ template<typename Y> struct Inner<T, Y> {}; // expected-note{{previous declaration of class template partial specialization 'Inner<int, Y>' is here}}
template<typename Y> struct Inner<U, Y> {}; // expected-error{{cannot be redeclared}}
};
@@ -80,7 +80,7 @@ namespace print_dependent_TemplateSpecializationType {
template <class T, class U> struct Foo {
template <unsigned long, class X, class Y> struct Bar;
template <class Y> struct Bar<0, T, Y> {};
- // expected-note-re at -1 {{previous declaration {{.*}} 'Bar<0, int, type-parameter-0-0>' is here}}
+ // expected-note-re at -1 {{previous declaration {{.*}} 'Bar<0, int, Y>' is here}}
template <class Y> struct Bar<0, U, Y> {};
// expected-error at -1 {{partial specialization 'Bar<0, int, Y>' cannot be redeclared}}
};
diff --git a/clang/test/CodeGen/preferred_name.cpp b/clang/test/CodeGen/preferred_name.cpp
index 9b3f532faf978..023245b0a4cb3 100644
--- a/clang/test/CodeGen/preferred_name.cpp
+++ b/clang/test/CodeGen/preferred_name.cpp
@@ -69,20 +69,16 @@ int main() {
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: ![[BAR_SHORT_TYPEDEF]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar<short>"
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_2:[0-9]+]])
+// LLDB: !DILocalVariable(name: "barChar", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_CHAR_TY:[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>"
-// LLDB: ![[BAR_CHAR_TY_2]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar<char>", file: ![[#]], line: [[#]], baseType: ![[BAR_CHAR_TY]])
-
return 0;
}
diff --git a/clang/test/SemaCXX/pr100095.cpp b/clang/test/SemaCXX/pr100095.cpp
index 15913fec9d5ae..f2a3b1f8b5ad2 100644
--- a/clang/test/SemaCXX/pr100095.cpp
+++ b/clang/test/SemaCXX/pr100095.cpp
@@ -1,5 +1,8 @@
// 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 Tuple {
diff --git a/clang/test/SemaCXX/references.cpp b/clang/test/SemaCXX/references.cpp
index 7ef3f43ff55ae..01ea50809dcb2 100644
--- a/clang/test/SemaCXX/references.cpp
+++ b/clang/test/SemaCXX/references.cpp
@@ -98,7 +98,7 @@ void test7(C& c) {
// C++ [dcl.ref]p1, C++ [dcl.ref]p4
void test8(int& const,// expected-error{{'const' qualifier may not be applied to a reference}}
-
+
void&, // expected-error{{cannot form a reference to 'void'}}
int& &) // expected-error{{type name declared as a reference to a reference}}
{
@@ -131,7 +131,7 @@ class string {
char *Data;
unsigned Length;
public:
- string();
+ string();
~string();
};
@@ -144,11 +144,11 @@ void test9() {
void test10() {
__attribute((vector_size(16))) typedef int vec4;
typedef __attribute__(( ext_vector_type(4) )) int ext_vec4;
-
+
vec4 v;
int &a = v[0]; // expected-error{{non-const reference cannot bind to vector element}}
const int &b = v[0];
-
+
ext_vec4 ev;
int &c = ev.x; // expected-error{{non-const reference cannot bind to vector element}}
const int &d = ev.x;
@@ -216,3 +216,15 @@ namespace PR45521 {
int *d;
const a &r = d;
}
+
+namespace with_sugar {
+ template <template <class> class TT, class T, class = T&> void f(TT<T>);
+ // expected-note at -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}}
+ }
+}
diff --git a/clang/test/SemaCXX/undefined-partial-specialization.cpp b/clang/test/SemaCXX/undefined-partial-specialization.cpp
index b07a513270fd6..0f776a6145fef 100644
--- a/clang/test/SemaCXX/undefined-partial-specialization.cpp
+++ b/clang/test/SemaCXX/undefined-partial-specialization.cpp
@@ -10,6 +10,6 @@ template <typename T>
class boo<T, true>;
template<typename T>
-void boo<T, true>::foo(){} // expected-error{{out-of-line definition of 'foo' from class 'boo<type-parameter-0-0, true>' without definition}}
+void boo<T, true>::foo(){} // expected-error{{out-of-line definition of 'foo' from class 'boo<T, true>' without definition}}
}
diff --git a/clang/test/SemaTemplate/cwg2398.cpp b/clang/test/SemaTemplate/cwg2398.cpp
index 06333c81a603e..1d27466907d64 100644
--- a/clang/test/SemaTemplate/cwg2398.cpp
+++ b/clang/test/SemaTemplate/cwg2398.cpp
@@ -130,16 +130,12 @@ namespace ttp_defaults {
template <template <class T1> class TT1> struct A {};
template <template <class T2> class TT2> void f(A<TT2>);
- // expected-note at -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>) {};
- // expected-note at -1 {{explicit instantiation candidate}}
template <class T5, class T6 = int> struct B;
template void f<B>(A<B>);
- // expected-error at -1 {{partial ordering for explicit instantiation of 'f' is ambiguous}}
} // namespace ttp_defaults
namespace ttp_only {
diff --git a/clang/test/SemaTemplate/make_integer_seq.cpp b/clang/test/SemaTemplate/make_integer_seq.cpp
index 71e34c5e0e7df..4f437976cf3cb 100644
--- a/clang/test/SemaTemplate/make_integer_seq.cpp
+++ b/clang/test/SemaTemplate/make_integer_seq.cpp
@@ -50,95 +50,64 @@ using test2 = B<int, 1>;
// CHECK-NEXT: |-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
// CHECK-NEXT: |-TemplateArgument expr '1'
-// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:64> 'int'
+// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'int'
// CHECK-NEXT: | |-value: Int 1
-// CHECK-NEXT: | `-SubstNonTypeTemplateParmExpr 0x{{[0-9A-Fa-f]+}} <col:64> 'int'
-// CHECK-NEXT: | |-NonTypeTemplateParmDecl 0x{{[0-9A-Fa-f]+}} <col:21, col:24> col:24 referenced 'B1' depth 0 index 1 B2
-// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:64> 'int' 1
+// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 1
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} 'A<int, 0>' sugar
// CHECK-NEXT: |-name: 'A' qualified
// CHECK-NEXT: | `-ClassTemplateDecl {{.+}} A
// CHECK-NEXT: |-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
// CHECK-NEXT: |-TemplateArgument expr '0'
-// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:64> 'int'
+// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'int'
// CHECK-NEXT: | |-value: Int 0
-// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:64> 'int' 0
+// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 0
// CHECK-NEXT: `-RecordType 0x{{[0-9A-Fa-f]+}} 'A<int, 0>'
// CHECK-NEXT: `-ClassTemplateSpecialization 0x{{[0-9A-Fa-f]+}} 'A'
template <template <class T, T...> class S, class T, int N> struct C {
using test3 = __make_integer_seq<S, T, N>;
-// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:43> col:9 test3 '__make_integer_seq<S, T, N>':'__make_integer_seq<template-parameter-0-0, type-parameter-0-1, N>'
+// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:43> col:9 test3 '__make_integer_seq<S, T, N>'
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<S, T, N>' sugar dependent
-// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<S, T, N>' sugar dependent alias
-// CHECK-NEXT: |-name: '__make_integer_seq' qualified
+// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<S, T, N>' dependent
+// CHECK-NEXT: |-name: '__make_integer_seq'
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq
// CHECK-NEXT: |-TemplateArgument template 'S'
// CHECK-NEXT: | | `-TemplateTemplateParmDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:11, col:42> col:42 depth 0 index 0 S
// CHECK-NEXT: |-TemplateArgument type 'T'
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'T' dependent depth 0 index 1
// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'T'
-// CHECK-NEXT: |-TemplateArgument expr 'N'
-// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent>
-// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
-// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<template-parameter-0-0, type-parameter-0-1, N>' dependent
-// CHECK-NEXT: |-name: '__make_integer_seq'
-// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq
-// CHECK-NEXT: |-TemplateArgument template 'template-parameter-0-0'
-// CHECK-NEXT: | `-TemplateTemplateParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> depth 0 index 0
-// CHECK-NEXT: |-TemplateArgument type 'type-parameter-0-1'
-// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1' dependent depth 0 index 1
-// CHECK-NEXT: `-TemplateArgument expr 'N'
-// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'T' <Dependent>
-// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
+// CHECK-NEXT: `-TemplateArgument expr 'N'
+// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent>
+// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
using test4 = __make_integer_seq<A, T, 1>;
-// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:43> col:9 test4 '__make_integer_seq<A, T, 1>':'__make_integer_seq<A, type-parameter-0-1, 1>'
+// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:43> col:9 test4 '__make_integer_seq<A, T, 1>'
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, T, 1>' sugar dependent
-// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, T, 1>' sugar dependent alias
-// CHECK-NEXT: |-name: '__make_integer_seq' qualified
+// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, T, 1>' dependent
+// CHECK-NEXT: |-name: '__make_integer_seq'
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq
// CHECK-NEXT: |-TemplateArgument template 'A'
// CHECK-NEXT: | `-ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:1, col:41> col:38 A
// CHECK-NEXT: |-TemplateArgument type 'T'
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'T' dependent depth 0 index 1
// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'T'
-// CHECK-NEXT: |-TemplateArgument expr '1'
-// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent>
-// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 1
-// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, type-parameter-0-1, 1>' dependent
-// CHECK-NEXT: |-name: '__make_integer_seq'
-// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq
-// CHECK-NEXT: |-TemplateArgument template 'A'
-// CHECK-NEXT: | `-ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:1, col:41> col:38 A
-// CHECK-NEXT: |-TemplateArgument type 'type-parameter-0-1'
-// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1' dependent depth 0 index 1
-// CHECK-NEXT: `-TemplateArgument expr '1'
-// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent>
-// CHECK-NEXT: `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 1
+// CHECK-NEXT: `-TemplateArgument expr '1'
+// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent>
+// CHECK-NEXT: `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 1
using test5 = __make_integer_seq<A, int, N>;
// CHECK: `-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:45> col:9 test5 '__make_integer_seq<A, int, N>'
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' sugar dependent
-// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' sugar dependent alias
-// CHECK-NEXT: |-name: '__make_integer_seq' qualified
+// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' dependent
+// CHECK-NEXT: |-name: '__make_integer_seq'
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq
// CHECK-NEXT: |-TemplateArgument template 'A'
// CHECK-NEXT: | `-ClassTemplateDecl 0x{{.+}} <line:{{.+}}:1, col:41> col:38 A
// CHECK-NEXT: |-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
-// CHECK-NEXT: |-TemplateArgument expr 'N'
-// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:44> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
-// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' dependent
-// CHECK-NEXT: |-name: '__make_integer_seq'
-// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __make_integer_seq
-// CHECK-NEXT: |-TemplateArgument template 'A'
-// CHECK-NEXT: | `-ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:1, col:41> col:38 A
-// CHECK-NEXT: |-TemplateArgument type 'int'
-// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
-// CHECK-NEXT: `-TemplateArgument expr 'N'
-// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:44> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
+// CHECK-NEXT: `-TemplateArgument expr 'N'
+// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:44> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
};
// expected-no-diagnostics
diff --git a/clang/test/SemaTemplate/type_pack_element.cpp b/clang/test/SemaTemplate/type_pack_element.cpp
index e08a4a6ee6c5a..bb02cab574087 100644
--- a/clang/test/SemaTemplate/type_pack_element.cpp
+++ b/clang/test/SemaTemplate/type_pack_element.cpp
@@ -17,73 +17,46 @@ using test1 = __type_pack_element<0, int>;
template<int N, class ...Ts> struct A {
using test2 = __type_pack_element<N, Ts...>;
-// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:45> col:9 test2 '__type_pack_element<N, Ts...>':'__type_pack_element<N, type-parameter-0-1...>'
+// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:45> col:9 test2 '__type_pack_element<N, Ts...>'
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, Ts...>' sugar dependent
-// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, Ts...>' sugar dependent alias
-// CHECK-NEXT: |-name: '__type_pack_element' qualified
+// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, Ts...>' 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 type 'Ts...'
-// CHECK-NEXT: | `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent
-// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack
-// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'Ts'
-// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, type-parameter-0-1...>' dependent
-// CHECK-NEXT: |-name: '__type_pack_element'
-// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element
-// CHECK-NEXT: |-TemplateArgument expr 'N'
-// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast>
-// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
-// CHECK-NEXT: `-TemplateArgument pack '<type-parameter-0-1...>'
-// CHECK-NEXT: `-TemplateArgument type 'type-parameter-0-1...'
-// CHECK-NEXT: `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1...' dependent
-// CHECK-NEXT: `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1' dependent contains_unexpanded_pack depth 0 index 1 pack
+// CHECK-NEXT: `-TemplateArgument type 'Ts...'
+// CHECK-NEXT: `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent
+// CHECK-NEXT: `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack
+// CHECK-NEXT: `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'Ts'
using test3 = __type_pack_element<0, Ts...>;
-// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:45> col:9 test3 '__type_pack_element<0, Ts...>':'__type_pack_element<0, type-parameter-0-1...>'
+// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:45> col:9 test3 '__type_pack_element<0, Ts...>'
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, Ts...>' sugar dependent
-// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, Ts...>' sugar dependent alias
-// CHECK-NEXT: |-name: '__type_pack_element' qualified
+// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, Ts...>' dependent
+// CHECK-NEXT: |-name: '__type_pack_element'
// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element
// CHECK-NEXT: |-TemplateArgument expr '0'
// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long'
// CHECK-NEXT: | |-value: Int 0
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast>
// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:37> 'int' 0
-// CHECK-NEXT: |-TemplateArgument type 'Ts...'
-// CHECK-NEXT: | `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent
-// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack
-// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'Ts'
-// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, type-parameter-0-1...>' dependent
-// CHECK-NEXT: |-name: '__type_pack_element'
-// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element
-// CHECK-NEXT: |-TemplateArgument integral '0UL'
-// CHECK-NEXT: `-TemplateArgument pack '<type-parameter-0-1...>'
-// CHECK-NEXT: `-TemplateArgument type 'type-parameter-0-1...'
-// CHECK-NEXT: `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1...' dependent
-// CHECK-NEXT: `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1' dependent contains_unexpanded_pack depth 0 index 1 pack
+// CHECK-NEXT: `-TemplateArgument type 'Ts...'
+// CHECK-NEXT: `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent
+// CHECK-NEXT: `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack
+// CHECK-NEXT: `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'Ts'
using test4 = __type_pack_element<N, int>;
// CHECK: `-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:3, col:43> col:9 test4 '__type_pack_element<N, int>'
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, int>' sugar dependent
-// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, int>' sugar dependent alias
-// CHECK-NEXT: |-name: '__type_pack_element' qualified
+// 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 type 'int'
-// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
-// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, int>' dependent
-// CHECK-NEXT: |-name: '__type_pack_element'
-// CHECK-NEXT: | `-BuiltinTemplateDecl {{.+}} __type_pack_element
-// CHECK-NEXT: |-TemplateArgument expr 'N'
-// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast>
-// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
-// CHECK-NEXT: `-TemplateArgument pack '<int>'
-// CHECK-NEXT: `-TemplateArgument type 'int'
-// CHECK-NEXT: `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
+// CHECK-NEXT: `-TemplateArgument type 'int'
+// CHECK-NEXT: `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
};
// expected-no-diagnostics
diff --git a/clang/tools/libclang/CXType.cpp b/clang/tools/libclang/CXType.cpp
index 2c9ef282b8abc..c94c2d3a32bf9 100644
--- a/clang/tools/libclang/CXType.cpp
+++ b/clang/tools/libclang/CXType.cpp
@@ -188,7 +188,7 @@ static std::optional<ArrayRef<TemplateArgument>>
GetTemplateArguments(QualType Type) {
assert(!Type.isNull());
if (const auto *Specialization = Type->getAs<TemplateSpecializationType>())
- return Specialization->template_arguments();
+ return Specialization->getSpecifiedArguments();
if (const auto *RecordDecl = Type->getAsCXXRecordDecl()) {
const auto *TemplateDecl =
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional_requires_destructible_object.verify.cpp b/libcxx/test/std/utilities/optional/optional.object/optional_requires_destructible_object.verify.cpp
index a96c3c648f939..7cfef471bc8e7 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional_requires_destructible_object.verify.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional_requires_destructible_object.verify.cpp
@@ -39,10 +39,10 @@ int main(int, char**)
optional<void()> opt4;
}
{
- // expected-error-re at optional:* {{static assertion failed{{.*}}instantiation of optional with a non-object type is undefined behavior}}
- // expected-error-re at optional:* {{static assertion failed{{.*}}instantiation of optional with a non-destructible type is ill-formed}}
- // expected-error at optional:* 1+ {{cannot form a reference to 'void'}}
- optional<const void> opt4;
+ // expected-error-re at optional:* {{static assertion failed{{.*}}instantiation of optional with a non-object type is undefined behavior}}
+ // expected-error-re at optional:* {{static assertion failed{{.*}}instantiation of optional with a non-destructible type is ill-formed}}
+ // expected-error at optional:* 1+ {{cannot form a reference to}}
+ optional<const void> opt4;
}
// FIXME these are garbage diagnostics that Clang should not produce
// expected-error at optional:* 0+ {{is not a base class}}
More information about the cfe-commits
mailing list