From: John McCall Date: Thu, 30 Jun 2011 08:33:18 +0000 (+0000) Subject: Preserve that a TemplateName was arrived at by substituting X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=146060435c3efce95c95a092c7a1eb651cfb9ae0;p=clang Preserve that a TemplateName was arrived at by substituting for a template template parameter. Uses to follow. I've also made the uniquing of SubstTemplateTemplateParmPacks use a ContextualFoldingSet as a minor space efficiency. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@134137 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 468343d2a0..a761ba3449 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -124,7 +124,10 @@ class ASTContext : public llvm::RefCountedBase { mutable llvm::FoldingSet QualifiedTemplateNames; mutable llvm::FoldingSet DependentTemplateNames; - mutable llvm::FoldingSet + mutable llvm::FoldingSet + SubstTemplateTemplateParms; + mutable llvm::ContextualFoldingSet SubstTemplateTemplateParmPacks; /// \brief The set of nested name specifiers. @@ -1019,6 +1022,8 @@ public: const IdentifierInfo *Name) const; TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, OverloadedOperatorKind Operator) const; + TemplateName getSubstTemplateTemplateParm(TemplateTemplateParmDecl *param, + TemplateName replacement) const; TemplateName getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, const TemplateArgument &ArgPack) const; diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h index 1721973e82..db4612990f 100644 --- a/include/clang/AST/TemplateName.h +++ b/include/clang/AST/TemplateName.h @@ -33,6 +33,7 @@ class OverloadedTemplateStorage; struct PrintingPolicy; class QualifiedTemplateName; class NamedDecl; +class SubstTemplateTemplateParmStorage; class SubstTemplateTemplateParmPackStorage; class TemplateArgument; class TemplateDecl; @@ -42,38 +43,49 @@ class TemplateTemplateParmDecl; /// template names or an already-substituted template template parameter pack. class UncommonTemplateNameStorage { protected: + enum Kind { + Overloaded, + SubstTemplateTemplateParm, + SubstTemplateTemplateParmPack + }; + union { struct { - /// \brief If true, this is an OverloadedTemplateStorage instance; - /// otherwise, it's a SubstTemplateTemplateParmPackStorage instance. - unsigned IsOverloadedStorage : 1; + /// \brief A Kind. + unsigned Kind : 2; /// \brief The number of stored templates or template arguments, /// depending on which subclass we have. - unsigned Size : 31; + unsigned Size : 30; } Bits; void *PointerAlignment; }; - UncommonTemplateNameStorage(unsigned Size, bool OverloadedStorage) { - Bits.IsOverloadedStorage = OverloadedStorage; - Bits.Size = Size; + UncommonTemplateNameStorage(Kind kind, unsigned size) { + Bits.Kind = kind; + Bits.Size = size; } public: unsigned size() const { return Bits.Size; } OverloadedTemplateStorage *getAsOverloadedStorage() { - return Bits.IsOverloadedStorage + return Bits.Kind == Overloaded ? reinterpret_cast(this) : 0; } + SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() { + return Bits.Kind == SubstTemplateTemplateParm + ? reinterpret_cast(this) + : 0; + } + SubstTemplateTemplateParmPackStorage *getAsSubstTemplateTemplateParmPack() { - return Bits.IsOverloadedStorage - ? 0 - : reinterpret_cast(this) ; + return Bits.Kind == SubstTemplateTemplateParmPack + ? reinterpret_cast(this) + : 0; } }; @@ -82,8 +94,8 @@ public: class OverloadedTemplateStorage : public UncommonTemplateNameStorage { friend class ASTContext; - OverloadedTemplateStorage(unsigned Size) - : UncommonTemplateNameStorage(Size, true) { } + OverloadedTemplateStorage(unsigned size) + : UncommonTemplateNameStorage(Overloaded, size) { } NamedDecl **getStorage() { return reinterpret_cast(this + 1); @@ -98,8 +110,7 @@ public: iterator begin() const { return getStorage(); } iterator end() const { return getStorage() + size(); } }; - - + /// \brief A structure for storing an already-substituted template template /// parameter pack. /// @@ -109,16 +120,14 @@ public: class SubstTemplateTemplateParmPackStorage : public UncommonTemplateNameStorage, public llvm::FoldingSetNode { - ASTContext &Context; TemplateTemplateParmDecl *Parameter; const TemplateArgument *Arguments; public: - SubstTemplateTemplateParmPackStorage(ASTContext &Context, - TemplateTemplateParmDecl *Parameter, + SubstTemplateTemplateParmPackStorage(TemplateTemplateParmDecl *Parameter, unsigned Size, const TemplateArgument *Arguments) - : UncommonTemplateNameStorage(Size, false), Context(Context), + : UncommonTemplateNameStorage(SubstTemplateTemplateParmPack, Size), Parameter(Parameter), Arguments(Arguments) { } /// \brief Retrieve the template template parameter pack being substituted. @@ -130,9 +139,10 @@ public: /// parameter was substituted. TemplateArgument getArgumentPack() const; - void Profile(llvm::FoldingSetNodeID &ID); + void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context); - static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, + static void Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context, TemplateTemplateParmDecl *Parameter, const TemplateArgument &ArgPack); }; @@ -189,6 +199,9 @@ public: /// \brief A dependent template name that has not been resolved to a /// template (or set of templates). DependentTemplate, + /// \brief A template template parameter that has been substituted + /// for some other template name. + SubstTemplateTemplateParm, /// \brief A template template parameter pack that has been substituted for /// a template template argument pack, but has not yet been expanded into /// individual arguments. @@ -199,6 +212,7 @@ public: explicit TemplateName(TemplateDecl *Template) : Storage(Template) { } explicit TemplateName(OverloadedTemplateStorage *Storage) : Storage(Storage) { } + explicit TemplateName(SubstTemplateTemplateParmStorage *Storage); explicit TemplateName(SubstTemplateTemplateParmPackStorage *Storage) : Storage(Storage) { } explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { } @@ -234,6 +248,19 @@ public: return 0; } + /// \brief Retrieve the substituted template template parameter, if + /// known. + /// + /// \returns The storage for the substituted template template parameter, + /// if known. Otherwise, returns NULL. + SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() const { + if (UncommonTemplateNameStorage *uncommon = + Storage.dyn_cast()) + return uncommon->getAsSubstTemplateTemplateParm(); + + return 0; + } + /// \brief Retrieve the substituted template template parameter pack, if /// known. /// @@ -260,6 +287,8 @@ public: return Storage.dyn_cast(); } + TemplateName getUnderlying() const; + /// \brief Determines whether this is a dependent template name. bool isDependent() const; @@ -300,6 +329,41 @@ public: const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, TemplateName N); +/// \brief A structure for storing the information associated with a +/// substituted template template parameter. +class SubstTemplateTemplateParmStorage + : public UncommonTemplateNameStorage, public llvm::FoldingSetNode { + friend class ASTContext; + + TemplateTemplateParmDecl *Parameter; + TemplateName Replacement; + + SubstTemplateTemplateParmStorage(TemplateTemplateParmDecl *parameter, + TemplateName replacement) + : UncommonTemplateNameStorage(SubstTemplateTemplateParm, 0), + Parameter(parameter), Replacement(replacement) {} + +public: + TemplateTemplateParmDecl *getParameter() const { return Parameter; } + TemplateName getReplacement() const { return Replacement; } + + void Profile(llvm::FoldingSetNodeID &ID); + + static void Profile(llvm::FoldingSetNodeID &ID, + TemplateTemplateParmDecl *parameter, + TemplateName replacement); +}; + +inline TemplateName::TemplateName(SubstTemplateTemplateParmStorage *Storage) + : Storage(Storage) { } + +inline TemplateName TemplateName::getUnderlying() const { + if (SubstTemplateTemplateParmStorage *subst + = getAsSubstTemplateTemplateParm()) + return subst->getReplacement().getUnderlying(); + return *this; +} + /// \brief Represents a template name that was expressed as a /// qualified name. /// diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 06daf24e30..06a9787d92 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -3457,8 +3457,10 @@ class TemplateSpecializationType /// \brief The name of the template being specialized. This is /// either a TemplateName::Template (in which case it is a /// ClassTemplateDecl*, a TemplateTemplateParmDecl*, or a - /// TypeAliasTemplateDecl*) or a - /// TemplateName::SubstTemplateTemplateParmPack. + /// TypeAliasTemplateDecl*), a + /// TemplateName::SubstTemplateTemplateParmPack, or a + /// TemplateName::SubstTemplateTemplateParm (in which case the + /// replacement must, recursively, be one of these). TemplateName Template; /// \brief - The number of template arguments named in this class diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 544fc1abab..ec064fc2f4 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -219,6 +219,7 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, FunctionProtoTypes(this_()), TemplateSpecializationTypes(this_()), DependentTemplateSpecializationTypes(this_()), + SubstTemplateTemplateParmPacks(this_()), GlobalNestedNameSpecifier(0), IsInt128Installed(false), CFConstantStringTypeDecl(0), NSConstantStringTypeDecl(0), ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), @@ -3036,11 +3037,21 @@ bool ASTContext::UnwrapSimilarPointerTypes(QualType &T1, QualType &T2) { DeclarationNameInfo ASTContext::getNameForTemplate(TemplateName Name, SourceLocation NameLoc) const { - if (TemplateDecl *TD = Name.getAsTemplateDecl()) + switch (Name.getKind()) { + case TemplateName::QualifiedTemplate: + case TemplateName::Template: // DNInfo work in progress: CHECKME: what about DNLoc? - return DeclarationNameInfo(TD->getDeclName(), NameLoc); + return DeclarationNameInfo(Name.getAsTemplateDecl()->getDeclName(), + NameLoc); - if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { + case TemplateName::OverloadedTemplate: { + OverloadedTemplateStorage *Storage = Name.getAsOverloadedTemplate(); + // DNInfo work in progress: CHECKME: what about DNLoc? + return DeclarationNameInfo((*Storage->begin())->getDeclName(), NameLoc); + } + + case TemplateName::DependentTemplate: { + DependentTemplateName *DTN = Name.getAsDependentTemplateName(); DeclarationName DName; if (DTN->isIdentifier()) { DName = DeclarationNames.getIdentifier(DTN->getIdentifier()); @@ -3055,36 +3066,64 @@ ASTContext::getNameForTemplate(TemplateName Name, } } - OverloadedTemplateStorage *Storage = Name.getAsOverloadedTemplate(); - assert(Storage); - // DNInfo work in progress: CHECKME: what about DNLoc? - return DeclarationNameInfo((*Storage->begin())->getDeclName(), NameLoc); + case TemplateName::SubstTemplateTemplateParm: { + SubstTemplateTemplateParmStorage *subst + = Name.getAsSubstTemplateTemplateParm(); + return DeclarationNameInfo(subst->getParameter()->getDeclName(), + NameLoc); + } + + case TemplateName::SubstTemplateTemplateParmPack: { + SubstTemplateTemplateParmPackStorage *subst + = Name.getAsSubstTemplateTemplateParmPack(); + return DeclarationNameInfo(subst->getParameterPack()->getDeclName(), + NameLoc); + } + } + + llvm_unreachable("bad template name kind!"); } TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) const { - if (TemplateDecl *Template = Name.getAsTemplateDecl()) { + switch (Name.getKind()) { + case TemplateName::QualifiedTemplate: + case TemplateName::Template: { + TemplateDecl *Template = Name.getAsTemplateDecl(); if (TemplateTemplateParmDecl *TTP - = dyn_cast(Template)) + = dyn_cast(Template)) Template = getCanonicalTemplateTemplateParmDecl(TTP); // The canonical template name is the canonical template declaration. return TemplateName(cast(Template->getCanonicalDecl())); } - if (SubstTemplateTemplateParmPackStorage *SubstPack - = Name.getAsSubstTemplateTemplateParmPack()) { - TemplateTemplateParmDecl *CanonParam - = getCanonicalTemplateTemplateParmDecl(SubstPack->getParameterPack()); - TemplateArgument CanonArgPack - = getCanonicalTemplateArgument(SubstPack->getArgumentPack()); - return getSubstTemplateTemplateParmPack(CanonParam, CanonArgPack); + case TemplateName::OverloadedTemplate: + llvm_unreachable("cannot canonicalize overloaded template"); + + case TemplateName::DependentTemplate: { + DependentTemplateName *DTN = Name.getAsDependentTemplateName(); + assert(DTN && "Non-dependent template names must refer to template decls."); + return DTN->CanonicalTemplateName; + } + + case TemplateName::SubstTemplateTemplateParm: { + SubstTemplateTemplateParmStorage *subst + = Name.getAsSubstTemplateTemplateParm(); + return getCanonicalTemplateName(subst->getReplacement()); } - - assert(!Name.getAsOverloadedTemplate()); - DependentTemplateName *DTN = Name.getAsDependentTemplateName(); - assert(DTN && "Non-dependent template names must refer to template decls."); - return DTN->CanonicalTemplateName; + case TemplateName::SubstTemplateTemplateParmPack: { + SubstTemplateTemplateParmPackStorage *subst + = Name.getAsSubstTemplateTemplateParmPack(); + TemplateTemplateParmDecl *canonParameter + = getCanonicalTemplateTemplateParmDecl(subst->getParameterPack()); + TemplateArgument canonArgPack + = getCanonicalTemplateArgument(subst->getArgumentPack()); + return getSubstTemplateTemplateParmPack(canonParameter, canonArgPack); + } + } + + llvm_unreachable("bad template name!"); } bool ASTContext::hasSameTemplateName(TemplateName X, TemplateName Y) { @@ -4790,6 +4829,24 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, return TemplateName(QTN); } +TemplateName +ASTContext::getSubstTemplateTemplateParm(TemplateTemplateParmDecl *param, + TemplateName replacement) const { + llvm::FoldingSetNodeID ID; + SubstTemplateTemplateParmStorage::Profile(ID, param, replacement); + + void *insertPos = 0; + SubstTemplateTemplateParmStorage *subst + = SubstTemplateTemplateParms.FindNodeOrInsertPos(ID, insertPos); + + if (!subst) { + subst = new (*this) SubstTemplateTemplateParmStorage(param, replacement); + SubstTemplateTemplateParms.InsertNode(subst, insertPos); + } + + return TemplateName(subst); +} + TemplateName ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, const TemplateArgument &ArgPack) const { @@ -4802,7 +4859,7 @@ ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, = SubstTemplateTemplateParmPacks.FindNodeOrInsertPos(ID, InsertPos); if (!Subst) { - Subst = new (*this) SubstTemplateTemplateParmPackStorage(Self, Param, + Subst = new (*this) SubstTemplateTemplateParmPackStorage(Param, ArgPack.pack_size(), ArgPack.pack_begin()); SubstTemplateTemplateParmPacks.InsertNode(Subst, InsertPos); diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 100e604d1c..9f5719f029 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -4201,6 +4201,20 @@ TemplateName ASTImporter::Import(TemplateName From) { return ToContext.getDependentTemplateName(Qualifier, DTN->getOperator()); } + + case TemplateName::SubstTemplateTemplateParm: { + SubstTemplateTemplateParmStorage *subst + = From.getAsSubstTemplateTemplateParm(); + TemplateTemplateParmDecl *param + = cast_or_null(Import(subst->getParameter())); + if (!param) + return TemplateName(); + + TemplateName replacement = Import(subst->getReplacement()); + if (replacement.isNull()) return TemplateName(); + + return ToContext.getSubstTemplateTemplateParm(param, replacement); + } case TemplateName::SubstTemplateTemplateParmPack: { SubstTemplateTemplateParmPackStorage *SubstPack diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 9f30f6e63a..0cbf1f7bdf 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -1369,6 +1369,10 @@ void CXXNameMangler::mangleType(TemplateName TN) { break; } + case TemplateName::SubstTemplateTemplateParm: + llvm_unreachable("mangling a substituted template name!"); + break; + case TemplateName::SubstTemplateTemplateParmPack: { SubstTemplateTemplateParmPackStorage *SubstPack = TN.getAsSubstTemplateTemplateParmPack(); diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index ebd07f4867..b22e4b4c0d 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -27,7 +27,19 @@ SubstTemplateTemplateParmPackStorage::getArgumentPack() const { return TemplateArgument(Arguments, size()); } -void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID) { +void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Parameter, Replacement); +} + +void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID, + TemplateTemplateParmDecl *parameter, + TemplateName replacement) { + ID.AddPointer(parameter); + ID.AddPointer(replacement.getAsVoidPointer()); +} + +void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context) { Profile(ID, Context, Parameter, TemplateArgument(Arguments, size())); } @@ -46,9 +58,14 @@ TemplateName::NameKind TemplateName::getKind() const { return DependentTemplate; if (Storage.is()) return QualifiedTemplate; - - return getAsOverloadedTemplate()? OverloadedTemplate - : SubstTemplateTemplateParmPack; + + UncommonTemplateNameStorage *uncommon + = Storage.get(); + if (uncommon->getAsOverloadedStorage()) + return OverloadedTemplate; + if (uncommon->getAsSubstTemplateTemplateParm()) + return SubstTemplateTemplateParm; + return SubstTemplateTemplateParmPack; } TemplateDecl *TemplateName::getAsTemplateDecl() const { @@ -58,6 +75,9 @@ TemplateDecl *TemplateName::getAsTemplateDecl() const { if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) return QTN->getTemplateDecl(); + if (SubstTemplateTemplateParmStorage *sub = getAsSubstTemplateTemplateParm()) + return sub->getReplacement().getAsTemplateDecl(); + return 0; } @@ -115,6 +135,9 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, OS << DTN->getIdentifier()->getName(); else OS << "operator " << getOperatorSpelling(DTN->getOperator()); + } else if (SubstTemplateTemplateParmStorage *subst + = getAsSubstTemplateTemplateParm()) { + subst->getReplacement().print(OS, Policy, SuppressNNS); } else if (SubstTemplateTemplateParmPackStorage *SubstPack = getAsSubstTemplateTemplateParmPack()) OS << SubstPack->getParameterPack()->getNameAsString(); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 68c3eeb892..1569173df7 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1764,6 +1764,7 @@ TemplateSpecializationType(TemplateName T, assert(!T.getAsDependentTemplateName() && "Use DependentTemplateSpecializationType for dependent template-name"); assert((T.getKind() == TemplateName::Template || + T.getKind() == TemplateName::SubstTemplateTemplateParm || T.getKind() == TemplateName::SubstTemplateTemplateParmPack) && "Unexpected template name for TemplateSpecializationType"); assert((!Canon.isNull() || diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 3b4ccac416..d88b785762 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1861,7 +1861,8 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) { QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { - DependentTemplateName *DTN = Name.getAsDependentTemplateName(); + DependentTemplateName *DTN + = Name.getUnderlying().getAsDependentTemplateName(); if (DTN && DTN->isIdentifier()) // When building a template-id where the template-name is dependent, // assume the template is a type template. Either our assumption is diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 69e592ee25..c452e26a40 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -992,13 +992,14 @@ TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS, TemplateName Template = Arg.getAsTemplate(); assert(!Template.isNull() && "Null template template argument"); - + // We don't ever want to substitute for a qualified template name, since // the qualifier is handled separately. So, look through the qualified // template name to its underlying declaration. if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) Template = TemplateName(QTN->getTemplateDecl()); - + + Template = getSema().Context.getSubstTemplateTemplateParm(TTP, Template); return Template; } } diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 3e95df4d4d..e8a5c41804 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -4742,6 +4742,14 @@ ASTReader::ReadTemplateName(PerFileData &F, const RecordData &Record, return Context->getDependentTemplateName(NNS, (OverloadedOperatorKind)Record[Idx++]); } + + case TemplateName::SubstTemplateTemplateParm: { + TemplateTemplateParmDecl *param + = cast_or_null(GetDecl(Record[Idx++])); + if (!param) return TemplateName(); + TemplateName replacement = ReadTemplateName(F, Record, Idx); + return Context->getSubstTemplateTemplateParm(param, replacement); + } case TemplateName::SubstTemplateTemplateParmPack: { TemplateTemplateParmDecl *Param diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index d616c84000..fb1795e6a4 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -3694,6 +3694,14 @@ void ASTWriter::AddTemplateName(TemplateName Name, RecordDataImpl &Record) { Record.push_back(DepT->getOperator()); break; } + + case TemplateName::SubstTemplateTemplateParm: { + SubstTemplateTemplateParmStorage *subst + = Name.getAsSubstTemplateTemplateParm(); + AddDeclRef(subst->getParameter(), Record); + AddTemplateName(subst->getReplacement(), Record); + break; + } case TemplateName::SubstTemplateTemplateParmPack: { SubstTemplateTemplateParmPackStorage *SubstPack diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index ec78caa783..e4902e9035 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -1330,6 +1330,11 @@ bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) { return Visit(MakeCursorTemplateRef( Name.getAsQualifiedTemplateName()->getDecl(), Loc, TU)); + + case TemplateName::SubstTemplateTemplateParm: + return Visit(MakeCursorTemplateRef( + Name.getAsSubstTemplateTemplateParm()->getParameter(), + Loc, TU)); case TemplateName::SubstTemplateTemplateParmPack: return Visit(MakeCursorTemplateRef(