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.

llvm-svn: 122527
This commit is contained in:
Douglas Gregor 2010-12-23 23:51:58 +00:00
parent d71ffbcb24
commit da3cc0d3bf
18 changed files with 93 additions and 30 deletions

View File

@ -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; }

View File

@ -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)

View File

@ -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<

View File

@ -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 "

View File

@ -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">;

View File

@ -109,6 +109,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
SourceLocation(), NTTP->getDepth(),
NTTP->getPosition(), 0,
getCanonicalType(NTTP->getType()),
NTTP->isParameterPack(),
0));
else
CanonParams.push_back(getCanonicalTemplateTemplateParmDecl(

View File

@ -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 *

View File

@ -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;
}

View File

@ -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 {

View File

@ -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,

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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:

View File

@ -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);

View File

@ -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());

View File

@ -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

View File

@ -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) {