aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-12-23 23:51:58 +0000
committerDouglas Gregor <dgregor@apple.com>2010-12-23 23:51:58 +0000
commit10738d36b150aa65206890c1c845cdba076e4200 (patch)
tree9485127dbdbb9dd5937d9615b97baa9bb3ad3ab4
parent662a4822ee7c8696434b054303c5076a606ab175 (diff)
Add an AST representation for non-type template parameter
packs, e.g., template<typename T, unsigned ...Dims> struct multi_array; along with semantic analysis support for finding unexpanded non-type template parameter packs in types, expressions, and so on. Template instantiation involving non-type template parameter packs probably doesn't work yet. That'll come soon. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122527 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/DeclTemplate.h27
-rw-r--r--include/clang/AST/Expr.h1
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td3
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--lib/AST/ASTContext.cpp1
-rw-r--r--lib/AST/ASTImporter.cpp2
-rw-r--r--lib/AST/DeclBase.cpp4
-rw-r--r--lib/AST/DeclTemplate.cpp5
-rw-r--r--lib/AST/Expr.cpp10
-rw-r--r--lib/Sema/SemaTemplate.cpp12
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp3
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp21
-rw-r--r--lib/Sema/SemaType.cpp2
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp3
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp1
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp4
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/p5.cpp20
18 files changed, 93 insertions, 30 deletions
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 7a311c8741..f2f91786bc 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -990,17 +990,27 @@ class NonTypeTemplateParmDecl
/// it was inherited.
llvm::PointerIntPair<Expr*, 1, bool> DefaultArgumentAndInherited;
+ // FIXME: Collapse this into TemplateParamPosition; or, just move depth/index
+ // down here to save memory.
+
+ /// \brief Whether this non-type template parameter is a parameter pack.
+ bool ParameterPack;
+
NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
unsigned P, IdentifierInfo *Id, QualType T,
- TypeSourceInfo *TInfo)
+ bool ParameterPack, TypeSourceInfo *TInfo)
: VarDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo, SC_None, SC_None),
- TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false)
+ TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false),
+ ParameterPack(ParameterPack)
{ }
+ friend class ASTDeclReader;
+
public:
static NonTypeTemplateParmDecl *
Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
- unsigned P, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo);
+ unsigned P, IdentifierInfo *Id, QualType T, bool ParameterPack,
+ TypeSourceInfo *TInfo);
using TemplateParmPosition::getDepth;
using TemplateParmPosition::setDepth;
@@ -1042,6 +1052,17 @@ public:
DefaultArgumentAndInherited.setInt(false);
}
+ /// \brief Whether this parameter is a non-type template parameter pack.
+ ///
+ /// If the parameter is a parameter pack, the type may be a
+ /// \c PackExpansionType. In the following example, the \c Dims parameter
+ /// is a parameter pack (whose type is 'unsigned').
+ ///
+ /// \code
+ /// template<typename T, unsigned ...Dims> struct multi_array;
+ /// \endcode
+ bool isParameterPack() const { return ParameterPack; }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const NonTypeTemplateParmDecl *D) { return true; }
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index e12f45b49e..d2add78cd8 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -3564,6 +3564,7 @@ class BlockDeclRefExpr : public Expr {
Stmt *CopyConstructorVal;
public:
// FIXME: Fix type/value dependence!
+ // FIXME: Variadic templates.
BlockDeclRefExpr(ValueDecl *d, QualType t, ExprValueKind VK,
SourceLocation l, bool ByRef, bool constAdded = false,
Stmt *copyConstructorVal = 0)
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index 98ea9d4bd6..1374402012 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -47,6 +47,8 @@ def err_param_redefinition : Error<"redefinition of parameter %0">;
def err_invalid_storage_class_in_func_decl : Error<
"invalid storage class specifier in function declarator">;
def err_expected_namespace_name : Error<"expected namespace name">;
+def err_variadic_templates : Error<
+ "variadic templates are only allowed in C++0x">;
// Sema && Lex
def ext_longlong : Extension<
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 3d677abb42..e8eb111795 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -374,9 +374,6 @@ def err_expected_type_name_after_typename : Error<
def err_explicit_spec_non_template : Error<
"explicit %select{specialization|instantiation}0 of non-template "
"%select{class|struct|union}1 %2">;
-
-def err_variadic_templates : Error<
- "variadic templates are only allowed in C++0x">;
def err_default_template_template_parameter_not_template : Error<
"default template argument for a template template parameter must be a class "
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 8e7a2ba818..49c9c4b6b7 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1876,8 +1876,6 @@ def err_pack_expansion_mismatch_unsupported : Error<
"clang cannot yet instantiate pack expansions with mismatched pack levels">;
def err_function_parameter_pack_unsupported : Error<
"clang does not yet support function parameter packs">;
-def err_non_type_parameter_pack_unsupported : Error<
- "clang does not yet support non-type template parameter packs">;
def err_unexpected_typedef : Error<
"unexpected type name %0: expected expression">;
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index e20b1ed63f..eaf222cafa 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -109,6 +109,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
SourceLocation(), NTTP->getDepth(),
NTTP->getPosition(), 0,
getCanonicalType(NTTP->getType()),
+ NTTP->isParameterPack(),
0));
else
CanonParams.push_back(getCanonicalTemplateTemplateParmDecl(
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 7ff217e334..7d6c90519b 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -3414,7 +3414,7 @@ ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
Importer.getToContext().getTranslationUnitDecl(),
Loc, D->getDepth(), D->getPosition(),
Name.getAsIdentifierInfo(),
- T, TInfo);
+ T, D->isParameterPack(), TInfo);
}
Decl *
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 843e907dea..75ea2df27e 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -110,7 +110,9 @@ void Decl::add(Kind k) {
bool Decl::isTemplateParameterPack() const {
if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(this))
return TTP->isParameterPack();
-
+ if (const NonTypeTemplateParmDecl *NTTP
+ = llvm::dyn_cast<NonTypeTemplateParmDecl>(this))
+ return NTTP->isParameterPack();
return false;
}
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 422e5e30f8..dff956c6dc 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -390,8 +390,9 @@ NonTypeTemplateParmDecl *
NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
IdentifierInfo *Id, QualType T,
- TypeSourceInfo *TInfo) {
- return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, TInfo);
+ bool ParameterPack, TypeSourceInfo *TInfo) {
+ return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, ParameterPack,
+ TInfo);
}
SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 5d0e0e3093..d8bb0af018 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -208,8 +208,14 @@ void DeclRefExpr::computeDependence() {
// member of an unknown specialization.
// (handled by DependentScopeDeclRefExpr)
- // FIXME: Variadic templates require that we compute whether this
- // declaration reference contains an unexpanded parameter pack.
+ // Determine whether this expression contains any unexpanded parameter
+ // packs.
+ // Is the declaration a parameter pack?
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
+ if (NTTP->isParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+ }
+ // FIXME: Variadic templates function parameter packs.
}
DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier,
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 7357e94490..a487825bb3 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -632,16 +632,12 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
Invalid = true;
}
- if (D.hasEllipsis()) {
- // FIXME: Variadic templates.
- Diag(D.getEllipsisLoc(), diag::err_non_type_parameter_pack_unsupported);
- Invalid = true;
- }
-
+ bool IsParameterPack = D.hasEllipsis();
NonTypeTemplateParmDecl *Param
= NonTypeTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(),
D.getIdentifierLoc(),
- Depth, Position, ParamName, T, TInfo);
+ Depth, Position, ParamName, T,
+ IsParameterPack, TInfo);
if (Invalid)
Param->setInvalidDecl();
@@ -652,7 +648,7 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
}
// Check the well-formedness of the default template argument, if provided.
- if (Default) {
+ if (Default) {
// Check for unexpanded parameter packs.
if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument))
return Param;
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 54c509544f..9db3a8cacf 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1506,11 +1506,12 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
Invalid = true;
}
+ // FIXME: Variadic templates.
NonTypeTemplateParmDecl *Param
= NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(),
D->getDepth() - TemplateArgs.getNumLevels(),
D->getPosition(), D->getIdentifier(), T,
- DI);
+ D->isParameterPack(), DI);
if (Invalid)
Param->setInvalidDecl();
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index d9c7e72a86..fe30ba5845 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -63,8 +63,21 @@ namespace {
return true;
}
- // FIXME: Record occurrences of non-type and template template
- // parameter packs.
+ /// \brief Record occurrences of (FIXME: function and) non-type template
+ /// parameter packs in an expression.
+ bool VisitDeclRefExpr(DeclRefExpr *E) {
+ if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(E->getDecl())) {
+ if (NTTP->isParameterPack())
+ Unexpanded.push_back(std::make_pair(NTTP, E->getLocation()));
+ }
+
+ // FIXME: Function parameter packs.
+
+ return true;
+ }
+
+ // FIXME: Record occurrences of template template parameter packs.
// FIXME: Once we have pack expansions in the AST, block their
// traversal.
@@ -95,8 +108,8 @@ namespace {
/// \brief Suppress traversel into types with location information
/// that do not contain unexpanded parameter packs.
bool TraverseTypeLoc(TypeLoc TL) {
- if (!TL.getType().isNull() && TL.
- getType()->containsUnexpandedParameterPack())
+ if (!TL.getType().isNull() &&
+ TL.getType()->containsUnexpandedParameterPack())
return inherited::TraverseTypeLoc(TL);
return true;
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index e693c8d4da..46ec0fe109 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1504,6 +1504,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// it expands those parameter packs.
if (T->containsUnexpandedParameterPack())
T = Context.getPackExpansionType(T);
+ else if (!getLangOptions().CPlusPlus0x)
+ Diag(D.getEllipsisLoc(), diag::err_variadic_templates);
break;
case Declarator::FileContext:
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 6100d65757..f2183ea695 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -1156,6 +1156,7 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
D->setDepth(Record[Idx++]);
D->setPosition(Record[Idx++]);
// Rest of NonTypeTemplateParmDecl.
+ D->ParameterPack = Record[Idx++];
if (Record[Idx++]) {
Expr *DefArg = Reader.ReadExpr(F);
bool Inherited = Record[Idx++];
@@ -1429,7 +1430,7 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
break;
case DECL_NON_TYPE_TEMPLATE_PARM:
D = NonTypeTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0,0,0,
- QualType(),0);
+ QualType(), false, 0);
break;
case DECL_TEMPLATE_TEMPLATE_PARM:
D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(),0,0,0,0);
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index aa145c415b..add6cd343d 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -994,6 +994,7 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
Record.push_back(D->getDepth());
Record.push_back(D->getPosition());
// Rest of NonTypeTemplateParmDecl.
+ Record.push_back(D->isParameterPack());
Record.push_back(D->getDefaultArgument() != 0);
if (D->getDefaultArgument()) {
Writer.AddStmt(D->getDefaultArgument());
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
index 59a0e7538d..d6df2370ad 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
@@ -11,12 +11,12 @@ void f1(const Types &...args); // FIXME: temporary expected-error{{clang does no
// [ Note: Otherwise, the parameter-declaration is part of a
// template-parameter-list and the parameter pack is a template
// parameter pack; see 14.1. -- end note ]
-template<int ...N> // FIXME: temporary expected-error{{clang does not yet support non-type template parameter packs}}
+template<int ...N>
struct X0 { };
template<typename ...Types>
struct X1 {
- template<Types ...Values> struct Inner; // FIXME: temporary expected-error{{clang does not yet support non-type template parameter packs}}
+ template<Types ...Values> struct Inner;
};
// A declarator-id or abstract-declarator containing an ellipsis shall
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
index aff9b44539..47581fee90 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
@@ -128,6 +128,26 @@ struct TestPPName
};
// FIXME: Test for unexpanded parameter packs in each of the expression nodes.
+template<int ...Values>
+void test_unexpanded_in_exprs() {
+ // PredefinedExpr is uninteresting
+ // DeclRefExpr
+ Values; // expected-error{{expression contains unexpanded parameter pack 'Values'}}
+ // IntegerLiteral is uninteresting
+ // FloatingLiteral is uninteresting
+ // ImaginaryLiteral is uninteresting
+ // StringLiteral is uninteresting
+ // CharacterLiteral is uninteresting
+ (Values); // expected-error{{expression contains unexpanded parameter pack 'Values'}}
+ // UnaryOperator
+ -Values; // expected-error{{expression contains unexpanded parameter pack 'Values'}}
+ // OffsetOfExpr
+ struct OffsetMe {
+ int array[17];
+ };
+ __builtin_offsetof(OffsetMe, array[Values]); // expected-error{{expression contains unexpanded parameter pack 'Values'}}
+ // FIXME: continue this...
+}
template<typename ... Types>
void TestPPNameFunc(int i) {