diff options
-rw-r--r-- | include/clang/AST/ASTContext.h | 8 | ||||
-rw-r--r-- | include/clang/AST/TemplateName.h | 134 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 4 | ||||
-rw-r--r-- | include/clang/Serialization/ASTReader.h | 3 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 30 | ||||
-rw-r--r-- | lib/AST/ASTImporter.cpp | 18 | ||||
-rw-r--r-- | lib/AST/ItaniumMangle.cpp | 6 | ||||
-rw-r--r-- | lib/AST/TemplateName.cpp | 33 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 65 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 30 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 22 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 8 | ||||
-rw-r--r-- | test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp | 26 | ||||
-rw-r--r-- | tools/libclang/CIndex.cpp | 5 |
14 files changed, 354 insertions, 38 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 93b793eb78..97388dc090 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -119,7 +119,9 @@ class ASTContext { mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames; mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames; - + mutable llvm::FoldingSet<SubstTemplateTemplateParmPackStorage> + SubstTemplateTemplateParmPacks; + /// \brief The set of nested name specifiers. /// /// This set is managed by the NestedNameSpecifier class. @@ -936,7 +938,9 @@ public: const IdentifierInfo *Name) const; TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, OverloadedOperatorKind Operator) const; - + TemplateName getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, + const TemplateArgument &ArgPack) const; + enum GetBuiltinTypeError { GE_None, //< No error GE_Missing_stdio, //< Missing a type from <stdio.h> diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h index c85b72f087..1721973e82 100644 --- a/include/clang/AST/TemplateName.h +++ b/include/clang/AST/TemplateName.h @@ -23,27 +23,67 @@ namespace llvm { } namespace clang { - + +class ASTContext; class DependentTemplateName; class DiagnosticBuilder; class IdentifierInfo; class NestedNameSpecifier; +class OverloadedTemplateStorage; struct PrintingPolicy; class QualifiedTemplateName; class NamedDecl; +class SubstTemplateTemplateParmPackStorage; +class TemplateArgument; class TemplateDecl; - -/// \brief A structure for storing the information associated with an -/// overloaded template name. -class OverloadedTemplateStorage { +class TemplateTemplateParmDecl; + +/// \brief Implementation class used to describe either a set of overloaded +/// template names or an already-substituted template template parameter pack. +class UncommonTemplateNameStorage { +protected: union { - unsigned Size; + struct { + /// \brief If true, this is an OverloadedTemplateStorage instance; + /// otherwise, it's a SubstTemplateTemplateParmPackStorage instance. + unsigned IsOverloadedStorage : 1; + + /// \brief The number of stored templates or template arguments, + /// depending on which subclass we have. + unsigned Size : 31; + } Bits; + void *PointerAlignment; }; + UncommonTemplateNameStorage(unsigned Size, bool OverloadedStorage) { + Bits.IsOverloadedStorage = OverloadedStorage; + Bits.Size = Size; + } + +public: + unsigned size() const { return Bits.Size; } + + OverloadedTemplateStorage *getAsOverloadedStorage() { + return Bits.IsOverloadedStorage + ? reinterpret_cast<OverloadedTemplateStorage *>(this) + : 0; + } + + SubstTemplateTemplateParmPackStorage *getAsSubstTemplateTemplateParmPack() { + return Bits.IsOverloadedStorage + ? 0 + : reinterpret_cast<SubstTemplateTemplateParmPackStorage *>(this) ; + } +}; + +/// \brief A structure for storing the information associated with an +/// overloaded template name. +class OverloadedTemplateStorage : public UncommonTemplateNameStorage { friend class ASTContext; - OverloadedTemplateStorage(unsigned Size) : Size(Size) {} + OverloadedTemplateStorage(unsigned Size) + : UncommonTemplateNameStorage(Size, true) { } NamedDecl **getStorage() { return reinterpret_cast<NamedDecl **>(this + 1); @@ -55,11 +95,47 @@ class OverloadedTemplateStorage { public: typedef NamedDecl *const *iterator; - unsigned size() const { return Size; } - iterator begin() const { return getStorage(); } iterator end() const { return getStorage() + size(); } }; + + +/// \brief A structure for storing an already-substituted template template +/// parameter pack. +/// +/// This kind of template names occurs when the parameter pack has been +/// provided with a template template argument pack in a context where its +/// enclosing pack expansion could not be fully expanded. +class SubstTemplateTemplateParmPackStorage + : public UncommonTemplateNameStorage, public llvm::FoldingSetNode +{ + ASTContext &Context; + TemplateTemplateParmDecl *Parameter; + const TemplateArgument *Arguments; + +public: + SubstTemplateTemplateParmPackStorage(ASTContext &Context, + TemplateTemplateParmDecl *Parameter, + unsigned Size, + const TemplateArgument *Arguments) + : UncommonTemplateNameStorage(Size, false), Context(Context), + Parameter(Parameter), Arguments(Arguments) { } + + /// \brief Retrieve the template template parameter pack being substituted. + TemplateTemplateParmDecl *getParameterPack() const { + return Parameter; + } + + /// \brief Retrieve the template template argument pack with which this + /// parameter was substituted. + TemplateArgument getArgumentPack() const; + + void Profile(llvm::FoldingSetNodeID &ID); + + static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, + TemplateTemplateParmDecl *Parameter, + const TemplateArgument &ArgPack); +}; /// \brief Represents a C++ template name within the type system. /// @@ -90,7 +166,7 @@ public: /// only be understood in the context of class TemplateName { typedef llvm::PointerUnion4<TemplateDecl *, - OverloadedTemplateStorage *, + UncommonTemplateNameStorage *, QualifiedTemplateName *, DependentTemplateName *> StorageType; @@ -103,16 +179,28 @@ class TemplateName { public: // \brief Kind of name that is actually stored. enum NameKind { + /// \brief A single template declaration. Template, + /// \brief A set of overloaded template declarations. OverloadedTemplate, + /// \brief A qualified template name, where the qualification is kept + /// to describe the source code as written. QualifiedTemplate, - DependentTemplate + /// \brief A dependent template name that has not been resolved to a + /// template (or set of templates). + DependentTemplate, + /// \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. + SubstTemplateTemplateParmPack }; TemplateName() : Storage() { } explicit TemplateName(TemplateDecl *Template) : Storage(Template) { } explicit TemplateName(OverloadedTemplateStorage *Storage) : Storage(Storage) { } + explicit TemplateName(SubstTemplateTemplateParmPackStorage *Storage) + : Storage(Storage) { } explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { } explicit TemplateName(DependentTemplateName *Dep) : Storage(Dep) { } @@ -122,7 +210,7 @@ public: // \brief Get the kind of name that is actually stored. NameKind getKind() const; - /// \brief Retrieve the the underlying template declaration that + /// \brief Retrieve the underlying template declaration that /// this template name refers to, if known. /// /// \returns The template declaration that this template name refers @@ -131,7 +219,7 @@ public: /// set of function templates, returns NULL. TemplateDecl *getAsTemplateDecl() const; - /// \brief Retrieve the the underlying, overloaded function template + /// \brief Retrieve the underlying, overloaded function template // declarations that this template name refers to, if known. /// /// \returns The set of overloaded function templates that this template @@ -139,7 +227,25 @@ public: /// specific set of function templates because it is a dependent name or /// refers to a single template, returns NULL. OverloadedTemplateStorage *getAsOverloadedTemplate() const { - return Storage.dyn_cast<OverloadedTemplateStorage *>(); + if (UncommonTemplateNameStorage *Uncommon = + Storage.dyn_cast<UncommonTemplateNameStorage *>()) + return Uncommon->getAsOverloadedStorage(); + + return 0; + } + + /// \brief Retrieve the substituted template template parameter pack, if + /// known. + /// + /// \returns The storage for the substituted template template parameter pack, + /// if known. Otherwise, returns NULL. + SubstTemplateTemplateParmPackStorage * + getAsSubstTemplateTemplateParmPack() const { + if (UncommonTemplateNameStorage *Uncommon = + Storage.dyn_cast<UncommonTemplateNameStorage *>()) + return Uncommon->getAsSubstTemplateTemplateParmPack(); + + return 0; } /// \brief Retrieve the underlying qualified template name diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index aaccaabd75..491df7f75d 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1885,10 +1885,6 @@ def err_ellipsis_in_declarator_not_parameter : Error< def err_sizeof_pack_no_pack_name : Error< "%0 does not refer to the name of a parameter pack">; -// Unsupported variadic templates features -def err_pack_expansion_mismatch_unsupported : Error< - "clang cannot yet instantiate pack expansions with mismatched pack levels">; - def err_unexpected_typedef : Error< "unexpected type name %0: expected expression">; def err_unexpected_namespace : Error< diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 10c23c0834..38b0c57d22 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -1073,7 +1073,8 @@ public: unsigned &Idx); /// \brief Read a template name. - TemplateName ReadTemplateName(const RecordData &Record, unsigned &Idx); + TemplateName ReadTemplateName(PerFileData &F, const RecordData &Record, + unsigned &Idx); /// \brief Read a template argument. TemplateArgument ReadTemplateArgument(PerFileData &F, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index e1e6fd08aa..a18247d7ce 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2737,6 +2737,15 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) const { return TemplateName(cast<TemplateDecl>(Template->getCanonicalDecl())); } + if (SubstTemplateTemplateParmPackStorage *SubstPack + = Name.getAsSubstTemplateTemplateParmPack()) { + TemplateTemplateParmDecl *CanonParam + = getCanonicalTemplateTemplateParmDecl(SubstPack->getParameterPack()); + TemplateArgument CanonArgPack + = getCanonicalTemplateArgument(SubstPack->getArgumentPack()); + return getSubstTemplateTemplateParmPack(CanonParam, CanonArgPack); + } + assert(!Name.getAsOverloadedTemplate()); DependentTemplateName *DTN = Name.getAsDependentTemplateName(); @@ -4344,6 +4353,27 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, return TemplateName(QTN); } +TemplateName +ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, + const TemplateArgument &ArgPack) const { + ASTContext &Self = const_cast<ASTContext &>(*this); + llvm::FoldingSetNodeID ID; + SubstTemplateTemplateParmPackStorage::Profile(ID, Self, Param, ArgPack); + + void *InsertPos = 0; + SubstTemplateTemplateParmPackStorage *Subst + = SubstTemplateTemplateParmPacks.FindNodeOrInsertPos(ID, InsertPos); + + if (!Subst) { + Subst = new (*this) SubstTemplateTemplateParmPackStorage(Self, Param, + ArgPack.pack_size(), + ArgPack.pack_begin()); + SubstTemplateTemplateParmPacks.InsertNode(Subst, InsertPos); + } + + return TemplateName(Subst); +} + /// getFromTargetType - Given one of the integer types provided by /// TargetInfo, produce the corresponding type. The unsigned @p Type /// is actually a value of type @c TargetInfo::IntType. diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index f9fe18f5df..eaab3d3e6c 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -4079,6 +4079,24 @@ TemplateName ASTImporter::Import(TemplateName From) { return ToContext.getDependentTemplateName(Qualifier, DTN->getOperator()); } + + case TemplateName::SubstTemplateTemplateParmPack: { + SubstTemplateTemplateParmPackStorage *SubstPack + = From.getAsSubstTemplateTemplateParmPack(); + TemplateTemplateParmDecl *Param + = cast_or_null<TemplateTemplateParmDecl>( + Import(SubstPack->getParameterPack())); + if (!Param) + return TemplateName(); + + ASTNodeImporter Importer(*this); + TemplateArgument ArgPack + = Importer.ImportTemplateArgument(SubstPack->getArgumentPack()); + if (ArgPack.isNull()) + return TemplateName(); + + return ToContext.getSubstTemplateTemplateParmPack(Param, ArgPack); + } } llvm_unreachable("Invalid template name kind"); diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 2f8be294f2..15cd7f7f8d 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -1017,6 +1017,12 @@ void CXXNameMangler::mangleType(TemplateName TN) { break; } + case TemplateName::SubstTemplateTemplateParmPack: { + SubstTemplateTemplateParmPackStorage *SubstPack + = TN.getAsSubstTemplateTemplateParmPack(); + mangleTemplateParameter(SubstPack->getParameterPack()->getIndex()); + break; + } } addSubstitution(TN); diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index 73ff402b07..6b378a0011 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/TemplateName.h" +#include "clang/AST/TemplateBase.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" @@ -21,15 +22,33 @@ using namespace clang; using namespace llvm; +TemplateArgument +SubstTemplateTemplateParmPackStorage::getArgumentPack() const { + return TemplateArgument(Arguments, size()); +} + +void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, Parameter, TemplateArgument(Arguments, size())); +} + +void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context, + TemplateTemplateParmDecl *Parameter, + const TemplateArgument &ArgPack) { + ID.AddPointer(Parameter); + ArgPack.Profile(ID, Context); +} + TemplateName::NameKind TemplateName::getKind() const { if (Storage.is<TemplateDecl *>()) return Template; - if (Storage.is<OverloadedTemplateStorage *>()) - return OverloadedTemplate; + if (Storage.is<DependentTemplateName *>()) + return DependentTemplate; if (Storage.is<QualifiedTemplateName *>()) return QualifiedTemplate; - assert(Storage.is<DependentTemplateName *>() && "There's a case unhandled!"); - return DependentTemplate; + + return getAsOverloadedTemplate()? OverloadedTemplate + : SubstTemplateTemplateParmPack; } TemplateDecl *TemplateName::getAsTemplateDecl() const { @@ -73,7 +92,7 @@ bool TemplateName::containsUnexpandedParameterPack() const { return DTN->getQualifier() && DTN->getQualifier()->containsUnexpandedParameterPack(); - return false; + return getAsSubstTemplateTemplateParmPack() != 0; } void @@ -96,7 +115,9 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, OS << DTN->getIdentifier()->getName(); else OS << "operator " << getOperatorSpelling(DTN->getOperator()); - } + } else if (SubstTemplateTemplateParmPackStorage *SubstPack + = getAsSubstTemplateTemplateParmPack()) + OS << SubstPack->getParameterPack()->getNameAsString(); } const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 8943daa369..98fa390feb 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -697,6 +697,10 @@ namespace { ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType T); + TemplateName TransformTemplateName(TemplateName Name, + QualType ObjectType = QualType(), + NamedDecl *FirstQualifierInScope = 0); + ExprResult TransformPredefinedExpr(PredefinedExpr *E); ExprResult TransformDeclRefExpr(DeclRefExpr *E); ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E); @@ -762,12 +766,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { assert(Arg.getKind() == TemplateArgument::Pack && "Missing argument pack"); - if (getSema().ArgumentPackSubstitutionIndex == -1) { - // FIXME: Variadic templates fun case. - getSema().Diag(Loc, diag::err_pack_expansion_mismatch_unsupported); - return 0; - } - + assert(getSema().ArgumentPackSubstitutionIndex >= 0); assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size()); Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex]; } @@ -887,6 +886,60 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc, NNS, T); } +TemplateName TemplateInstantiator::TransformTemplateName(TemplateName Name, + QualType ObjectType, + NamedDecl *FirstQualifierInScope) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast_or_null<TemplateTemplateParmDecl>(Name.getAsTemplateDecl())) { + if (TTP->getDepth() < TemplateArgs.getNumLevels()) { + // If the corresponding template argument is NULL or non-existent, it's + // because we are performing instantiation from explicitly-specified + // template arguments in a function template, but there were some + // arguments left unspecified. + if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(), + TTP->getPosition())) + return Name; + + TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition()); + + if (TTP->isParameterPack()) { + assert(Arg.getKind() == TemplateArgument::Pack && + "Missing argument pack"); + + if (getSema().ArgumentPackSubstitutionIndex == -1) { + // We have the template argument pack to substitute, but we're not + // actually expanding the enclosing pack expansion yet. So, just + // keep the entire argument pack. + return getSema().Context.getSubstTemplateTemplateParmPack(TTP, Arg); + } + + assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size()); + Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex]; + } + + TemplateName Template = Arg.getAsTemplate(); + assert(!Template.isNull() && Template.getAsTemplateDecl() && + "Wrong kind of template template argument"); + return Template; + } + } + + if (SubstTemplateTemplateParmPackStorage *SubstPack + = Name.getAsSubstTemplateTemplateParmPack()) { + if (getSema().ArgumentPackSubstitutionIndex == -1) + return Name; + + const TemplateArgument &ArgPack = SubstPack->getArgumentPack(); + assert(getSema().ArgumentPackSubstitutionIndex < (int)ArgPack.pack_size() && + "Pack substitution index out-of-range"); + return ArgPack.pack_begin()[getSema().ArgumentPackSubstitutionIndex] + .getAsTemplate(); + } + + return inherited::TransformTemplateName(Name, ObjectType, + FirstQualifierInScope); +} + ExprResult TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { if (!E->isTypeDependent()) diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 73982a71c2..be4d82c39a 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -891,7 +891,19 @@ public: TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier, OverloadedOperatorKind Operator, QualType ObjectType); - + + /// \brief Build a new template name given a template template parameter pack + /// and the + /// + /// By default, performs semantic analysis to determine whether the name can + /// be resolved to a specific template, then builds the appropriate kind of + /// template name. Subclasses may override this routine to provide different + /// behavior. + TemplateName RebuildTemplateName(TemplateTemplateParmDecl *Param, + const TemplateArgument &ArgPack) { + return getSema().Context.getSubstTemplateTemplateParmPack(Param, ArgPack); + } + /// \brief Build a new compound statement. /// /// By default, performs semantic analysis to build the new statement. @@ -2590,6 +2602,22 @@ TreeTransform<Derived>::TransformTemplateName(TemplateName Name, return TemplateName(TransTemplate); } + if (SubstTemplateTemplateParmPackStorage *SubstPack + = Name.getAsSubstTemplateTemplateParmPack()) { + TemplateTemplateParmDecl *TransParam + = cast_or_null<TemplateTemplateParmDecl>( + getDerived().TransformDecl(Loc, SubstPack->getParameterPack())); + if (!TransParam) + return TemplateName(); + + if (!getDerived().AlwaysRebuild() && + TransParam == SubstPack->getParameterPack()) + return Name; + + return getDerived().RebuildTemplateName(TransParam, + SubstPack->getArgumentPack()); + } + // These should be getting filtered out before they reach the AST. llvm_unreachable("overloaded function decl survived to here"); return TemplateName(); diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 584abfbcd1..6f87e40159 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -3082,7 +3082,7 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { case TYPE_TEMPLATE_SPECIALIZATION: { unsigned Idx = 0; bool IsDependent = Record[Idx++]; - TemplateName Name = ReadTemplateName(Record, Idx); + TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx); llvm::SmallVector<TemplateArgument, 8> Args; ReadTemplateArgumentList(Args, *Loc.F, Record, Idx); QualType Canon = GetType(Record[Idx++]); @@ -4238,7 +4238,8 @@ void ASTReader::ReadQualifierInfo(PerFileData &F, QualifierInfo &Info, } TemplateName -ASTReader::ReadTemplateName(const RecordData &Record, unsigned &Idx) { +ASTReader::ReadTemplateName(PerFileData &F, const RecordData &Record, + unsigned &Idx) { TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++]; switch (Kind) { case TemplateName::Template: @@ -4268,6 +4269,19 @@ ASTReader::ReadTemplateName(const RecordData &Record, unsigned &Idx) { return Context->getDependentTemplateName(NNS, (OverloadedOperatorKind)Record[Idx++]); } + + case TemplateName::SubstTemplateTemplateParmPack: { + TemplateTemplateParmDecl *Param + = cast_or_null<TemplateTemplateParmDecl>(GetDecl(Record[Idx++])); + if (!Param) + return TemplateName(); + + TemplateArgument ArgPack = ReadTemplateArgument(F, Record, Idx); + if (ArgPack.getKind() != TemplateArgument::Pack) + return TemplateName(); + + return Context->getSubstTemplateTemplateParmPack(Param, ArgPack); + } } assert(0 && "Unhandled template name kind!"); @@ -4291,9 +4305,9 @@ ASTReader::ReadTemplateArgument(PerFileData &F, return TemplateArgument(Value, T); } case TemplateArgument::Template: - return TemplateArgument(ReadTemplateName(Record, Idx)); + return TemplateArgument(ReadTemplateName(F, Record, Idx)); case TemplateArgument::TemplateExpansion: { - TemplateName Name = ReadTemplateName(Record, Idx); + TemplateName Name = ReadTemplateName(F, Record, Idx); llvm::Optional<unsigned> NumTemplateExpansions; if (unsigned NumExpansions = Record[Idx++]) NumTemplateExpansions = NumExpansions - 1; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 4fa48faec5..8a6461fb4f 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -3214,6 +3214,14 @@ void ASTWriter::AddTemplateName(TemplateName Name, RecordDataImpl &Record) { Record.push_back(DepT->getOperator()); break; } + + case TemplateName::SubstTemplateTemplateParmPack: { + SubstTemplateTemplateParmPackStorage *SubstPack + = Name.getAsSubstTemplateTemplateParmPack(); + AddDeclRef(SubstPack->getParameterPack(), Record); + AddTemplateArgument(SubstPack->getArgumentPack(), Record); + break; + } } } diff --git a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp index 01d5759188..8a53f54456 100644 --- a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp +++ b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp @@ -149,4 +149,30 @@ namespace PacksAtDifferentLevels { unsigned_pair<3, 4>, unsigned_pair<5, 6>> >::value == 0? 1 : -1]; + + template<class> struct add_reference; + template<class> struct add_pointer; + template<class> struct add_const; + + template<template<class> class ...Templates> + struct X5 { + template<typename> struct Inner { + static const unsigned value = 0; + }; + + template<typename ...Types> + struct Inner<tuple<Templates<Types>...>> { + static const unsigned value = 1; + }; + }; + + int check10[X5<add_reference, add_pointer, add_const> + ::Inner<tuple<add_reference<int>, + add_pointer<float>, + add_const<double>>>::value == 1? 1 : -1]; + int check11[X5<add_reference, add_pointer> + ::Inner<tuple<add_reference<int>, + add_pointer<float>, + add_const<double>>>::value == 0? 1 : -1]; + } diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 574b4c8b4e..910f449894 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -1228,6 +1228,11 @@ bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) { return Visit(MakeCursorTemplateRef( Name.getAsQualifiedTemplateName()->getDecl(), Loc, TU)); + + case TemplateName::SubstTemplateTemplateParmPack: + return Visit(MakeCursorTemplateRef( + Name.getAsSubstTemplateTemplateParmPack()->getParameterPack(), + Loc, TU)); } return false; |