364 changes: 103 additions & 261 deletions clang/docs/LibASTMatchersReference.html

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,6 @@ Clang Frontend Potentially Breaking Changes
$ clang --target=<your target triple> -print-target-triple
<the normalized target triple>

- The ``hasTypeLoc`` AST matcher will no longer match a ``classTemplateSpecializationDecl``;
existing uses should switch to ``templateArgumentLoc`` or ``hasAnyTemplateArgumentLoc`` instead.

What's New in Clang |release|?
==============================
Some of the major new features and improvements to Clang are listed
Expand Down
220 changes: 127 additions & 93 deletions clang/include/clang/AST/DeclTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -1776,25 +1776,6 @@ class BuiltinTemplateDecl : public TemplateDecl {
BuiltinTemplateKind getBuiltinTemplateKind() const { return BTK; }
};

/// Provides information about an explicit instantiation of a variable or class
/// template.
struct ExplicitInstantiationInfo {
/// The template arguments as written..
const ASTTemplateArgumentListInfo *TemplateArgsAsWritten = nullptr;

/// The location of the extern keyword.
SourceLocation ExternKeywordLoc;

/// The location of the template keyword.
SourceLocation TemplateKeywordLoc;

ExplicitInstantiationInfo() = default;
};

using SpecializationOrInstantiationInfo =
llvm::PointerUnion<const ASTTemplateArgumentListInfo *,
ExplicitInstantiationInfo *>;

/// Represents a class template specialization, which refers to
/// a class template with a given set of template arguments.
///
Expand All @@ -1808,8 +1789,8 @@ using SpecializationOrInstantiationInfo =
/// template<>
/// class array<bool> { }; // class template specialization array<bool>
/// \endcode
class ClassTemplateSpecializationDecl : public CXXRecordDecl,
public llvm::FoldingSetNode {
class ClassTemplateSpecializationDecl
: public CXXRecordDecl, public llvm::FoldingSetNode {
/// Structure that stores information about a class template
/// specialization that was instantiated from a class template partial
/// specialization.
Expand All @@ -1827,9 +1808,23 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
llvm::PointerUnion<ClassTemplateDecl *, SpecializedPartialSpecialization *>
SpecializedTemplate;

/// Further info for explicit template specialization/instantiation.
struct ExplicitSpecializationInfo {
/// The type-as-written.
TypeSourceInfo *TypeAsWritten = nullptr;

/// The location of the extern keyword.
SourceLocation ExternLoc;

/// The location of the template keyword.
SourceLocation TemplateKeywordLoc;

ExplicitSpecializationInfo() = default;
};

/// Further info for explicit template specialization/instantiation.
/// Does not apply to implicit specializations.
SpecializationOrInstantiationInfo ExplicitInfo = nullptr;
ExplicitSpecializationInfo *ExplicitInfo = nullptr;

/// The template arguments used to describe this specialization.
const TemplateArgumentList *TemplateArgs;
Expand Down Expand Up @@ -2006,49 +2001,44 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
SpecializedTemplate = TemplDecl;
}

/// Retrieve the template argument list as written in the sources,
/// if any.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
if (auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>())
return Info->TemplateArgsAsWritten;
return ExplicitInfo.get<const ASTTemplateArgumentListInfo *>();
/// Sets the type of this specialization as it was written by
/// the user. This will be a class template specialization type.
void setTypeAsWritten(TypeSourceInfo *T) {
if (!ExplicitInfo)
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
ExplicitInfo->TypeAsWritten = T;
}

/// Set the template argument list as written in the sources.
void
setTemplateArgsAsWritten(const ASTTemplateArgumentListInfo *ArgsWritten) {
if (auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>())
Info->TemplateArgsAsWritten = ArgsWritten;
else
ExplicitInfo = ArgsWritten;
}

/// Set the template argument list as written in the sources.
void setTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgsInfo) {
setTemplateArgsAsWritten(
ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo));
/// Gets the type of this specialization as it was written by
/// the user, if it was so written.
TypeSourceInfo *getTypeAsWritten() const {
return ExplicitInfo ? ExplicitInfo->TypeAsWritten : nullptr;
}

/// Gets the location of the extern keyword, if present.
SourceLocation getExternKeywordLoc() const {
if (auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>())
return Info->ExternKeywordLoc;
return SourceLocation();
SourceLocation getExternLoc() const {
return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation();
}

/// Sets the location of the extern keyword.
void setExternKeywordLoc(SourceLocation Loc);
void setExternLoc(SourceLocation Loc) {
if (!ExplicitInfo)
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
ExplicitInfo->ExternLoc = Loc;
}

/// Sets the location of the template keyword.
void setTemplateKeywordLoc(SourceLocation Loc) {
if (!ExplicitInfo)
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
ExplicitInfo->TemplateKeywordLoc = Loc;
}

/// Gets the location of the template keyword, if present.
SourceLocation getTemplateKeywordLoc() const {
if (auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>())
return Info->TemplateKeywordLoc;
return SourceLocation();
return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation();
}

/// Sets the location of the template keyword.
void setTemplateKeywordLoc(SourceLocation Loc);

SourceRange getSourceRange() const override LLVM_READONLY;

void Profile(llvm::FoldingSetNodeID &ID) const {
Expand Down Expand Up @@ -2076,6 +2066,10 @@ class ClassTemplatePartialSpecializationDecl
/// The list of template parameters
TemplateParameterList* TemplateParams = nullptr;

/// The source info for the template arguments as written.
/// FIXME: redundant with TypeAsWritten?
const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;

/// The class template partial specialization from which this
/// class template partial specialization was instantiated.
///
Expand All @@ -2084,11 +2078,15 @@ class ClassTemplatePartialSpecializationDecl
llvm::PointerIntPair<ClassTemplatePartialSpecializationDecl *, 1, bool>
InstantiatedFromMember;

ClassTemplatePartialSpecializationDecl(
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
ClassTemplatePartialSpecializationDecl *PrevDecl);
ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK,
DeclContext *DC,
SourceLocation StartLoc,
SourceLocation IdLoc,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args,
const ASTTemplateArgumentListInfo *ArgsAsWritten,
ClassTemplatePartialSpecializationDecl *PrevDecl);

ClassTemplatePartialSpecializationDecl(ASTContext &C)
: ClassTemplateSpecializationDecl(C, ClassTemplatePartialSpecialization),
Expand All @@ -2103,8 +2101,11 @@ class ClassTemplatePartialSpecializationDecl
static ClassTemplatePartialSpecializationDecl *
Create(ASTContext &Context, TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args, QualType CanonInjectedType,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args,
const TemplateArgumentListInfo &ArgInfos,
QualType CanonInjectedType,
ClassTemplatePartialSpecializationDecl *PrevDecl);

static ClassTemplatePartialSpecializationDecl *
Expand Down Expand Up @@ -2135,6 +2136,11 @@ class ClassTemplatePartialSpecializationDecl
return TemplateParams->hasAssociatedConstraints();
}

/// Get the template arguments as written.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
return ArgsAsWritten;
}

/// Retrieve the member class template partial specialization from
/// which this particular class template partial specialization was
/// instantiated.
Expand Down Expand Up @@ -2607,12 +2613,27 @@ class VarTemplateSpecializationDecl : public VarDecl,
llvm::PointerUnion<VarTemplateDecl *, SpecializedPartialSpecialization *>
SpecializedTemplate;

/// Further info for explicit template specialization/instantiation.
struct ExplicitSpecializationInfo {
/// The type-as-written.
TypeSourceInfo *TypeAsWritten = nullptr;

/// The location of the extern keyword.
SourceLocation ExternLoc;

/// The location of the template keyword.
SourceLocation TemplateKeywordLoc;

ExplicitSpecializationInfo() = default;
};

/// Further info for explicit template specialization/instantiation.
/// Does not apply to implicit specializations.
SpecializationOrInstantiationInfo ExplicitInfo = nullptr;
ExplicitSpecializationInfo *ExplicitInfo = nullptr;

/// The template arguments used to describe this specialization.
const TemplateArgumentList *TemplateArgs;
const ASTTemplateArgumentListInfo *TemplateArgsInfo = nullptr;

/// The point where this template was instantiated (if any).
SourceLocation PointOfInstantiation;
Expand Down Expand Up @@ -2666,6 +2687,14 @@ class VarTemplateSpecializationDecl : public VarDecl,
/// specialization.
const TemplateArgumentList &getTemplateArgs() const { return *TemplateArgs; }

// TODO: Always set this when creating the new specialization?
void setTemplateArgsInfo(const TemplateArgumentListInfo &ArgsInfo);
void setTemplateArgsInfo(const ASTTemplateArgumentListInfo *ArgsInfo);

const ASTTemplateArgumentListInfo *getTemplateArgsInfo() const {
return TemplateArgsInfo;
}

/// Determine the kind of specialization that this
/// declaration represents.
TemplateSpecializationKind getSpecializationKind() const {
Expand Down Expand Up @@ -2769,49 +2798,44 @@ class VarTemplateSpecializationDecl : public VarDecl,
SpecializedTemplate = TemplDecl;
}

/// Retrieve the template argument list as written in the sources,
/// if any.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
if (auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>())
return Info->TemplateArgsAsWritten;
return ExplicitInfo.get<const ASTTemplateArgumentListInfo *>();
}

/// Set the template argument list as written in the sources.
void
setTemplateArgsAsWritten(const ASTTemplateArgumentListInfo *ArgsWritten) {
if (auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>())
Info->TemplateArgsAsWritten = ArgsWritten;
else
ExplicitInfo = ArgsWritten;
/// Sets the type of this specialization as it was written by
/// the user.
void setTypeAsWritten(TypeSourceInfo *T) {
if (!ExplicitInfo)
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
ExplicitInfo->TypeAsWritten = T;
}

/// Set the template argument list as written in the sources.
void setTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgsInfo) {
setTemplateArgsAsWritten(
ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo));
/// Gets the type of this specialization as it was written by
/// the user, if it was so written.
TypeSourceInfo *getTypeAsWritten() const {
return ExplicitInfo ? ExplicitInfo->TypeAsWritten : nullptr;
}

/// Gets the location of the extern keyword, if present.
SourceLocation getExternKeywordLoc() const {
if (auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>())
return Info->ExternKeywordLoc;
return SourceLocation();
SourceLocation getExternLoc() const {
return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation();
}

/// Sets the location of the extern keyword.
void setExternKeywordLoc(SourceLocation Loc);
void setExternLoc(SourceLocation Loc) {
if (!ExplicitInfo)
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
ExplicitInfo->ExternLoc = Loc;
}

/// Sets the location of the template keyword.
void setTemplateKeywordLoc(SourceLocation Loc) {
if (!ExplicitInfo)
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
ExplicitInfo->TemplateKeywordLoc = Loc;
}

/// Gets the location of the template keyword, if present.
SourceLocation getTemplateKeywordLoc() const {
if (auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>())
return Info->TemplateKeywordLoc;
return SourceLocation();
return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation();
}

/// Sets the location of the template keyword.
void setTemplateKeywordLoc(SourceLocation Loc);

SourceRange getSourceRange() const override LLVM_READONLY;

void Profile(llvm::FoldingSetNodeID &ID) const {
Expand Down Expand Up @@ -2839,6 +2863,10 @@ class VarTemplatePartialSpecializationDecl
/// The list of template parameters
TemplateParameterList *TemplateParams = nullptr;

/// The source info for the template arguments as written.
/// FIXME: redundant with TypeAsWritten?
const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;

/// The variable template partial specialization from which this
/// variable template partial specialization was instantiated.
///
Expand All @@ -2851,7 +2879,8 @@ class VarTemplatePartialSpecializationDecl
ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
StorageClass S, ArrayRef<TemplateArgument> Args);
StorageClass S, ArrayRef<TemplateArgument> Args,
const ASTTemplateArgumentListInfo *ArgInfos);

VarTemplatePartialSpecializationDecl(ASTContext &Context)
: VarTemplateSpecializationDecl(VarTemplatePartialSpecialization,
Expand All @@ -2868,8 +2897,8 @@ class VarTemplatePartialSpecializationDecl
Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
VarTemplateDecl *SpecializedTemplate, QualType T,
TypeSourceInfo *TInfo, StorageClass S,
ArrayRef<TemplateArgument> Args);
TypeSourceInfo *TInfo, StorageClass S, ArrayRef<TemplateArgument> Args,
const TemplateArgumentListInfo &ArgInfos);

static VarTemplatePartialSpecializationDecl *
CreateDeserialized(ASTContext &C, GlobalDeclID ID);
Expand All @@ -2885,6 +2914,11 @@ class VarTemplatePartialSpecializationDecl
return TemplateParams;
}

/// Get the template arguments as written.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
return ArgsAsWritten;
}

/// \brief All associated constraints of this partial specialization,
/// including the requires clause and any constraints derived from
/// constrained-parameters.
Expand Down
27 changes: 12 additions & 15 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2030,15 +2030,6 @@ DEF_TRAVERSE_DECL(RecordDecl, { TRY_TO(TraverseRecordHelper(D)); })

DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); })

template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
const TemplateArgumentLoc *TAL, unsigned Count) {
for (unsigned I = 0; I < Count; ++I) {
TRY_TO(TraverseTemplateArgumentLoc(TAL[I]));
}
return true;
}

#define DEF_TRAVERSE_TMPL_SPEC_DECL(TMPLDECLKIND, DECLKIND) \
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateSpecializationDecl, { \
/* For implicit instantiations ("set<int> x;"), we don't want to \
Expand All @@ -2048,12 +2039,9 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
TemplateSpecializationType). For explicit instantiations \
("template set<int>;"), we do need a callback, since this \
is the only callback that's made for this instantiation. \
We use getTemplateArgsAsWritten() to distinguish. */ \
if (const auto *ArgsWritten = D->getTemplateArgsAsWritten()) { \
/* The args that remains unspecialized. */ \
TRY_TO(TraverseTemplateArgumentLocsHelper( \
ArgsWritten->getTemplateArgs(), ArgsWritten->NumTemplateArgs)); \
} \
We use getTypeAsWritten() to distinguish. */ \
if (TypeSourceInfo *TSI = D->getTypeAsWritten()) \
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); \
\
if (getDerived().shouldVisitTemplateInstantiations() || \
D->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { \
Expand All @@ -2073,6 +2061,15 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
DEF_TRAVERSE_TMPL_SPEC_DECL(Class, CXXRecord)
DEF_TRAVERSE_TMPL_SPEC_DECL(Var, Var)

template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
const TemplateArgumentLoc *TAL, unsigned Count) {
for (unsigned I = 0; I < Count; ++I) {
TRY_TO(TraverseTemplateArgumentLoc(TAL[I]));
}
return true;
}

#define DEF_TRAVERSE_TMPL_PART_SPEC_DECL(TMPLDECLKIND, DECLKIND) \
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplatePartialSpecializationDecl, { \
/* The partial specialization. */ \
Expand Down
74 changes: 33 additions & 41 deletions clang/include/clang/ASTMatchers/ASTMatchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -764,9 +764,9 @@ AST_POLYMORPHIC_MATCHER(isImplicit,
return Node.isImplicit();
}

/// Matches templateSpecializationTypes, class template specializations,
/// variable template specializations, and function template specializations
/// that have at least one TemplateArgument matching the given InnerMatcher.
/// Matches classTemplateSpecializations, templateSpecializationType and
/// functionDecl that have at least one TemplateArgument matching the given
/// InnerMatcher.
///
/// Given
/// \code
Expand All @@ -788,8 +788,8 @@ AST_POLYMORPHIC_MATCHER(isImplicit,
AST_POLYMORPHIC_MATCHER_P(
hasAnyTemplateArgument,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
VarTemplateSpecializationDecl, FunctionDecl,
TemplateSpecializationType),
TemplateSpecializationType,
FunctionDecl),
internal::Matcher<TemplateArgument>, InnerMatcher) {
ArrayRef<TemplateArgument> List =
internal::getTemplateSpecializationArgs(Node);
Expand Down Expand Up @@ -1047,9 +1047,8 @@ AST_MATCHER(Expr, isTypeDependent) { return Node.isTypeDependent(); }
/// expr(isValueDependent()) matches return Size
AST_MATCHER(Expr, isValueDependent) { return Node.isValueDependent(); }

/// Matches templateSpecializationType, class template specializations,
/// variable template specializations, and function template specializations
/// where the n'th TemplateArgument matches the given InnerMatcher.
/// Matches classTemplateSpecializations, templateSpecializationType and
/// functionDecl where the n'th TemplateArgument matches the given InnerMatcher.
///
/// Given
/// \code
Expand All @@ -1069,8 +1068,8 @@ AST_MATCHER(Expr, isValueDependent) { return Node.isValueDependent(); }
AST_POLYMORPHIC_MATCHER_P2(
hasTemplateArgument,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
VarTemplateSpecializationDecl, FunctionDecl,
TemplateSpecializationType),
TemplateSpecializationType,
FunctionDecl),
unsigned, N, internal::Matcher<TemplateArgument>, InnerMatcher) {
ArrayRef<TemplateArgument> List =
internal::getTemplateSpecializationArgs(Node);
Expand Down Expand Up @@ -4067,7 +4066,7 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
/// Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
/// Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>,
/// Matcher<CXXUnresolvedConstructExpr>,
/// Matcher<CompoundLiteralExpr>,
/// Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>,
/// Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>,
/// Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
/// Matcher<TypedefNameDecl>
Expand All @@ -4076,8 +4075,9 @@ AST_POLYMORPHIC_MATCHER_P(
AST_POLYMORPHIC_SUPPORTED_TYPES(
BlockDecl, CXXBaseSpecifier, CXXCtorInitializer, CXXFunctionalCastExpr,
CXXNewExpr, CXXTemporaryObjectExpr, CXXUnresolvedConstructExpr,
CompoundLiteralExpr, DeclaratorDecl, ExplicitCastExpr, ObjCPropertyDecl,
TemplateArgumentLoc, TypedefNameDecl),
ClassTemplateSpecializationDecl, CompoundLiteralExpr, DeclaratorDecl,
ExplicitCastExpr, ObjCPropertyDecl, TemplateArgumentLoc,
TypedefNameDecl),
internal::Matcher<TypeLoc>, Inner) {
TypeSourceInfo *source = internal::GetTypeSourceInfo(Node);
if (source == nullptr) {
Expand Down Expand Up @@ -5304,10 +5304,9 @@ AST_POLYMORPHIC_MATCHER_P(parameterCountIs,
return Node.getNumParams() == N;
}

/// Matches templateSpecializationType, class template specialization,
/// variable template specialization, and function template specialization
/// nodes where the template argument matches the inner matcher. This matcher
/// may produce multiple matches.
/// Matches classTemplateSpecialization, templateSpecializationType and
/// functionDecl nodes where the template argument matches the inner matcher.
/// This matcher may produce multiple matches.
///
/// Given
/// \code
Expand All @@ -5331,8 +5330,7 @@ AST_POLYMORPHIC_MATCHER_P(parameterCountIs,
AST_POLYMORPHIC_MATCHER_P(
forEachTemplateArgument,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
VarTemplateSpecializationDecl, FunctionDecl,
TemplateSpecializationType),
TemplateSpecializationType, FunctionDecl),
internal::Matcher<TemplateArgument>, InnerMatcher) {
ArrayRef<TemplateArgument> TemplateArgs =
clang::ast_matchers::internal::getTemplateSpecializationArgs(Node);
Expand Down Expand Up @@ -6907,10 +6905,8 @@ extern const internal::VariadicDynCastAllOfMatcher<
TypeLoc, TemplateSpecializationTypeLoc>
templateSpecializationTypeLoc;

/// Matches template specialization `TypeLoc`s, class template specializations,
/// variable template specializations, and function template specializations
/// that have at least one `TemplateArgumentLoc` matching the given
/// `InnerMatcher`.
/// Matches template specialization `TypeLoc`s that have at least one
/// `TemplateArgumentLoc` matching the given `InnerMatcher`.
///
/// Given
/// \code
Expand All @@ -6920,21 +6916,20 @@ extern const internal::VariadicDynCastAllOfMatcher<
/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
/// hasTypeLoc(loc(asString("int")))))))
/// matches `A<int> a`.
AST_POLYMORPHIC_MATCHER_P(
hasAnyTemplateArgumentLoc,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
VarTemplateSpecializationDecl, FunctionDecl,
DeclRefExpr, TemplateSpecializationTypeLoc),
internal::Matcher<TemplateArgumentLoc>, InnerMatcher) {
auto Args = internal::getTemplateArgsWritten(Node);
return matchesFirstInRange(InnerMatcher, Args.begin(), Args.end(), Finder,
Builder) != Args.end();
AST_MATCHER_P(TemplateSpecializationTypeLoc, hasAnyTemplateArgumentLoc,
internal::Matcher<TemplateArgumentLoc>, InnerMatcher) {
for (unsigned Index = 0, N = Node.getNumArgs(); Index < N; ++Index) {
clang::ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);
if (InnerMatcher.matches(Node.getArgLoc(Index), Finder, &Result)) {
*Builder = std::move(Result);
return true;
}
}
return false;
}

/// Matches template specialization `TypeLoc`s, class template specializations,
/// variable template specializations, and function template specializations
/// where the n'th `TemplateArgumentLoc` matches the given `InnerMatcher`.
/// Matches template specialization `TypeLoc`s where the n'th
/// `TemplateArgumentLoc` matches the given `InnerMatcher`.
///
/// Given
/// \code
Expand All @@ -6947,13 +6942,10 @@ AST_POLYMORPHIC_MATCHER_P(
/// matches `A<double, int> b`, but not `A<int, double> c`.
AST_POLYMORPHIC_MATCHER_P2(
hasTemplateArgumentLoc,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
VarTemplateSpecializationDecl, FunctionDecl,
DeclRefExpr, TemplateSpecializationTypeLoc),
AST_POLYMORPHIC_SUPPORTED_TYPES(DeclRefExpr, TemplateSpecializationTypeLoc),
unsigned, Index, internal::Matcher<TemplateArgumentLoc>, InnerMatcher) {
auto Args = internal::getTemplateArgsWritten(Node);
return Index < Args.size() &&
InnerMatcher.matches(Args[Index], Finder, Builder);
return internal::MatchTemplateArgLocAt(Node, Index, InnerMatcher, Finder,
Builder);
}

/// Matches C or C++ elaborated `TypeLoc`s.
Expand Down
50 changes: 5 additions & 45 deletions clang/include/clang/ASTMatchers/ASTMatchersInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ inline TypeSourceInfo *GetTypeSourceInfo(const BlockDecl &Node) {
inline TypeSourceInfo *GetTypeSourceInfo(const CXXNewExpr &Node) {
return Node.getAllocatedTypeSourceInfo();
}
inline TypeSourceInfo *
GetTypeSourceInfo(const ClassTemplateSpecializationDecl &Node) {
return Node.getTypeAsWritten();
}

/// Unifies obtaining the FunctionProtoType pointer from both
/// FunctionProtoType and FunctionDecl nodes..
Expand Down Expand Up @@ -1935,11 +1939,6 @@ getTemplateSpecializationArgs(const ClassTemplateSpecializationDecl &D) {
return D.getTemplateArgs().asArray();
}

inline ArrayRef<TemplateArgument>
getTemplateSpecializationArgs(const VarTemplateSpecializationDecl &D) {
return D.getTemplateArgs().asArray();
}

inline ArrayRef<TemplateArgument>
getTemplateSpecializationArgs(const TemplateSpecializationType &T) {
return T.template_arguments();
Expand All @@ -1949,46 +1948,7 @@ inline ArrayRef<TemplateArgument>
getTemplateSpecializationArgs(const FunctionDecl &FD) {
if (const auto* TemplateArgs = FD.getTemplateSpecializationArgs())
return TemplateArgs->asArray();
return std::nullopt;
}

inline ArrayRef<TemplateArgumentLoc>
getTemplateArgsWritten(const ClassTemplateSpecializationDecl &D) {
if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
return Args->arguments();
return std::nullopt;
}

inline ArrayRef<TemplateArgumentLoc>
getTemplateArgsWritten(const VarTemplateSpecializationDecl &D) {
if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
return Args->arguments();
return std::nullopt;
}

inline ArrayRef<TemplateArgumentLoc>
getTemplateArgsWritten(const FunctionDecl &FD) {
if (const auto *Args = FD.getTemplateSpecializationArgsAsWritten())
return Args->arguments();
return std::nullopt;
}

inline ArrayRef<TemplateArgumentLoc>
getTemplateArgsWritten(const DeclRefExpr &DRE) {
if (const auto *Args = DRE.getTemplateArgs())
return {Args, DRE.getNumTemplateArgs()};
return std::nullopt;
}

inline SmallVector<TemplateArgumentLoc>
getTemplateArgsWritten(const TemplateSpecializationTypeLoc &T) {
SmallVector<TemplateArgumentLoc> Args;
if (!T.isNull()) {
Args.reserve(T.getNumArgs());
for (unsigned I = 0; I < T.getNumArgs(); ++I)
Args.emplace_back(T.getArgLoc(I));
}
return Args;
return ArrayRef<TemplateArgument>();
}

struct NotEqualsBoundNodePredicate {
Expand Down
68 changes: 36 additions & 32 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -443,9 +443,8 @@ namespace clang {
Expected<FunctionTemplateAndArgsTy>
ImportFunctionTemplateWithTemplateArgsFromSpecialization(
FunctionDecl *FromFD);

template <typename DeclTy>
Error ImportTemplateParameterLists(const DeclTy *FromD, DeclTy *ToD);
Error ImportTemplateParameterLists(const DeclaratorDecl *FromD,
DeclaratorDecl *ToD);

Error ImportTemplateInformation(FunctionDecl *FromFD, FunctionDecl *ToFD);

Expand Down Expand Up @@ -3323,9 +3322,8 @@ ExpectedDecl ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
return ToEnumerator;
}

template <typename DeclTy>
Error ASTNodeImporter::ImportTemplateParameterLists(const DeclTy *FromD,
DeclTy *ToD) {
Error ASTNodeImporter::ImportTemplateParameterLists(const DeclaratorDecl *FromD,
DeclaratorDecl *ToD) {
unsigned int Num = FromD->getNumTemplateParameterLists();
if (Num == 0)
return Error::success();
Expand Down Expand Up @@ -6212,16 +6210,15 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
if (!IdLocOrErr)
return IdLocOrErr.takeError();

// Import TemplateArgumentListInfo.
TemplateArgumentListInfo ToTAInfo;
if (const auto *ASTTemplateArgs = D->getTemplateArgsAsWritten()) {
if (Error Err = ImportTemplateArgumentListInfo(*ASTTemplateArgs, ToTAInfo))
return std::move(Err);
}

// Create the specialization.
ClassTemplateSpecializationDecl *D2 = nullptr;
if (PartialSpec) {
// Import TemplateArgumentListInfo.
TemplateArgumentListInfo ToTAInfo;
const auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten();
if (Error Err = ImportTemplateArgumentListInfo(ASTTemplateArgs, ToTAInfo))
return std::move(Err);

QualType CanonInjType;
if (Error Err = importInto(
CanonInjType, PartialSpec->getInjectedSpecializationType()))
Expand All @@ -6231,7 +6228,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>(
D2, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr,
*IdLocOrErr, ToTPList, ClassTemplate,
llvm::ArrayRef(TemplateArgs.data(), TemplateArgs.size()),
llvm::ArrayRef(TemplateArgs.data(), TemplateArgs.size()), ToTAInfo,
CanonInjType,
cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
return D2;
Expand Down Expand Up @@ -6279,27 +6276,28 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
else
return BraceRangeOrErr.takeError();

if (Error Err = ImportTemplateParameterLists(D, D2))
return std::move(Err);

// Import the qualifier, if any.
if (auto LocOrErr = import(D->getQualifierLoc()))
D2->setQualifierInfo(*LocOrErr);
else
return LocOrErr.takeError();

if (D->getTemplateArgsAsWritten())
D2->setTemplateArgsAsWritten(ToTAInfo);
if (auto *TSI = D->getTypeAsWritten()) {
if (auto TInfoOrErr = import(TSI))
D2->setTypeAsWritten(*TInfoOrErr);
else
return TInfoOrErr.takeError();

if (auto LocOrErr = import(D->getTemplateKeywordLoc()))
D2->setTemplateKeywordLoc(*LocOrErr);
else
return LocOrErr.takeError();
if (auto LocOrErr = import(D->getTemplateKeywordLoc()))
D2->setTemplateKeywordLoc(*LocOrErr);
else
return LocOrErr.takeError();

if (auto LocOrErr = import(D->getExternKeywordLoc()))
D2->setExternKeywordLoc(*LocOrErr);
else
return LocOrErr.takeError();
if (auto LocOrErr = import(D->getExternLoc()))
D2->setExternLoc(*LocOrErr);
else
return LocOrErr.takeError();
}

if (D->getPointOfInstantiation().isValid()) {
if (auto POIOrErr = import(D->getPointOfInstantiation()))
Expand Down Expand Up @@ -6519,14 +6517,22 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *D2 = nullptr;

TemplateArgumentListInfo ToTAInfo;
if (const auto *Args = D->getTemplateArgsAsWritten()) {
if (const ASTTemplateArgumentListInfo *Args = D->getTemplateArgsInfo()) {
if (Error Err = ImportTemplateArgumentListInfo(*Args, ToTAInfo))
return std::move(Err);
}

using PartVarSpecDecl = VarTemplatePartialSpecializationDecl;
// Create a new specialization.
if (auto *FromPartial = dyn_cast<PartVarSpecDecl>(D)) {
// Import TemplateArgumentListInfo
TemplateArgumentListInfo ArgInfos;
const auto *FromTAArgsAsWritten = FromPartial->getTemplateArgsAsWritten();
// NOTE: FromTAArgsAsWritten and template parameter list are non-null.
if (Error Err =
ImportTemplateArgumentListInfo(*FromTAArgsAsWritten, ArgInfos))
return std::move(Err);

auto ToTPListOrErr = import(FromPartial->getTemplateParameters());
if (!ToTPListOrErr)
return ToTPListOrErr.takeError();
Expand All @@ -6535,7 +6541,7 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
if (GetImportedOrCreateDecl(ToPartial, D, Importer.getToContext(), DC,
*BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr,
VarTemplate, QualType(), nullptr,
D->getStorageClass(), TemplateArgs))
D->getStorageClass(), TemplateArgs, ArgInfos))
return ToPartial;

if (Expected<PartVarSpecDecl *> ToInstOrErr =
Expand Down Expand Up @@ -6578,9 +6584,7 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
}

D2->setSpecializationKind(D->getSpecializationKind());

if (D->getTemplateArgsAsWritten())
D2->setTemplateArgsAsWritten(ToTAInfo);
D2->setTemplateArgsInfo(ToTAInfo);

if (auto LocOrErr = import(D->getQualifierLoc()))
D2->setQualifierInfo(*LocOrErr);
Expand Down
18 changes: 9 additions & 9 deletions clang/lib/AST/DeclPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1083,15 +1083,15 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
NNS->print(Out, Policy);
Out << *D;

if (auto *S = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
const TemplateParameterList *TParams =
S->getSpecializedTemplate()->getTemplateParameters();
const ASTTemplateArgumentListInfo *TArgAsWritten =
S->getTemplateArgsAsWritten();
if (TArgAsWritten && !Policy.PrintCanonicalTypes)
printTemplateArguments(TArgAsWritten->arguments(), TParams);
else
printTemplateArguments(S->getTemplateArgs().asArray(), TParams);
if (auto S = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
ArrayRef<TemplateArgument> Args = S->getTemplateArgs().asArray();
if (!Policy.PrintCanonicalTypes)
if (const auto* TSI = S->getTypeAsWritten())
if (const auto *TST =
dyn_cast<TemplateSpecializationType>(TSI->getType()))
Args = TST->template_arguments();
printTemplateArguments(
Args, S->getSpecializedTemplate()->getTemplateParameters());
}
}

Expand Down
198 changes: 88 additions & 110 deletions clang/lib/AST/DeclTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -985,63 +985,41 @@ ClassTemplateSpecializationDecl::getSpecializedTemplate() const {

SourceRange
ClassTemplateSpecializationDecl::getSourceRange() const {
if (getSpecializationKind() == TSK_ExplicitInstantiationDeclaration) {
return SourceRange(getExternKeywordLoc(),
getTemplateArgsAsWritten()->getRAngleLoc());
} else if (getSpecializationKind() == TSK_ExplicitInstantiationDefinition) {
return SourceRange(getTemplateKeywordLoc(),
getTemplateArgsAsWritten()->getRAngleLoc());
} else if (!isExplicitSpecialization()) {
if (ExplicitInfo) {
SourceLocation Begin = getTemplateKeywordLoc();
if (Begin.isValid()) {
// Here we have an explicit (partial) specialization or instantiation.
assert(getSpecializationKind() == TSK_ExplicitSpecialization ||
getSpecializationKind() == TSK_ExplicitInstantiationDeclaration ||
getSpecializationKind() == TSK_ExplicitInstantiationDefinition);
if (getExternLoc().isValid())
Begin = getExternLoc();
SourceLocation End = getBraceRange().getEnd();
if (End.isInvalid())
End = getTypeAsWritten()->getTypeLoc().getEndLoc();
return SourceRange(Begin, End);
}
// An implicit instantiation of a class template partial specialization
// uses ExplicitInfo to record the TypeAsWritten, but the source
// locations should be retrieved from the instantiation pattern.
using CTPSDecl = ClassTemplatePartialSpecializationDecl;
auto *ctpsd = const_cast<CTPSDecl *>(cast<CTPSDecl>(this));
CTPSDecl *inst_from = ctpsd->getInstantiatedFromMember();
assert(inst_from != nullptr);
return inst_from->getSourceRange();
}
else {
// No explicit info available.
llvm::PointerUnion<ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *>
InstFrom = getInstantiatedFrom();
if (InstFrom.isNull())
inst_from = getInstantiatedFrom();
if (inst_from.isNull())
return getSpecializedTemplate()->getSourceRange();
if (const auto *CTD = InstFrom.dyn_cast<ClassTemplateDecl *>())
return CTD->getSourceRange();
return InstFrom.get<ClassTemplatePartialSpecializationDecl *>()
->getSourceRange();
}
SourceLocation Begin = TagDecl::getOuterLocStart();
if (const auto *CTPSD =
dyn_cast<ClassTemplatePartialSpecializationDecl>(this)) {
if (const auto *InstFrom = CTPSD->getInstantiatedFromMember())
return InstFrom->getSourceRange();
else if (!getNumTemplateParameterLists())
Begin = CTPSD->getTemplateParameters()->getTemplateLoc();
}
SourceLocation End = getBraceRange().getEnd();
if (End.isInvalid())
End = getTemplateArgsAsWritten()->getRAngleLoc();
return SourceRange(Begin, End);
}

void ClassTemplateSpecializationDecl::setExternKeywordLoc(SourceLocation Loc) {
auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>();
if (!Info) {
// Don't allocate if the location is invalid.
if (Loc.isInvalid())
return;
Info = new (getASTContext()) ExplicitInstantiationInfo;
Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
ExplicitInfo = Info;
if (const auto *ctd = inst_from.dyn_cast<ClassTemplateDecl *>())
return ctd->getSourceRange();
return inst_from.get<ClassTemplatePartialSpecializationDecl *>()
->getSourceRange();
}
Info->ExternKeywordLoc = Loc;
}

void ClassTemplateSpecializationDecl::setTemplateKeywordLoc(
SourceLocation Loc) {
auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>();
if (!Info) {
// Don't allocate if the location is invalid.
if (Loc.isInvalid())
return;
Info = new (getASTContext()) ExplicitInstantiationInfo;
Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
ExplicitInfo = Info;
}
Info->TemplateKeywordLoc = Loc;
}

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1109,29 +1087,43 @@ void ImplicitConceptSpecializationDecl::setTemplateArguments(
//===----------------------------------------------------------------------===//
void ClassTemplatePartialSpecializationDecl::anchor() {}

ClassTemplatePartialSpecializationDecl::ClassTemplatePartialSpecializationDecl(
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
ClassTemplatePartialSpecializationDecl *PrevDecl)
: ClassTemplateSpecializationDecl(
Context, ClassTemplatePartialSpecialization, TK, DC, StartLoc, IdLoc,
SpecializedTemplate, Args, PrevDecl),
TemplateParams(Params), InstantiatedFromMember(nullptr, false) {
ClassTemplatePartialSpecializationDecl::
ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK,
DeclContext *DC,
SourceLocation StartLoc,
SourceLocation IdLoc,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args,
const ASTTemplateArgumentListInfo *ArgInfos,
ClassTemplatePartialSpecializationDecl *PrevDecl)
: ClassTemplateSpecializationDecl(Context,
ClassTemplatePartialSpecialization,
TK, DC, StartLoc, IdLoc,
SpecializedTemplate, Args, PrevDecl),
TemplateParams(Params), ArgsAsWritten(ArgInfos),
InstantiatedFromMember(nullptr, false) {
if (AdoptTemplateParameterList(Params, this))
setInvalidDecl();
}

ClassTemplatePartialSpecializationDecl *
ClassTemplatePartialSpecializationDecl::Create(
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
QualType CanonInjectedType,
ClassTemplatePartialSpecializationDecl *PrevDecl) {
auto *Result = new (Context, DC) ClassTemplatePartialSpecializationDecl(
Context, TK, DC, StartLoc, IdLoc, Params, SpecializedTemplate, Args,
PrevDecl);
ClassTemplatePartialSpecializationDecl::
Create(ASTContext &Context, TagKind TK,DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args,
const TemplateArgumentListInfo &ArgInfos,
QualType CanonInjectedType,
ClassTemplatePartialSpecializationDecl *PrevDecl) {
const ASTTemplateArgumentListInfo *ASTArgInfos =
ASTTemplateArgumentListInfo::Create(Context, ArgInfos);

auto *Result = new (Context, DC)
ClassTemplatePartialSpecializationDecl(Context, TK, DC, StartLoc, IdLoc,
Params, SpecializedTemplate, Args,
ASTArgInfos, PrevDecl);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
Result->setMayHaveOutOfDateDef(false);

Expand Down Expand Up @@ -1379,47 +1371,26 @@ VarTemplateDecl *VarTemplateSpecializationDecl::getSpecializedTemplate() const {
return SpecializedTemplate.get<VarTemplateDecl *>();
}

void VarTemplateSpecializationDecl::setTemplateArgsInfo(
const TemplateArgumentListInfo &ArgsInfo) {
TemplateArgsInfo =
ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo);
}

void VarTemplateSpecializationDecl::setTemplateArgsInfo(
const ASTTemplateArgumentListInfo *ArgsInfo) {
TemplateArgsInfo =
ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo);
}

SourceRange VarTemplateSpecializationDecl::getSourceRange() const {
if (isExplicitSpecialization() && !hasInit()) {
if (const ASTTemplateArgumentListInfo *Info = getTemplateArgsAsWritten())
if (const ASTTemplateArgumentListInfo *Info = getTemplateArgsInfo())
return SourceRange(getOuterLocStart(), Info->getRAngleLoc());
} else if (getTemplateSpecializationKind() ==
TSK_ExplicitInstantiationDeclaration) {
if (const ASTTemplateArgumentListInfo *Info = getTemplateArgsAsWritten())
return SourceRange(getExternKeywordLoc(), Info->getRAngleLoc());
} else if (getTemplateSpecializationKind() ==
TSK_ExplicitInstantiationDefinition) {
if (const ASTTemplateArgumentListInfo *Info = getTemplateArgsAsWritten())
return SourceRange(getTemplateKeywordLoc(), Info->getRAngleLoc());
}
return VarDecl::getSourceRange();
}

void VarTemplateSpecializationDecl::setExternKeywordLoc(SourceLocation Loc) {
auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>();
if (!Info) {
// Don't allocate if the location is invalid.
if (Loc.isInvalid())
return;
Info = new (getASTContext()) ExplicitInstantiationInfo;
Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
ExplicitInfo = Info;
}
Info->ExternKeywordLoc = Loc;
}

void VarTemplateSpecializationDecl::setTemplateKeywordLoc(SourceLocation Loc) {
auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>();
if (!Info) {
// Don't allocate if the location is invalid.
if (Loc.isInvalid())
return;
Info = new (getASTContext()) ExplicitInstantiationInfo;
Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
ExplicitInfo = Info;
}
Info->TemplateKeywordLoc = Loc;
}

//===----------------------------------------------------------------------===//
// VarTemplatePartialSpecializationDecl Implementation
Expand All @@ -1431,11 +1402,13 @@ VarTemplatePartialSpecializationDecl::VarTemplatePartialSpecializationDecl(
ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
StorageClass S, ArrayRef<TemplateArgument> Args)
StorageClass S, ArrayRef<TemplateArgument> Args,
const ASTTemplateArgumentListInfo *ArgInfos)
: VarTemplateSpecializationDecl(VarTemplatePartialSpecialization, Context,
DC, StartLoc, IdLoc, SpecializedTemplate, T,
TInfo, S, Args),
TemplateParams(Params), InstantiatedFromMember(nullptr, false) {
TemplateParams(Params), ArgsAsWritten(ArgInfos),
InstantiatedFromMember(nullptr, false) {
if (AdoptTemplateParameterList(Params, DC))
setInvalidDecl();
}
Expand All @@ -1445,10 +1418,15 @@ VarTemplatePartialSpecializationDecl::Create(
ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
StorageClass S, ArrayRef<TemplateArgument> Args) {
auto *Result = new (Context, DC) VarTemplatePartialSpecializationDecl(
Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo, S,
Args);
StorageClass S, ArrayRef<TemplateArgument> Args,
const TemplateArgumentListInfo &ArgInfos) {
const ASTTemplateArgumentListInfo *ASTArgInfos
= ASTTemplateArgumentListInfo::Create(Context, ArgInfos);

auto *Result =
new (Context, DC) VarTemplatePartialSpecializationDecl(
Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo,
S, Args, ASTArgInfos);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
return Result;
}
Expand Down
25 changes: 14 additions & 11 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1472,18 +1472,21 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {

// If this is a class template specialization, print the template
// arguments.
if (auto *S = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
const TemplateParameterList *TParams =
S->getSpecializedTemplate()->getTemplateParameters();
const ASTTemplateArgumentListInfo *TArgAsWritten =
S->getTemplateArgsAsWritten();
if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
ArrayRef<TemplateArgument> Args;
TypeSourceInfo *TAW = Spec->getTypeAsWritten();
if (!Policy.PrintCanonicalTypes && TAW) {
const TemplateSpecializationType *TST =
cast<TemplateSpecializationType>(TAW->getType());
Args = TST->template_arguments();
} else {
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
Args = TemplateArgs.asArray();
}
IncludeStrongLifetimeRAII Strong(Policy);
if (TArgAsWritten && !Policy.PrintCanonicalTypes)
printTemplateArgumentList(OS, TArgAsWritten->arguments(), Policy,
TParams);
else
printTemplateArgumentList(OS, S->getTemplateArgs().asArray(), Policy,
TParams);
printTemplateArgumentList(
OS, Args, Policy,
Spec->getSpecializedTemplate()->getTemplateParameters());
}

spaceBeforePlaceHolder(OS);
Expand Down
9 changes: 3 additions & 6 deletions clang/lib/Index/IndexDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -673,12 +673,9 @@ class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> {
IndexCtx.indexTagDecl(
D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf),
SpecializationOf));
// Template specialization arguments.
if (const ASTTemplateArgumentListInfo *TemplateArgInfo =
D->getTemplateArgsAsWritten()) {
for (const auto &Arg : TemplateArgInfo->arguments())
handleTemplateArgumentLoc(Arg, D, D->getLexicalDeclContext());
}
if (TypeSourceInfo *TSI = D->getTypeAsWritten())
IndexCtx.indexTypeSourceInfo(TSI, /*Parent=*/nullptr,
D->getLexicalDeclContext());
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1408,7 +1408,7 @@ void Sema::ActOnEndOfTranslationUnit() {
SourceRange DiagRange = DiagD->getLocation();
if (const auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(DiagD)) {
if (const ASTTemplateArgumentListInfo *ASTTAL =
VTSD->getTemplateArgsAsWritten())
VTSD->getTemplateArgsInfo())
DiagRange.setEnd(ASTTAL->RAngleLoc);
}
if (DiagD->isReferenced()) {
Expand Down
56 changes: 34 additions & 22 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5166,8 +5166,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
VarTemplatePartialSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc,
TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC,
CanonicalConverted);
Partial->setTemplateArgsAsWritten(TemplateArgs);
CanonicalConverted, TemplateArgs);

if (!PrevPartial)
VarTemplate->AddPartialSpecialization(Partial, InsertPos);
Expand All @@ -5185,7 +5184,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
Specialization = VarTemplateSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc,
VarTemplate, DI->getType(), DI, SC, CanonicalConverted);
Specialization->setTemplateArgsAsWritten(TemplateArgs);
Specialization->setTemplateArgsInfo(TemplateArgs);

if (!PrevDecl)
VarTemplate->AddSpecialization(Specialization, InsertPos);
Expand Down Expand Up @@ -5220,6 +5219,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
}
}

Specialization->setTemplateKeywordLoc(TemplateKWLoc);
Specialization->setLexicalDeclContext(CurContext);

// Add the specialization into its lexical context, so that it can
Expand Down Expand Up @@ -9276,6 +9276,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(

// NOTE: KWLoc is the location of the tag keyword. This will instead
// store the location of the outermost template keyword in the declaration.
SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0
? TemplateParameterLists[0]->getTemplateLoc() : KWLoc;
SourceLocation TemplateNameLoc = TemplateId.TemplateNameLoc;
SourceLocation LAngleLoc = TemplateId.LAngleLoc;
SourceLocation RAngleLoc = TemplateId.RAngleLoc;
Expand Down Expand Up @@ -9487,8 +9489,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
ClassTemplatePartialSpecializationDecl::Create(
Context, Kind, ClassTemplate->getDeclContext(), KWLoc,
TemplateNameLoc, TemplateParams, ClassTemplate, CanonicalConverted,
CanonType, PrevPartial);
Partial->setTemplateArgsAsWritten(TemplateArgs);
TemplateArgs, CanonType, PrevPartial);
SetNestedNameSpecifier(*this, Partial, SS);
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
Partial->setTemplateParameterListsInfo(
Expand All @@ -9511,7 +9512,6 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
Specialization = ClassTemplateSpecializationDecl::Create(
Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
ClassTemplate, CanonicalConverted, PrevDecl);
Specialization->setTemplateArgsAsWritten(TemplateArgs);
SetNestedNameSpecifier(*this, Specialization, SS);
if (TemplateParameterLists.size() > 0) {
Specialization->setTemplateParameterListsInfo(Context,
Expand Down Expand Up @@ -9595,6 +9595,21 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
<< (isPartialSpecialization? 1 : 0)
<< FixItHint::CreateRemoval(ModulePrivateLoc);

// Build the fully-sugared type for this class template
// specialization as the user wrote in the specialization
// itself. This means that we'll pretty-print the type retrieved
// from the specialization's declaration the way that the user
// 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);
if (TUK != TUK_Friend) {
Specialization->setTypeAsWritten(WrittenTy);
Specialization->setTemplateKeywordLoc(TemplateKWLoc);
}

// C++ [temp.expl.spec]p9:
// A template explicit specialization is in the scope of the
// namespace in which the template was defined.
Expand All @@ -9610,15 +9625,6 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
Specialization->startDefinition();

if (TUK == TUK_Friend) {
// Build the fully-sugared type for this class template
// specialization as the user wrote in the specialization
// itself. This means that we'll pretty-print the type retrieved
// from the specialization's declaration the way that the user
// 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,
Expand Down Expand Up @@ -10824,10 +10830,21 @@ DeclResult Sema::ActOnExplicitInstantiation(
}
}

Specialization->setTemplateArgsAsWritten(TemplateArgs);
// Build the fully-sugared type for this explicit instantiation as
// the user wrote in the explicit instantiation itself. This means
// that we'll pretty-print the type retrieved from the
// specialization's declaration the way that the user actually wrote
// the explicit instantiation, 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,
Context.getTypeDeclType(Specialization));
Specialization->setTypeAsWritten(WrittenTy);

// Set source locations for keywords.
Specialization->setExternKeywordLoc(ExternLoc);
Specialization->setExternLoc(ExternLoc);
Specialization->setTemplateKeywordLoc(TemplateLoc);
Specialization->setBraceRange(SourceRange());

Expand Down Expand Up @@ -11240,11 +11257,6 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (!HasNoEffect) {
// Instantiate static data member or variable template.
Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
if (auto *VTSD = dyn_cast<VarTemplatePartialSpecializationDecl>(Prev)) {
VTSD->setExternKeywordLoc(ExternLoc);
VTSD->setTemplateKeywordLoc(TemplateLoc);
}

// Merge attributes.
ProcessDeclAttributeList(S, Prev, D.getDeclSpec().getAttributes());
if (PrevTemplate)
Expand Down
163 changes: 104 additions & 59 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3858,16 +3858,15 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(

// Substitute into the template arguments of the class template explicit
// specialization.
TemplateArgumentListInfo InstTemplateArgs;
if (const ASTTemplateArgumentListInfo *TemplateArgsInfo =
D->getTemplateArgsAsWritten()) {
InstTemplateArgs.setLAngleLoc(TemplateArgsInfo->getLAngleLoc());
InstTemplateArgs.setRAngleLoc(TemplateArgsInfo->getRAngleLoc());

if (SemaRef.SubstTemplateArguments(TemplateArgsInfo->arguments(),
TemplateArgs, InstTemplateArgs))
return nullptr;
}
TemplateSpecializationTypeLoc Loc = D->getTypeAsWritten()->getTypeLoc().
castAs<TemplateSpecializationTypeLoc>();
TemplateArgumentListInfo InstTemplateArgs(Loc.getLAngleLoc(),
Loc.getRAngleLoc());
SmallVector<TemplateArgumentLoc, 4> ArgLocs;
for (unsigned I = 0; I != Loc.getNumArgs(); ++I)
ArgLocs.push_back(Loc.getArgLoc(I));
if (SemaRef.SubstTemplateArguments(ArgLocs, TemplateArgs, InstTemplateArgs))
return nullptr;

// Check that the template argument list is well-formed for this
// class template.
Expand Down Expand Up @@ -3921,7 +3920,6 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
ClassTemplateSpecializationDecl::Create(
SemaRef.Context, D->getTagKind(), Owner, D->getBeginLoc(),
D->getLocation(), InstClassTemplate, CanonicalConverted, PrevDecl);
InstD->setTemplateArgsAsWritten(InstTemplateArgs);

// Add this partial specialization to the set of class template partial
// specializations.
Expand All @@ -3932,10 +3930,28 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
if (SubstQualifier(D, InstD))
return nullptr;

// Build the canonical type that describes the converted template
// arguments of the class template explicit specialization.
QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
TemplateName(InstClassTemplate), CanonicalConverted,
SemaRef.Context.getRecordType(InstD));

// Build the fully-sugared type for this class template
// specialization as the user wrote in the specialization
// itself. This means that we'll pretty-print the type retrieved
// from the specialization's declaration the way that the user
// 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 = SemaRef.Context.getTemplateSpecializationTypeInfo(
TemplateName(InstClassTemplate), D->getLocation(), InstTemplateArgs,
CanonType);

InstD->setAccess(D->getAccess());
InstD->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation);
InstD->setSpecializationKind(D->getSpecializationKind());
InstD->setExternKeywordLoc(D->getExternKeywordLoc());
InstD->setTypeAsWritten(WrittenTy);
InstD->setExternLoc(D->getExternLoc());
InstD->setTemplateKeywordLoc(D->getTemplateKeywordLoc());

Owner->addDecl(InstD);
Expand Down Expand Up @@ -3969,7 +3985,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(

// Substitute the current template arguments.
if (const ASTTemplateArgumentListInfo *TemplateArgsInfo =
D->getTemplateArgsAsWritten()) {
D->getTemplateArgsInfo()) {
VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo->getLAngleLoc());
VarTemplateArgsInfo.setRAngleLoc(TemplateArgsInfo->getRAngleLoc());

Expand Down Expand Up @@ -4027,7 +4043,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *Var = VarTemplateSpecializationDecl::Create(
SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted);
Var->setTemplateArgsAsWritten(TemplateArgsInfo);
Var->setTemplateArgsInfo(TemplateArgsInfo);
if (!PrevDecl) {
void *InsertPos = nullptr;
VarTemplate->findSpecialization(Converted, InsertPos);
Expand Down Expand Up @@ -4269,21 +4285,19 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
TemplateName(ClassTemplate), CanonicalConverted);

// Create the class template partial specialization declaration.
ClassTemplatePartialSpecializationDecl *InstPartialSpec =
ClassTemplatePartialSpecializationDecl::Create(
SemaRef.Context, PartialSpec->getTagKind(), Owner,
PartialSpec->getBeginLoc(), PartialSpec->getLocation(), InstParams,
ClassTemplate, CanonicalConverted, CanonType,
/*PrevDecl=*/nullptr);

InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs);

// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
return nullptr;

InstPartialSpec->setInstantiatedFromMember(PartialSpec);
// Build the fully-sugared type for this class template
// specialization as the user wrote in the specialization
// itself. This means that we'll pretty-print the type retrieved
// from the specialization's declaration the way that the user
// 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
= SemaRef.Context.getTemplateSpecializationTypeInfo(
TemplateName(ClassTemplate),
PartialSpec->getLocation(),
InstTemplateArgs,
CanonType);

if (PrevDecl) {
// We've already seen a partial specialization with the same template
Expand All @@ -4301,14 +4315,28 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
//
// Outer<int, int> outer; // error: the partial specializations of Inner
// // have the same signature.
SemaRef.Diag(InstPartialSpec->getLocation(),
diag::err_partial_spec_redeclared)
<< InstPartialSpec;
SemaRef.Diag(PartialSpec->getLocation(), diag::err_partial_spec_redeclared)
<< WrittenTy->getType();
SemaRef.Diag(PrevDecl->getLocation(), diag::note_prev_partial_spec_here)
<< SemaRef.Context.getTypeDeclType(PrevDecl);
return nullptr;
}


// Create the class template partial specialization declaration.
ClassTemplatePartialSpecializationDecl *InstPartialSpec =
ClassTemplatePartialSpecializationDecl::Create(
SemaRef.Context, PartialSpec->getTagKind(), Owner,
PartialSpec->getBeginLoc(), PartialSpec->getLocation(), InstParams,
ClassTemplate, CanonicalConverted, InstTemplateArgs, CanonType,
nullptr);
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
return nullptr;

InstPartialSpec->setInstantiatedFromMember(PartialSpec);
InstPartialSpec->setTypeAsWritten(WrittenTy);

// Check the completed partial specialization.
SemaRef.CheckTemplatePartialSpecialization(InstPartialSpec);

Expand Down Expand Up @@ -4377,6 +4405,46 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
VarTemplate->findPartialSpecialization(CanonicalConverted, InstParams,
InsertPos);

// Build the canonical type that describes the converted template
// arguments of the variable template partial specialization.
QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
TemplateName(VarTemplate), CanonicalConverted);

// Build the fully-sugared type for this variable template
// specialization as the user wrote in the specialization
// itself. This means that we'll pretty-print the type retrieved
// from the specialization's declaration the way that the user
// 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 = SemaRef.Context.getTemplateSpecializationTypeInfo(
TemplateName(VarTemplate), PartialSpec->getLocation(), InstTemplateArgs,
CanonType);

if (PrevDecl) {
// We've already seen a partial specialization with the same template
// parameters and template arguments. This can happen, for example, when
// substituting the outer template arguments ends up causing two
// variable template partial specializations of a member variable template
// to have identical forms, e.g.,
//
// template<typename T, typename U>
// struct Outer {
// template<typename X, typename Y> pair<X,Y> p;
// template<typename Y> pair<T, Y> p;
// template<typename Y> pair<U, Y> p;
// };
//
// Outer<int, int> outer; // error: the partial specializations of Inner
// // have the same signature.
SemaRef.Diag(PartialSpec->getLocation(),
diag::err_var_partial_spec_redeclared)
<< WrittenTy->getType();
SemaRef.Diag(PrevDecl->getLocation(),
diag::note_var_prev_partial_spec_here);
return nullptr;
}

// Do substitution on the type of the declaration
TypeSourceInfo *DI = SemaRef.SubstType(
PartialSpec->getTypeSourceInfo(), TemplateArgs,
Expand All @@ -4396,39 +4464,16 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
VarTemplatePartialSpecializationDecl::Create(
SemaRef.Context, Owner, PartialSpec->getInnerLocStart(),
PartialSpec->getLocation(), InstParams, VarTemplate, DI->getType(),
DI, PartialSpec->getStorageClass(), CanonicalConverted);

InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs);
DI, PartialSpec->getStorageClass(), CanonicalConverted,
InstTemplateArgs);

// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
return nullptr;

InstPartialSpec->setInstantiatedFromMember(PartialSpec);
InstPartialSpec->setTypeAsWritten(WrittenTy);

if (PrevDecl) {
// We've already seen a partial specialization with the same template
// parameters and template arguments. This can happen, for example, when
// substituting the outer template arguments ends up causing two
// variable template partial specializations of a member variable template
// to have identical forms, e.g.,
//
// template<typename T, typename U>
// struct Outer {
// template<typename X, typename Y> pair<X,Y> p;
// template<typename Y> pair<T, Y> p;
// template<typename Y> pair<U, Y> p;
// };
//
// Outer<int, int> outer; // error: the partial specializations of Inner
// // have the same signature.
SemaRef.Diag(PartialSpec->getLocation(),
diag::err_var_partial_spec_redeclared)
<< InstPartialSpec;
SemaRef.Diag(PrevDecl->getLocation(),
diag::note_var_prev_partial_spec_here);
return nullptr;
}
// Check the completed partial specialization.
SemaRef.CheckTemplatePartialSpecialization(InstPartialSpec);

Expand Down Expand Up @@ -5690,7 +5735,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,

TemplateArgumentListInfo TemplateArgInfo;
if (const ASTTemplateArgumentListInfo *ArgInfo =
VarSpec->getTemplateArgsAsWritten()) {
VarSpec->getTemplateArgsInfo()) {
TemplateArgInfo.setLAngleLoc(ArgInfo->getLAngleLoc());
TemplateArgInfo.setRAngleLoc(ArgInfo->getRAngleLoc());
for (const TemplateArgumentLoc &Arg : ArgInfo->arguments())
Expand Down
28 changes: 14 additions & 14 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2548,17 +2548,16 @@ ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
}
}

// extern/template keyword locations for explicit instantiations
if (Record.readBool()) {
auto *ExplicitInfo = new (C) ExplicitInstantiationInfo;
ExplicitInfo->ExternKeywordLoc = readSourceLocation();
// Explicit info.
if (TypeSourceInfo *TyInfo = readTypeSourceInfo()) {
auto *ExplicitInfo =
new (C) ClassTemplateSpecializationDecl::ExplicitSpecializationInfo;
ExplicitInfo->TypeAsWritten = TyInfo;
ExplicitInfo->ExternLoc = readSourceLocation();
ExplicitInfo->TemplateKeywordLoc = readSourceLocation();
D->ExplicitInfo = ExplicitInfo;
}

if (Record.readBool())
D->setTemplateArgsAsWritten(Record.readASTTemplateArgumentListInfo());

return Redecl;
}

Expand All @@ -2568,6 +2567,7 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
// need them for profiling
TemplateParameterList *Params = Record.readTemplateParameterList();
D->TemplateParams = Params;
D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();

RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);

Expand Down Expand Up @@ -2617,17 +2617,16 @@ ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
}
}

// extern/template keyword locations for explicit instantiations
if (Record.readBool()) {
auto *ExplicitInfo = new (C) ExplicitInstantiationInfo;
ExplicitInfo->ExternKeywordLoc = readSourceLocation();
// Explicit info.
if (TypeSourceInfo *TyInfo = readTypeSourceInfo()) {
auto *ExplicitInfo =
new (C) VarTemplateSpecializationDecl::ExplicitSpecializationInfo;
ExplicitInfo->TypeAsWritten = TyInfo;
ExplicitInfo->ExternLoc = readSourceLocation();
ExplicitInfo->TemplateKeywordLoc = readSourceLocation();
D->ExplicitInfo = ExplicitInfo;
}

if (Record.readBool())
D->setTemplateArgsAsWritten(Record.readASTTemplateArgumentListInfo());

SmallVector<TemplateArgument, 8> TemplArgs;
Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true);
D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs);
Expand Down Expand Up @@ -2667,6 +2666,7 @@ void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
VarTemplatePartialSpecializationDecl *D) {
TemplateParameterList *Params = Record.readTemplateParameterList();
D->TemplateParams = Params;
D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();

RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);

Expand Down
36 changes: 10 additions & 26 deletions clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1765,28 +1765,20 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
Record.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl());
}

bool ExplicitInstantiation =
D->getTemplateSpecializationKind() ==
TSK_ExplicitInstantiationDeclaration ||
D->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition;
Record.push_back(ExplicitInstantiation);
if (ExplicitInstantiation) {
Record.AddSourceLocation(D->getExternKeywordLoc());
// Explicit info.
Record.AddTypeSourceInfo(D->getTypeAsWritten());
if (D->getTypeAsWritten()) {
Record.AddSourceLocation(D->getExternLoc());
Record.AddSourceLocation(D->getTemplateKeywordLoc());
}

const ASTTemplateArgumentListInfo *ArgsWritten =
D->getTemplateArgsAsWritten();
Record.push_back(!!ArgsWritten);
if (ArgsWritten)
Record.AddASTTemplateArgumentListInfo(ArgsWritten);

Code = serialization::DECL_CLASS_TEMPLATE_SPECIALIZATION;
}

void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D) {
Record.AddTemplateParameterList(D->getTemplateParameters());
Record.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten());

VisitClassTemplateSpecializationDecl(D);

Expand Down Expand Up @@ -1820,22 +1812,13 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
Record.AddTemplateArgumentList(&D->getTemplateInstantiationArgs());
}

bool ExplicitInstantiation =
D->getTemplateSpecializationKind() ==
TSK_ExplicitInstantiationDeclaration ||
D->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition;
Record.push_back(ExplicitInstantiation);
if (ExplicitInstantiation) {
Record.AddSourceLocation(D->getExternKeywordLoc());
// Explicit info.
Record.AddTypeSourceInfo(D->getTypeAsWritten());
if (D->getTypeAsWritten()) {
Record.AddSourceLocation(D->getExternLoc());
Record.AddSourceLocation(D->getTemplateKeywordLoc());
}

const ASTTemplateArgumentListInfo *ArgsWritten =
D->getTemplateArgsAsWritten();
Record.push_back(!!ArgsWritten);
if (ArgsWritten)
Record.AddASTTemplateArgumentListInfo(ArgsWritten);

Record.AddTemplateArgumentList(&D->getTemplateArgs());
Record.AddSourceLocation(D->getPointOfInstantiation());
Record.push_back(D->getSpecializationKind());
Expand All @@ -1856,6 +1839,7 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
VarTemplatePartialSpecializationDecl *D) {
Record.AddTemplateParameterList(D->getTemplateParameters());
Record.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten());

VisitVarTemplateSpecializationDecl(D);

Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Tooling/Syntax/BuildTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -735,8 +735,7 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
auto *Declaration =
cast<syntax::SimpleDeclaration>(handleFreeStandingTagDecl(C));
foldExplicitTemplateInstantiation(
Builder.getTemplateRange(C),
Builder.findToken(C->getExternKeywordLoc()),
Builder.getTemplateRange(C), Builder.findToken(C->getExternLoc()),
Builder.findToken(C->getTemplateKeywordLoc()), Declaration, C);
return true;
}
Expand Down
18 changes: 11 additions & 7 deletions clang/test/AST/ast-dump-template-decls.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Test without serialization:
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown -ast-dump %s \
// RUN: | FileCheck -strict-whitespace %s
// RUN: | FileCheck -strict-whitespace %s --check-prefix=DIRECT
//
// Test with serialization:
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown -emit-pch -o %t %s
// RUN: %clang_cc1 -x c++ -std=c++17 -triple x86_64-unknown-unknown -include-pch %t -ast-dump-all /dev/null \
// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
// RUN: | FileCheck --strict-whitespace %s
// RUN: | FileCheck --strict-whitespace %s --check-prefix=SERIALIZED

template <typename Ty>
// CHECK: FunctionTemplateDecl 0x{{[^ ]*}} <{{.*}}:1, line:[[@LINE+2]]:10> col:6 a
Expand Down Expand Up @@ -189,13 +189,15 @@ T unTempl = 1;

template<>
int unTempl<int>;
// CHECK: VarTemplateSpecializationDecl 0x{{[^ ]*}} <line:{{[0-9]+}}:1, line:{{[0-9]+}}:16> col:5 unTempl 'int'
// FIXME (#61680) - serializing and loading AST should not affect reported source range
// DIRECT: VarTemplateSpecializationDecl 0x{{[^ ]*}} <line:{{[0-9]+}}:1, line:{{[0-9]+}}:16> col:5 unTempl 'int'
// SERIALIZED: VarTemplateSpecializationDecl 0x{{[^ ]*}} <line:{{[0-9]+}}:1, line:{{[0-9]+}}:5> col:5 unTempl 'int'
// CHECK-NEXT: `-TemplateArgument type 'int'
// CHECK-NEXT: `-BuiltinType 0x{{[^ ]*}} 'int'

template<>
float unTempl<float> = 1;
// CHECK: VarTemplateSpecializationDecl 0x{{[^ ]*}} <line:{{[0-9]+}}:1, line:{{[0-9]+}}:24> col:7 unTempl 'float'
// CHECK: VarTemplateSpecializationDecl 0x{{[^ ]*}} <line:{{[0-9]+}}:1, line:{{[0-9]+}}:24> col:7 unTempl 'float' cinit
// CHECK-NEXT: |-TemplateArgument type 'float'
// CHECK-NEXT: | `-BuiltinType 0x{{[^ ]*}} 'float'
// CHECK-NEXT: `-ImplicitCastExpr 0x{{[^ ]*}} <col:24> 'float' <IntegralToFloating>
Expand All @@ -220,7 +222,7 @@ int binTempl<int, U>;

template<class U>
float binTempl<float, U> = 1;
// CHECK: VarTemplatePartialSpecializationDecl 0x{{[^ ]*}} <line:{{[0-9]+}}:1, line:{{[0-9]+}}:28> col:7 binTempl 'float'
// CHECK: VarTemplatePartialSpecializationDecl 0x{{[^ ]*}} <line:{{[0-9]+}}:1, line:{{[0-9]+}}:24> col:7 binTempl 'float' cinit
// CHECK-NEXT: |-TemplateTypeParmDecl 0x{{[^ ]*}} <line:{{[0-9]+}}:10, col:16> col:16 referenced class depth 0 index 0 U
// CHECK-NEXT: |-TemplateArgument type 'float'
// CHECK-NEXT: | `-BuiltinType 0x{{[^ ]*}} 'float'
Expand All @@ -231,15 +233,17 @@ float binTempl<float, U> = 1;

template<>
int binTempl<int, int>;
// CHECK: VarTemplateSpecializationDecl 0x{{[^ ]*}} <line:{{[0-9]+}}:1, line:{{[0-9]+}}:22> col:5 binTempl 'int'
// FIXME (#61680) - serializing and loading AST should not affect reported source range
// DIRECT: VarTemplateSpecializationDecl 0x{{[^ ]*}} <line:{{[0-9]+}}:1, line:{{[0-9]+}}:22> col:5 binTempl 'int'
// SERIALIZED: VarTemplateSpecializationDecl 0x{{[^ ]*}} <line:{{[0-9]+}}:1, line:{{[0-9]+}}:5> col:5 binTempl 'int'
// CHECK-NEXT: |-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType 0x{{[^ ]*}} 'int'
// CHECK-NEXT: `-TemplateArgument type 'int'
// CHECK-NEXT: `-BuiltinType 0x{{[^ ]*}} 'int'

template<>
float binTempl<float, float> = 1;
// CHECK: VarTemplateSpecializationDecl 0x{{[^ ]*}} <line:{{[0-9]+}}:1, line:{{[0-9]+}}:32> col:7 binTempl 'float'
// CHECK: VarTemplateSpecializationDecl 0x{{[^ ]*}} <line:{{[0-9]+}}:1, line:{{[0-9]+}}:32> col:7 binTempl 'float' cinit
// CHECK-NEXT: |-TemplateArgument type 'float'
// CHECK-NEXT: | `-BuiltinType 0x{{[^ ]*}} 'float'
// CHECK-NEXT: |-TemplateArgument type 'float'
Expand Down
24 changes: 11 additions & 13 deletions clang/test/Index/Core/index-source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,28 +285,30 @@ template<>
class SpecializationDecl<int>;
// CHECK: [[@LINE-1]]:7 | class(Gen,TS)/C++ | SpecializationDecl | c:@S@SpecializationDecl>#I | <no-cgname> | Decl,RelSpecialization | rel: 1
// CHECK-NEXT: RelSpecialization | SpecializationDecl | c:@ST>1#T@SpecializationDecl
// CHECK: [[@LINE-3]]:7 | class(Gen,TS)/C++ | SpecializationDecl | c:@S@SpecializationDecl>#I | <no-cgname> | Ref | rel: 0

template<>
class SpecializationDecl<int> { };
// CHECK: [[@LINE-1]]:7 | class(Gen,TS)/C++ | SpecializationDecl | c:@S@SpecializationDecl>#I | <no-cgname> | Def,RelSpecialization | rel: 1
// CHECK-NEXT: RelSpecialization | SpecializationDecl | c:@ST>1#T@SpecializationDecl
// CHECK-NEXT: [[@LINE-3]]:7 | class(Gen,TS)/C++ | SpecializationDecl | c:@S@SpecializationDecl>#I | <no-cgname> | Ref | rel: 0

template<typename T>
class PartialSpecilizationClass<Cls, T>;
// CHECK: [[@LINE-1]]:7 | class(Gen,TPS)/C++ | PartialSpecilizationClass | c:@SP>1#T@PartialSpecilizationClass>#$@S@Cls#t0.0 | <no-cgname> | Decl,RelSpecialization | rel: 1
// CHECK-NEXT: RelSpecialization | PartialSpecilizationClass | c:@ST>2#T#T@PartialSpecilizationClass
// CHECK-NEXT: [[@LINE-3]]:33 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
// CHECK: [[@LINE-3]]:7 | class(Gen)/C++ | PartialSpecilizationClass | c:@ST>2#T#T@PartialSpecilizationClass | <no-cgname> | Ref | rel: 0
// CHECK-NEXT: [[@LINE-4]]:33 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref | rel: 0

template<>
class PartialSpecilizationClass<Cls, Cls> : Cls { };
// CHECK: [[@LINE-1]]:7 | class(Gen,TS)/C++ | PartialSpecilizationClass | c:@S@PartialSpecilizationClass>#$@S@Cls#S0_ | <no-cgname> | Def,RelSpecialization | rel: 1
// CHECK-NEXT: RelSpecialization | PartialSpecilizationClass | c:@ST>2#T#T@PartialSpecilizationClass
// CHECK-NEXT: [[@LINE-3]]:45 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelBase,RelCont | rel: 1
// CHECK-NEXT: RelBase,RelCont | PartialSpecilizationClass | c:@S@PartialSpecilizationClass>#$@S@Cls#S0_
// CHECK-NEXT: [[@LINE-5]]:33 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
// CHECK-NEXT: RelCont | PartialSpecilizationClass | c:@S@PartialSpecilizationClass>#$@S@Cls#S0_
// CHECK-NEXT: [[@LINE-7]]:38 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
// CHECK-NEXT: RelCont | PartialSpecilizationClass | c:@S@PartialSpecilizationClass>#$@S@Cls#S0_
// CHECK-NEXT: [[@LINE-5]]:7 | class(Gen,TS)/C++ | PartialSpecilizationClass | c:@S@PartialSpecilizationClass>#$@S@Cls#S0_ | <no-cgname> | Ref | rel: 0
// CHECK-NEXT: [[@LINE-6]]:33 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref | rel: 0
// CHECK-NEXT: [[@LINE-7]]:38 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref | rel: 0

template<typename T, int x>
void functionSp() { }
Expand All @@ -330,14 +332,10 @@ class ClassWithCorrectSpecialization { };

template<>
class ClassWithCorrectSpecialization<SpecializationDecl<Cls>, Record::C> { };
// CHECK: [[@LINE-1]]:38 | class(Gen)/C++ | SpecializationDecl | c:@ST>1#T@SpecializationDecl | <no-cgname> | Ref,RelCont | rel: 1
// CHECK-NEXT: RelCont | ClassWithCorrectSpecialization | c:@S@ClassWithCorrectSpecialization>#$@S@SpecializationDecl>#$@S@Cls#VI2
// CHECK-NEXT: [[@LINE-3]]:57 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
// CHECK-NEXT: RelCont | ClassWithCorrectSpecialization | c:@S@ClassWithCorrectSpecialization>#$@S@SpecializationDecl>#$@S@Cls#VI2
// CHECK-NEXT: [[@LINE-5]]:71 | static-property/C++ | C | c:@S@Record@C | __ZN6Record1CE | Ref,Read,RelCont | rel: 1
// CHECK-NEXT: RelCont | ClassWithCorrectSpecialization | c:@S@ClassWithCorrectSpecialization>#$@S@SpecializationDecl>#$@S@Cls#VI2
// CHECK-NEXT: [[@LINE-7]]:63 | struct/C++ | Record | c:@S@Record | <no-cgname> | Ref,RelCont | rel: 1
// CHECK-NEXT: RelCont | ClassWithCorrectSpecialization | c:@S@ClassWithCorrectSpecialization>#$@S@SpecializationDecl>#$@S@Cls#VI2
// CHECK: [[@LINE-1]]:38 | class(Gen)/C++ | SpecializationDecl | c:@ST>1#T@SpecializationDecl | <no-cgname> | Ref | rel: 0
// CHECK: [[@LINE-2]]:57 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref | rel: 0
// CHECK: [[@LINE-3]]:71 | static-property/C++ | C | c:@S@Record@C | __ZN6Record1CE | Ref,Read | rel: 0
// CHECK: [[@LINE-4]]:63 | struct/C++ | Record | c:@S@Record | <no-cgname> | Ref | rel: 0

namespace ns {
// CHECK: [[@LINE-1]]:11 | namespace/C++ | ns | c:@N@ns | <no-cgname> | Decl | rel: 0
Expand Down
1 change: 1 addition & 0 deletions clang/test/Index/index-refs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ int ginitlist[] = {EnumVal};
// CHECK: [indexDeclaration]: kind: c++-class-template | name: TS | {{.*}} | loc: 47:8
// CHECK-NEXT: [indexDeclaration]: kind: struct-template-partial-spec | name: TS | USR: c:@SP>1#T@TS>#t0.0#I | {{.*}} | loc: 50:8
// CHECK-NEXT: [indexDeclaration]: kind: typedef | name: MyInt | USR: c:index-refs.cpp@SP>1#T@TS>#t0.0#I@T@MyInt | {{.*}} | loc: 51:15 | semantic-container: [TS:50:8] | lexical-container: [TS:50:8]
// CHECK-NEXT: [indexEntityReference]: kind: c++-class-template | name: TS | USR: c:@ST>2#T#T@TS | lang: C++ | cursor: TemplateRef=TS:47:8 | loc: 50:8 | <parent>:: <<NULL>> | container: [TU] | refkind: direct | role: ref
/* when indexing implicit instantiations
[indexDeclaration]: kind: struct-template-spec | name: TS | USR: c:@S@TS>#I | {{.*}} | loc: 50:8
[indexDeclaration]: kind: typedef | name: MyInt | USR: c:index-refs.cpp@593@S@TS>#I@T@MyInt | {{.*}} | loc: 51:15 | semantic-container: [TS:50:8] | lexical-container: [TS:50:8]
Expand Down
29 changes: 15 additions & 14 deletions clang/tools/libclang/CIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -743,10 +743,14 @@ bool CursorVisitor::VisitClassTemplateSpecializationDecl(
}

// Visit the template arguments used in the specialization.
if (const auto *ArgsWritten = D->getTemplateArgsAsWritten()) {
for (const TemplateArgumentLoc &Arg : ArgsWritten->arguments())
if (VisitTemplateArgumentLoc(Arg))
return true;
if (TypeSourceInfo *SpecType = D->getTypeAsWritten()) {
TypeLoc TL = SpecType->getTypeLoc();
if (TemplateSpecializationTypeLoc TSTLoc =
TL.getAs<TemplateSpecializationTypeLoc>()) {
for (unsigned I = 0, N = TSTLoc.getNumArgs(); I != N; ++I)
if (VisitTemplateArgumentLoc(TSTLoc.getArgLoc(I)))
return true;
}
}

return ShouldVisitBody && VisitCXXRecordDecl(D);
Expand Down Expand Up @@ -5655,19 +5659,16 @@ CXString clang_getCursorDisplayName(CXCursor C) {

if (const ClassTemplateSpecializationDecl *ClassSpec =
dyn_cast<ClassTemplateSpecializationDecl>(D)) {
// If the type was explicitly written, use that.
if (TypeSourceInfo *TSInfo = ClassSpec->getTypeAsWritten())
return cxstring::createDup(TSInfo->getType().getAsString(Policy));

SmallString<128> Str;
llvm::raw_svector_ostream OS(Str);
OS << *ClassSpec;
// If the template arguments were written explicitly, use them..
if (const auto *ArgsWritten = ClassSpec->getTemplateArgsAsWritten()) {
printTemplateArgumentList(
OS, ArgsWritten->arguments(), Policy,
ClassSpec->getSpecializedTemplate()->getTemplateParameters());
} else {
printTemplateArgumentList(
OS, ClassSpec->getTemplateArgs().asArray(), Policy,
ClassSpec->getSpecializedTemplate()->getTemplateParameters());
}
printTemplateArgumentList(
OS, ClassSpec->getTemplateArgs().asArray(), Policy,
ClassSpec->getSpecializedTemplate()->getTemplateParameters());
return cxstring::createDup(OS.str());
}

Expand Down
12 changes: 12 additions & 0 deletions clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2213,6 +2213,18 @@ TEST_P(ASTMatchersTest, ReferenceTypeLocTest_BindsToAnyRvalueReferenceTypeLoc) {
EXPECT_TRUE(matches("float&& r = 3.0;", matcher));
}

TEST_P(
ASTMatchersTest,
TemplateSpecializationTypeLocTest_BindsToTemplateSpecializationExplicitInstantiation) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(
matches("template <typename T> class C {}; template class C<int>;",
classTemplateSpecializationDecl(
hasName("C"), hasTypeLoc(templateSpecializationTypeLoc()))));
}

TEST_P(ASTMatchersTest,
TemplateSpecializationTypeLocTest_BindsToVarDeclTemplateSpecialization) {
if (!GetParam().isCXX()) {
Expand Down
92 changes: 57 additions & 35 deletions clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,12 @@ TEST(HasTypeLoc, MatchesCXXUnresolvedConstructExpr) {
cxxUnresolvedConstructExpr(hasTypeLoc(loc(asString("T"))))));
}

TEST(HasTypeLoc, MatchesClassTemplateSpecializationDecl) {
EXPECT_TRUE(matches(
"template <typename T> class Foo; template <> class Foo<int> {};",
classTemplateSpecializationDecl(hasTypeLoc(loc(asString("Foo<int>"))))));
}

TEST(HasTypeLoc, MatchesCompoundLiteralExpr) {
EXPECT_TRUE(
matches("int* x = (int[2]) { 0, 1 };",
Expand Down Expand Up @@ -6378,7 +6384,8 @@ TEST(HasAnyTemplateArgumentLoc, BindsToExplicitSpecializationWithIntArgument) {
"template<typename T> class A {}; template<> class A<int> {};",
classTemplateSpecializationDecl(
hasName("A"),
hasAnyTemplateArgumentLoc(hasTypeLoc(loc(asString("int")))))));
hasTypeLoc(templateSpecializationTypeLoc(
hasAnyTemplateArgumentLoc(hasTypeLoc(loc(asString("int")))))))));
}

TEST(HasAnyTemplateArgumentLoc,
Expand All @@ -6387,7 +6394,8 @@ TEST(HasAnyTemplateArgumentLoc,
"template<typename T> class A {}; template<> class A<double> {};",
classTemplateSpecializationDecl(
hasName("A"),
hasAnyTemplateArgumentLoc(hasTypeLoc(loc(asString("double")))))));
hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
hasTypeLoc(loc(asString("double")))))))));
}

TEST(HasAnyTemplateArgumentLoc, BindsToSpecializationWithMultipleArguments) {
Expand All @@ -6397,20 +6405,24 @@ TEST(HasAnyTemplateArgumentLoc, BindsToSpecializationWithMultipleArguments) {
)";
EXPECT_TRUE(
matches(code, classTemplateSpecializationDecl(
hasName("A"), hasAnyTemplateArgumentLoc(hasTypeLoc(
loc(asString("double")))))));

hasName("A"), hasTypeLoc(templateSpecializationTypeLoc(
hasAnyTemplateArgumentLoc(hasTypeLoc(
loc(asString("double")))))))));
EXPECT_TRUE(matches(
code, classTemplateSpecializationDecl(
hasName("A"),
hasAnyTemplateArgumentLoc(hasTypeLoc(loc(asString("int")))))));
code,
classTemplateSpecializationDecl(
hasName("A"),
hasTypeLoc(templateSpecializationTypeLoc(
hasAnyTemplateArgumentLoc(hasTypeLoc(loc(asString("int")))))))));
}

TEST(HasAnyTemplateArgumentLoc, DoesNotBindToSpecializationWithIntArgument) {
EXPECT_TRUE(notMatches("template<typename T> class A {}; A<int> a;",
classTemplateSpecializationDecl(
hasName("A"), hasAnyTemplateArgumentLoc(hasTypeLoc(
loc(asString("double")))))));
EXPECT_TRUE(notMatches(
"template<typename T> class A {}; A<int> a;",
classTemplateSpecializationDecl(
hasName("A"),
hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
hasTypeLoc(loc(asString("double")))))))));
}

TEST(HasAnyTemplateArgumentLoc,
Expand All @@ -6419,7 +6431,8 @@ TEST(HasAnyTemplateArgumentLoc,
"template<typename T> class A {}; template<> class A<int> {};",
classTemplateSpecializationDecl(
hasName("A"),
hasAnyTemplateArgumentLoc(hasTypeLoc(loc(asString("double")))))));
hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
hasTypeLoc(loc(asString("double")))))))));
}

TEST(HasTemplateArgumentLoc, BindsToSpecializationWithIntArgument) {
Expand All @@ -6440,29 +6453,22 @@ TEST(HasTemplateArgumentLoc, BindsToSpecializationWithDoubleArgument) {
0, hasTypeLoc(loc(asString("double")))))))))));
}

TEST(HasTemplateArgumentLoc, DoesNotBindToSpecializationWithIntArgument) {
EXPECT_TRUE(notMatches(
"template<typename T> class A {}; A<int> a;",
varDecl(hasName("a"),
hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc(
templateSpecializationTypeLoc(hasTemplateArgumentLoc(
0, hasTypeLoc(loc(asString("double")))))))))));
}

TEST(HasTemplateArgumentLoc, BindsToExplicitSpecializationWithIntArgument) {
EXPECT_TRUE(matches(
"template<typename T> class A {}; template<> class A<int> {};",
classTemplateSpecializationDecl(
hasName("A"),
hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("int")))))));
hasTypeLoc(templateSpecializationTypeLoc(
hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("int")))))))));
}

TEST(HasTemplateArgumentLoc, BindsToExplicitSpecializationWithDoubleArgument) {
EXPECT_TRUE(matches(
"template<typename T> class A {}; template<> class A<double> {};",
classTemplateSpecializationDecl(
hasName("A"),
hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("double")))))));
hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(
0, hasTypeLoc(loc(asString("double")))))))));
}

TEST(HasTemplateArgumentLoc, BindsToSpecializationWithMultipleArguments) {
Expand All @@ -6472,12 +6478,23 @@ TEST(HasTemplateArgumentLoc, BindsToSpecializationWithMultipleArguments) {
)";
EXPECT_TRUE(matches(
code, classTemplateSpecializationDecl(
hasName("A"), hasTemplateArgumentLoc(
0, hasTypeLoc(loc(asString("double")))))));
hasName("A"),
hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(
0, hasTypeLoc(loc(asString("double")))))))));
EXPECT_TRUE(matches(
code, classTemplateSpecializationDecl(
hasName("A"),
hasTemplateArgumentLoc(1, hasTypeLoc(loc(asString("int")))))));
hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(
1, hasTypeLoc(loc(asString("int")))))))));
}

TEST(HasTemplateArgumentLoc, DoesNotBindToSpecializationWithIntArgument) {
EXPECT_TRUE(notMatches(
"template<typename T> class A {}; A<int> a;",
classTemplateSpecializationDecl(
hasName("A"),
hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(
0, hasTypeLoc(loc(asString("double")))))))));
}

TEST(HasTemplateArgumentLoc,
Expand All @@ -6486,7 +6503,8 @@ TEST(HasTemplateArgumentLoc,
"template<typename T> class A {}; template<> class A<int> {};",
classTemplateSpecializationDecl(
hasName("A"),
hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("double")))))));
hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(
0, hasTypeLoc(loc(asString("double")))))))));
}

TEST(HasTemplateArgumentLoc,
Expand All @@ -6497,12 +6515,14 @@ TEST(HasTemplateArgumentLoc,
)";
EXPECT_TRUE(notMatches(
code, classTemplateSpecializationDecl(
hasName("A"), hasTemplateArgumentLoc(
1, hasTypeLoc(loc(asString("double")))))));
hasName("A"),
hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(
1, hasTypeLoc(loc(asString("double")))))))));
EXPECT_TRUE(notMatches(
code, classTemplateSpecializationDecl(
hasName("A"),
hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("int")))))));
hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(
0, hasTypeLoc(loc(asString("int")))))))));
}

TEST(HasTemplateArgumentLoc, DoesNotBindWithBadIndex) {
Expand All @@ -6512,12 +6532,14 @@ TEST(HasTemplateArgumentLoc, DoesNotBindWithBadIndex) {
)";
EXPECT_TRUE(notMatches(
code, classTemplateSpecializationDecl(
hasName("A"), hasTemplateArgumentLoc(
-1, hasTypeLoc(loc(asString("double")))))));
hasName("A"),
hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(
-1, hasTypeLoc(loc(asString("double")))))))));
EXPECT_TRUE(notMatches(
code, classTemplateSpecializationDecl(
hasName("A"), hasTemplateArgumentLoc(
100, hasTypeLoc(loc(asString("int")))))));
hasName("A"),
hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(
100, hasTypeLoc(loc(asString("int")))))))));
}

TEST(HasTemplateArgumentLoc, BindsToDeclRefExprWithIntArgument) {
Expand Down