forked from OSchip/llvm-project
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:
parent
d71ffbcb24
commit
da3cc0d3bf
|
@ -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; }
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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">;
|
||||
|
|
|
@ -109,6 +109,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
|
|||
SourceLocation(), NTTP->getDepth(),
|
||||
NTTP->getPosition(), 0,
|
||||
getCanonicalType(NTTP->getType()),
|
||||
NTTP->isParameterPack(),
|
||||
0));
|
||||
else
|
||||
CanonParams.push_back(getCanonicalTemplateTemplateParmDecl(
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue