aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ASTContext.h8
-rw-r--r--include/clang/AST/TemplateName.h134
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td4
-rw-r--r--include/clang/Serialization/ASTReader.h3
-rw-r--r--lib/AST/ASTContext.cpp30
-rw-r--r--lib/AST/ASTImporter.cpp18
-rw-r--r--lib/AST/ItaniumMangle.cpp6
-rw-r--r--lib/AST/TemplateName.cpp33
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp65
-rw-r--r--lib/Sema/TreeTransform.h30
-rw-r--r--lib/Serialization/ASTReader.cpp22
-rw-r--r--lib/Serialization/ASTWriter.cpp8
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp26
-rw-r--r--tools/libclang/CIndex.cpp5
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;