aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/TemplateBase.h47
-rw-r--r--include/clang/Sema/ParsedTemplate.h21
-rw-r--r--lib/AST/DeclTemplate.cpp3
-rw-r--r--lib/AST/TemplateBase.cpp72
-rw-r--r--lib/Sema/SemaTemplate.cpp17
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp7
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp28
-rw-r--r--lib/Serialization/ASTReader.cpp11
-rw-r--r--lib/Serialization/ASTWriter.cpp2
-rw-r--r--test/CXX/temp/temp.param/p11-0x.cpp12
10 files changed, 159 insertions, 61 deletions
diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h
index c7cb2fbe8e..758926c957 100644
--- a/include/clang/AST/TemplateBase.h
+++ b/include/clang/AST/TemplateBase.h
@@ -77,6 +77,10 @@ private:
TemplateArgument *Args;
unsigned NumArgs;
} Args;
+ struct {
+ void *Template;
+ bool PackExpansion;
+ } TemplateArg;
};
public:
@@ -104,14 +108,21 @@ public:
Integer.Type = Type.getAsOpaquePtr();
}
- /// \brief Construct a template argument that is a template.
+ /// \brief Construct a template argument that is a template or a pack
+ /// expansion of templates.
///
/// This form of template argument is generally used for template template
/// parameters. However, the template name could be a dependent template
/// name that ends up being instantiated to a function template whose address
/// is taken.
- TemplateArgument(TemplateName Name) : Kind(Template) {
- TypeOrValue = reinterpret_cast<uintptr_t>(Name.getAsVoidPointer());
+ ///
+ /// \param Name The template name.
+ /// \param PackExpansion Whether this template argument is a pack expansion.
+ TemplateArgument(TemplateName Name, bool PackExpansion = false)
+ : Kind(Template)
+ {
+ TemplateArg.Template = Name.getAsVoidPointer();
+ TemplateArg.PackExpansion = PackExpansion;
}
/// \brief Construct a template argument that is an expression.
@@ -142,8 +153,9 @@ public:
} else if (Kind == Pack) {
Args.NumArgs = Other.Args.NumArgs;
Args.Args = Other.Args.Args;
- }
- else
+ } else if (Kind == Template) {
+ TemplateArg = Other.TemplateArg;
+ } else
TypeOrValue = Other.TypeOrValue;
}
@@ -169,6 +181,8 @@ public:
} else if (Other.Kind == Pack) {
Args.NumArgs = Other.Args.NumArgs;
Args.Args = Other.Args.Args;
+ } else if (Other.Kind == Template) {
+ TemplateArg = Other.TemplateArg;
} else {
TypeOrValue = Other.TypeOrValue;
}
@@ -220,8 +234,7 @@ public:
if (Kind != Template)
return TemplateName();
- return TemplateName::getFromVoidPointer(
- reinterpret_cast<void *> (TypeOrValue));
+ return TemplateName::getFromVoidPointer(TemplateArg.Template);
}
/// \brief Retrieve the template argument as an integral value.
@@ -307,6 +320,7 @@ private:
struct {
unsigned QualifierRange[2];
unsigned TemplateNameLoc;
+ unsigned EllipsisLoc;
} Template;
};
@@ -318,11 +332,13 @@ public:
TemplateArgumentLocInfo(Expr *E) : Expression(E) {}
TemplateArgumentLocInfo(SourceRange QualifierRange,
- SourceLocation TemplateNameLoc)
+ SourceLocation TemplateNameLoc,
+ SourceLocation EllipsisLoc)
{
Template.QualifierRange[0] = QualifierRange.getBegin().getRawEncoding();
Template.QualifierRange[1] = QualifierRange.getEnd().getRawEncoding();
Template.TemplateNameLoc = TemplateNameLoc.getRawEncoding();
+ Template.EllipsisLoc = EllipsisLoc.getRawEncoding();
}
TypeSourceInfo *getAsTypeSourceInfo() const {
@@ -342,6 +358,10 @@ public:
SourceLocation getTemplateNameLoc() const {
return SourceLocation::getFromRawEncoding(Template.TemplateNameLoc);
}
+
+ SourceLocation getTemplateEllipsisLoc() const {
+ return SourceLocation::getFromRawEncoding(Template.EllipsisLoc);
+ }
};
/// Location wrapper for a TemplateArgument. TemplateArgument is to
@@ -370,8 +390,10 @@ public:
TemplateArgumentLoc(const TemplateArgument &Argument,
SourceRange QualifierRange,
- SourceLocation TemplateNameLoc)
- : Argument(Argument), LocInfo(QualifierRange, TemplateNameLoc) {
+ SourceLocation TemplateNameLoc,
+ SourceLocation EllipsisLoc = SourceLocation())
+ : Argument(Argument),
+ LocInfo(QualifierRange, TemplateNameLoc, EllipsisLoc) {
assert(Argument.getKind() == TemplateArgument::Template);
}
@@ -419,6 +441,11 @@ public:
return LocInfo.getTemplateNameLoc();
}
+ SourceLocation getTemplateEllipsisLoc() const {
+ assert(Argument.getKind() == TemplateArgument::Template);
+ return LocInfo.getTemplateEllipsisLoc();
+ }
+
/// \brief When the template argument is a pack expansion, returns
/// the pattern of the pack expansion.
///
diff --git a/include/clang/Sema/ParsedTemplate.h b/include/clang/Sema/ParsedTemplate.h
index 6a60ab1294..5aa6f47425 100644
--- a/include/clang/Sema/ParsedTemplate.h
+++ b/include/clang/Sema/ParsedTemplate.h
@@ -58,7 +58,7 @@ namespace clang {
SourceLocation TemplateLoc)
: Kind(ParsedTemplateArgument::Template),
Arg(Template.getAsOpaquePtr()),
- Loc(TemplateLoc), SS(SS) { }
+ Loc(TemplateLoc), SS(SS), EllipsisLoc() { }
/// \brief Determine whether the given template argument is invalid.
bool isInvalid() const { return Arg == 0; }
@@ -95,6 +95,21 @@ namespace clang {
return SS;
}
+ /// \brief Retrieve the location of the ellipsis that makes a template
+ /// template argument into a pack expansion.
+ SourceLocation getEllipsisLoc() const {
+ assert(Kind == Template &&
+ "Only template template arguments can have an ellipsis");
+ return EllipsisLoc;
+ }
+
+ /// \brief Retrieve a pack expansion of the given template template
+ /// argument.
+ ///
+ /// \param EllipsisLoc The location of the ellipsis.
+ ParsedTemplateArgument getTemplatePackExpansion(
+ SourceLocation EllipsisLoc) const;
+
private:
KindType Kind;
@@ -109,6 +124,10 @@ namespace clang {
/// \brief The nested-name-specifier that can accompany a template template
/// argument.
CXXScopeSpec SS;
+
+ /// \brief The ellipsis location that can accompany a template template
+ /// argument (turning it into a template template argument expansion).
+ SourceLocation EllipsisLoc;
};
/// \brief Information about a template-id annotation
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 2755a9e230..b7a586cb17 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -335,8 +335,7 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
Arg = TemplateArgument(E);
} else {
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
- // FIXME: Variadic templates.
- Arg = TemplateArgument(TemplateName(TTP));
+ Arg = TemplateArgument(TemplateName(TTP), TTP->isParameterPack());
}
if ((*Param)->isTemplateParameterPack()) {
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index c971519961..6eae6a4192 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -76,8 +76,7 @@ bool TemplateArgument::isPackExpansion() const {
return isa<PackExpansionType>(getAsType());
case Template:
- // FIXME: Template template pack expansions.
- break;
+ return TemplateArg.PackExpansion;
case Expression:
return isa<PackExpansionExpr>(getAsExpr());
@@ -99,7 +98,8 @@ bool TemplateArgument::containsUnexpandedParameterPack() const {
break;
case Template:
- if (getAsTemplate().containsUnexpandedParameterPack())
+ if (!TemplateArg.PackExpansion &&
+ getAsTemplate().containsUnexpandedParameterPack())
return true;
break;
@@ -135,12 +135,14 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
break;
case Template:
+ ID.AddBoolean(TemplateArg.PackExpansion);
if (TemplateTemplateParmDecl *TTP
= dyn_cast_or_null<TemplateTemplateParmDecl>(
getAsTemplate().getAsTemplateDecl())) {
ID.AddBoolean(true);
ID.AddInteger(TTP->getDepth());
ID.AddInteger(TTP->getPosition());
+ ID.AddBoolean(TTP->isParameterPack());
} else {
ID.AddBoolean(false);
ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate())
@@ -171,10 +173,13 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
case Null:
case Type:
case Declaration:
- case Template:
case Expression:
return TypeOrValue == Other.TypeOrValue;
+ case Template:
+ return TemplateArg.Template == Other.TemplateArg.Template &&
+ TemplateArg.PackExpansion == Other.TemplateArg.PackExpansion;
+
case Integral:
return getIntegralType() == Other.getIntegralType() &&
*getAsIntegral() == *Other.getAsIntegral();
@@ -195,21 +200,20 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
assert(isPackExpansion());
switch (getKind()) {
- case Type:
- return getAsType()->getAs<PackExpansionType>()->getPattern();
-
- case Expression:
- return cast<PackExpansionExpr>(getAsExpr())->getPattern();
-
- case Template:
- // FIXME: Variadic templates.
- llvm_unreachable("Template pack expansions unsupported");
-
- case Declaration:
- case Integral:
- case Pack:
- case Null:
- return TemplateArgument();
+ case Type:
+ return getAsType()->getAs<PackExpansionType>()->getPattern();
+
+ case Expression:
+ return cast<PackExpansionExpr>(getAsExpr())->getPattern();
+
+ case Template:
+ return TemplateArgument(getAsTemplate(), false);
+
+ case Declaration:
+ case Integral:
+ case Pack:
+ case Null:
+ return TemplateArgument();
}
return TemplateArgument();
@@ -246,6 +250,8 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
case Template: {
getAsTemplate().print(Out, Policy);
+ if (TemplateArg.PackExpansion)
+ Out << "...";
break;
}
@@ -254,12 +260,9 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
break;
}
- case Expression: {
- // FIXME: This is non-optimal, since we're regurgitating the
- // expression we were given.
+ case Expression:
getAsExpr()->printPretty(Out, 0, Policy);
break;
- }
case Pack:
Out << "<";
@@ -296,12 +299,15 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
else
return SourceRange();
- case TemplateArgument::Template:
+ case TemplateArgument::Template: {
+ SourceLocation End = getTemplateNameLoc();
+ if (getTemplateEllipsisLoc().isValid())
+ End = getTemplateEllipsisLoc();
if (getTemplateQualifierRange().isValid())
- return SourceRange(getTemplateQualifierRange().getBegin(),
- getTemplateNameLoc());
- return SourceRange(getTemplateNameLoc());
-
+ return SourceRange(getTemplateQualifierRange().getBegin(), End);
+ return SourceRange(getTemplateNameLoc(), End);
+ }
+
case TemplateArgument::Integral:
case TemplateArgument::Pack:
case TemplateArgument::Null:
@@ -351,8 +357,9 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
}
case TemplateArgument::Template:
- // FIXME: Variadic templates.
- llvm_unreachable("Template pack expansions unsupported");
+ return TemplateArgumentLoc(Argument.getPackExpansionPattern(),
+ getTemplateQualifierRange(),
+ getTemplateNameLoc());
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
@@ -382,7 +389,10 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
return DB << Arg.getAsIntegral()->toString(10);
case TemplateArgument::Template:
- return DB << Arg.getAsTemplate();
+ DB << Arg.getAsTemplate();
+ if (Arg.isPackExpansion())
+ DB << "...";
+ return DB;
case TemplateArgument::Expression: {
// This shouldn't actually ever happen, so it's okay that we're
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index ff0fe9d6b6..9adcf1c81f 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -437,6 +437,17 @@ TemplateDecl *Sema::AdjustDeclIfTemplate(Decl *&D) {
return 0;
}
+ParsedTemplateArgument ParsedTemplateArgument::getTemplatePackExpansion(
+ SourceLocation EllipsisLoc) const {
+ assert(Kind == Template &&
+ "Only template template arguments can be pack expansions here");
+ assert(getAsTemplate().get().containsUnexpandedParameterPack() &&
+ "Template template argument pack expansion without packs");
+ ParsedTemplateArgument Result(*this);
+ Result.EllipsisLoc = EllipsisLoc;
+ return Result;
+}
+
static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
const ParsedTemplateArgument &Arg) {
@@ -456,9 +467,11 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
case ParsedTemplateArgument::Template: {
TemplateName Template = Arg.getAsTemplate().get();
- return TemplateArgumentLoc(TemplateArgument(Template),
+ return TemplateArgumentLoc(TemplateArgument(Template,
+ Arg.getEllipsisLoc().isValid()),
Arg.getScopeSpec().getRange(),
- Arg.getLocation());
+ Arg.getLocation(),
+ Arg.getEllipsisLoc());
}
}
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 18bfee301b..a72a29378a 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -1344,19 +1344,20 @@ getTrivialTemplateArgumentLoc(Sema &S,
case TemplateArgument::Declaration: {
Expr *E
- = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
+ = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
.takeAs<Expr>();
return TemplateArgumentLoc(TemplateArgument(E), E);
}
case TemplateArgument::Integral: {
Expr *E
- = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>();
+ = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>();
return TemplateArgumentLoc(TemplateArgument(E), E);
}
case TemplateArgument::Template:
- return TemplateArgumentLoc(Arg, SourceRange(), Loc);
+ return TemplateArgumentLoc(Arg, SourceRange(), Loc,
+ Arg.isPackExpansion()? Loc : SourceLocation());
case TemplateArgument::Expression:
return TemplateArgumentLoc(Arg, Arg.getAsExpr());
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index acb73144d9..fb88bd114b 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -130,6 +130,22 @@ namespace {
return true;
}
+
+ /// \brief Suppress traversal of template argument pack expansions.
+ bool TraverseTemplateArgument(const TemplateArgument &Arg) {
+ if (Arg.isPackExpansion())
+ return true;
+
+ return inherited::TraverseTemplateArgument(Arg);
+ }
+
+ /// \brief Suppress traversal of template argument pack expansions.
+ bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
+ if (ArgLoc.getArgument().isPackExpansion())
+ return true;
+
+ return inherited::TraverseTemplateArgumentLoc(ArgLoc);
+ }
};
}
@@ -335,8 +351,16 @@ Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg,
}
case ParsedTemplateArgument::Template:
- Diag(EllipsisLoc, diag::err_pack_expansion_unsupported);
- return ParsedTemplateArgument();
+ if (!Arg.getAsTemplate().get().containsUnexpandedParameterPack()) {
+ SourceRange R(Arg.getLocation());
+ if (Arg.getScopeSpec().isValid())
+ R.setBegin(Arg.getScopeSpec().getBeginLoc());
+ Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
+ << R;
+ return ParsedTemplateArgument();
+ }
+
+ return Arg.getTemplatePackExpansion(EllipsisLoc);
}
llvm_unreachable("Unhandled template argument kind?");
return ParsedTemplateArgument();
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index f3320a0415..ed0e58f18f 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -3381,7 +3381,9 @@ ASTReader::GetTemplateArgumentLocInfo(PerFileData &F,
case TemplateArgument::Template: {
SourceRange QualifierRange = ReadSourceRange(F, Record, Index);
SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index);
- return TemplateArgumentLocInfo(QualifierRange, TemplateNameLoc);
+ SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Index);
+ return TemplateArgumentLocInfo(QualifierRange, TemplateNameLoc,
+ EllipsisLoc);
}
case TemplateArgument::Null:
case TemplateArgument::Integral:
@@ -4226,8 +4228,11 @@ ASTReader::ReadTemplateArgument(PerFileData &F,
QualType T = GetType(Record[Idx++]);
return TemplateArgument(Value, T);
}
- case TemplateArgument::Template:
- return TemplateArgument(ReadTemplateName(Record, Idx));
+ case TemplateArgument::Template: {
+ TemplateName Name = ReadTemplateName(Record, Idx);
+ bool IsPackExpansion = Record[Idx++];
+ return TemplateArgument(Name, IsPackExpansion);
+ }
case TemplateArgument::Expression:
return TemplateArgument(ReadExpr(F));
case TemplateArgument::Pack: {
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index cbf5ac7919..44f17e40b1 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -2889,6 +2889,7 @@ void ASTWriter::AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind,
case TemplateArgument::Template:
AddSourceRange(Arg.getTemplateQualifierRange(), Record);
AddSourceLocation(Arg.getTemplateNameLoc(), Record);
+ AddSourceLocation(Arg.getTemplateEllipsisLoc(), Record);
break;
case TemplateArgument::Null:
case TemplateArgument::Integral:
@@ -3176,6 +3177,7 @@ void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg,
break;
case TemplateArgument::Template:
AddTemplateName(Arg.getAsTemplate(), Record);
+ Record.push_back(Arg.isPackExpansion());
break;
case TemplateArgument::Expression:
AddStmt(Arg.getAsExpr());
diff --git a/test/CXX/temp/temp.param/p11-0x.cpp b/test/CXX/temp/temp.param/p11-0x.cpp
index 00f56ab86d..d31a1f05fe 100644
--- a/test/CXX/temp/temp.param/p11-0x.cpp
+++ b/test/CXX/temp/temp.param/p11-0x.cpp
@@ -34,10 +34,9 @@ template<typename ...Types, typename T> struct X1t<T, Types...> { };
template<int... Values> struct X1nt;
template<int ...Values, int V> struct X1nt<V, Values...> { };
-// FIXME: Need template template argument packs!
-// template<template<int> class... Meta> struct X1tt;
-// template<template<int> class... Meta, template<int> class M>
-// struct X1tt<M, Meta...> { };
+template<template<int> class... Meta> struct X1tt;
+template<template<int> class... Meta, template<int> class M>
+ struct X1tt<M, Meta...> { };
template<typename ...Types, typename T>
void f1t(X1t<T, Types...>);
@@ -45,6 +44,5 @@ void f1t(X1t<T, Types...>);
template<int ...Values, int V>
void f1nt(X1nt<V, Values...>);
-// FIXME: Need template template argument packs!
-// template<template<int> class... Meta, template<int> class M>
-// void f1tt(X1tt<M, Meta...>);
+template<template<int> class... Meta, template<int> class M>
+void f1tt(X1tt<M, Meta...>);