diff options
-rw-r--r-- | clang/include/clang/AST/DeclTemplate.h | 12 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 3 | ||||
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 8 | ||||
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 1 | ||||
-rw-r--r-- | clang/lib/AST/DeclBase.cpp | 5 | ||||
-rw-r--r-- | clang/lib/AST/DeclPrinter.cpp | 7 | ||||
-rw-r--r-- | clang/lib/AST/DeclTemplate.cpp | 5 | ||||
-rw-r--r-- | clang/lib/AST/StmtProfile.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Parse/ParseTemplate.cpp | 31 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 51 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 19 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateVariadic.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriterDecl.cpp | 1 | ||||
-rw-r--r-- | clang/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp | 26 | ||||
-rw-r--r-- | clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp | 5 | ||||
-rw-r--r-- | clang/test/CXX/temp/temp.decls/temp.variadic/parameter-matching.cpp | 2 | ||||
-rw-r--r-- | clang/test/CXX/temp/temp.param/p9-0x.cpp | 4 |
19 files changed, 152 insertions, 51 deletions
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index f2f91786bce..b20aeeb74a0 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1084,18 +1084,22 @@ class TemplateTemplateParmDecl /// Whether or not the default argument was inherited. bool DefaultArgumentWasInherited; + /// \brief Whether this parameter is a parameter pack. + bool ParameterPack; + TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, - unsigned D, unsigned P, + unsigned D, unsigned P, bool ParameterPack, IdentifierInfo *Id, TemplateParameterList *Params) : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), TemplateParmPosition(D, P), DefaultArgument(), - DefaultArgumentWasInherited(false) + DefaultArgumentWasInherited(false), ParameterPack(ParameterPack) { } public: static TemplateTemplateParmDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, - unsigned P, IdentifierInfo *Id, + unsigned P, bool ParameterPack, + IdentifierInfo *Id, TemplateParameterList *Params); using TemplateParmPosition::getDepth; @@ -1108,7 +1112,7 @@ public: /// \code /// template<template <class T> ...MetaFunctions> struct Apply; /// \endcode - bool isParameterPack() const { return /*FIXME: variadic templates*/false; } + bool isParameterPack() const { return ParameterPack; } /// \brief Determine whether this template parameter has a default /// argument. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fac590a82f5..3ec6f05ea44 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2845,12 +2845,13 @@ public: Decl *ActOnTemplateTemplateParameter(Scope *S, SourceLocation TmpLoc, TemplateParamsTy *Params, + SourceLocation EllipsisLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, - const ParsedTemplateArgument &DefaultArg); + ParsedTemplateArgument DefaultArg); TemplateParamsTy * ActOnTemplateParameterList(unsigned Depth, diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 149ecbc5998..b4520609ff7 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -51,7 +51,7 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID, TemplateTemplateParmDecl *Parm) { ID.AddInteger(Parm->getDepth()); ID.AddInteger(Parm->getPosition()); - // FIXME: Parameter pack + ID.AddBoolean(Parm->isParameterPack()); TemplateParameterList *Params = Parm->getTemplateParameters(); ID.AddInteger(Params->size()); @@ -66,7 +66,7 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID, if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { ID.AddInteger(1); - // FIXME: Parameter pack + ID.AddBoolean(NTTP->isParameterPack()); ID.AddPointer(NTTP->getType().getAsOpaquePtr()); continue; } @@ -119,7 +119,9 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( TemplateTemplateParmDecl *CanonTTP = TemplateTemplateParmDecl::Create(*this, getTranslationUnitDecl(), SourceLocation(), TTP->getDepth(), - TTP->getPosition(), 0, + TTP->getPosition(), + TTP->isParameterPack(), + 0, TemplateParameterList::Create(*this, SourceLocation(), SourceLocation(), CanonParams.data(), diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index c62225ef407..70c86320470 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -3444,6 +3444,7 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { return TemplateTemplateParmDecl::Create(Importer.getToContext(), Importer.getToContext().getTranslationUnitDecl(), Loc, D->getDepth(), D->getPosition(), + D->isParameterPack(), Name.getAsIdentifierInfo(), TemplateParams); } diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 75ea2df27e0..700100507b4 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -111,8 +111,11 @@ bool Decl::isTemplateParameterPack() const { if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(this)) return TTP->isParameterPack(); if (const NonTypeTemplateParmDecl *NTTP - = llvm::dyn_cast<NonTypeTemplateParmDecl>(this)) + = dyn_cast<NonTypeTemplateParmDecl>(this)) return NTTP->isParameterPack(); + if (const TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(this)) + return TTP->isParameterPack(); return false; } diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 8941200969e..eaa117a0456 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -699,8 +699,11 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { Out << "> "; - if (isa<TemplateTemplateParmDecl>(D)) { - Out << "class " << D->getName(); + if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) { + Out << "class "; + if (TTP->isParameterPack()) + Out << "..."; + Out << D->getName(); } else { Visit(D->getTemplatedDecl()); } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 0110e3b180c..2755a9e2302 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -412,9 +412,10 @@ SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { TemplateTemplateParmDecl * TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, - IdentifierInfo *Id, + bool ParameterPack, IdentifierInfo *Id, TemplateParameterList *Params) { - return new (C) TemplateTemplateParmDecl(DC, L, D, P, Id, Params); + return new (C) TemplateTemplateParmDecl(DC, L, D, P, ParameterPack, Id, + Params); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index ab24a691240..17a9326cc0b 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -903,7 +903,7 @@ void StmtProfiler::VisitDecl(Decl *D) { if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { ID.AddInteger(NTTP->getDepth()); ID.AddInteger(NTTP->getIndex()); - ID.AddInteger(NTTP->isParameterPack()); + ID.AddBoolean(NTTP->isParameterPack()); VisitType(NTTP->getType()); return; } @@ -921,6 +921,7 @@ void StmtProfiler::VisitDecl(Decl *D) { if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) { ID.AddInteger(TTP->getDepth()); ID.AddInteger(TTP->getIndex()); + ID.AddBoolean(TTP->isParameterPack()); return; } } diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index afa2cc62f9f..8fb6b966733 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -421,12 +421,14 @@ bool Parser::isStartOfTemplateTypeParameter() { /// parameter-declaration /// /// type-parameter: (see below) -/// 'class' ...[opt][C++0x] identifier[opt] +/// 'class' ...[opt] identifier[opt] /// 'class' identifier[opt] '=' type-id -/// 'typename' ...[opt][C++0x] identifier[opt] +/// 'typename' ...[opt] identifier[opt] /// 'typename' identifier[opt] '=' type-id -/// 'template' ...[opt][C++0x] '<' template-parameter-list '>' 'class' identifier[opt] -/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression +/// 'template' '<' template-parameter-list '>' +/// 'class' ...[opt] identifier[opt] +/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] +/// = id-expression Decl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { if (isStartOfTemplateTypeParameter()) return ParseTypeParameter(Depth, Position); @@ -502,8 +504,10 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { /// template parameters. /// /// type-parameter: [C++ temp.param] -/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] -/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression +/// 'template' '<' template-parameter-list '>' 'class' +/// ...[opt] identifier[opt] +/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] +/// = id-expression Decl * Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { assert(Tok.is(tok::kw_template) && "Expected 'template' keyword"); @@ -529,6 +533,15 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { } SourceLocation ClassLoc = ConsumeToken(); + // Parse the ellipsis, if given. + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis)) { + EllipsisLoc = ConsumeToken(); + + if (!getLang().CPlusPlus0x) + Diag(EllipsisLoc, diag::err_variadic_templates); + } + // Get the identifier, if given. SourceLocation NameLoc; IdentifierInfo* ParamName = 0; @@ -569,9 +582,9 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { } return Actions.ActOnTemplateTemplateParameter(getCurScope(), TemplateLoc, - ParamList, ParamName, - NameLoc, Depth, Position, - EqualLoc, DefaultArg); + ParamList, EllipsisLoc, + ParamName, NameLoc, Depth, + Position, EqualLoc, DefaultArg); } /// ParseNonTypeTemplateParameter - Handle the parsing of non-type diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 419f59d5886..a0c89f0fbd6 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -522,6 +522,14 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, IdResolver.AddDecl(Param); } + // C++0x [temp.param]p9: + // A default template-argument may be specified for any kind of + // template-parameter that is not a template parameter pack. + if (DefaultArg && Ellipsis) { + Diag(EqualLoc, diag::err_template_param_pack_default_arg); + DefaultArg = ParsedType(); + } + // Handle the default argument, if provided. if (DefaultArg) { TypeSourceInfo *DefaultTInfo; @@ -529,14 +537,6 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, assert(DefaultTInfo && "expected source information for type"); - // C++0x [temp.param]p9: - // A default template-argument may be specified for any kind of - // template-parameter that is not a template parameter pack. - if (Ellipsis) { - Diag(EqualLoc, diag::err_template_param_pack_default_arg); - return Param; - } - // Check for unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(Loc, DefaultTInfo, UPPC_DefaultArgument)) @@ -647,16 +647,16 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, IdResolver.AddDecl(Param); } + // C++0x [temp.param]p9: + // A default template-argument may be specified for any kind of + // template-parameter that is not a template parameter pack. + if (Default && IsParameterPack) { + Diag(EqualLoc, diag::err_template_param_pack_default_arg); + Default = 0; + } + // Check the well-formedness of the default template argument, if provided. if (Default) { - // C++0x [temp.param]p9: - // A default template-argument may be specified for any kind of - // template-parameter that is not a template parameter pack. - if (IsParameterPack) { - Diag(EqualLoc, diag::err_template_param_pack_default_arg); - return Param; - } - // Check for unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument)) return Param; @@ -679,21 +679,24 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, SourceLocation TmpLoc, TemplateParamsTy *Params, + SourceLocation EllipsisLoc, IdentifierInfo *Name, SourceLocation NameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, - const ParsedTemplateArgument &Default) { + ParsedTemplateArgument Default) { assert(S->isTemplateParamScope() && "Template template parameter not in template parameter scope!"); // Construct the parameter object. + bool IsParameterPack = EllipsisLoc.isValid(); + // FIXME: Pack-ness is dropped TemplateTemplateParmDecl *Param = TemplateTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(), NameLoc.isInvalid()? TmpLoc : NameLoc, - Depth, Position, Name, - Params); + Depth, Position, IsParameterPack, + Name, Params); // If the template template parameter has a name, then link the identifier // into the scope and lookup mechanisms. @@ -708,6 +711,14 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, Param->setInvalidDecl(); } + // C++0x [temp.param]p9: + // A default template-argument may be specified for any kind of + // template-parameter that is not a template parameter pack. + if (IsParameterPack && !Default.isInvalid()) { + Diag(EqualLoc, diag::err_template_param_pack_default_arg); + Default = ParsedTemplateArgument(); + } + if (!Default.isInvalid()) { // Check only that we have a template template argument. We don't want to // try to check well-formedness now, because our template template parameter @@ -1212,7 +1223,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // new declaration. SawDefaultArgument = true; // FIXME: We need to create a new kind of "default argument" - // expression that points to a previous template template + // expression that points to a previous non-type template // parameter. NewNonTypeParm->setDefaultArgument( OldNonTypeParm->getDefaultArgument(), diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 5d724f3b704..a256537068c 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -697,9 +697,22 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { TTP->getPosition())) return D; - // FIXME: Variadic templates index substitution. - TemplateName Template - = TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsTemplate(); + TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition()); + + if (TTP->isParameterPack()) { + 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; + } + + Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex]; + } + + TemplateName Template = Arg.getAsTemplate(); assert(!Template.isNull() && Template.getAsTemplateDecl() && "Wrong kind of template template argument"); return Template.getAsTemplateDecl(); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 60a942ac2fa..92521ae16eb 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1542,8 +1542,8 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl( TemplateTemplateParmDecl *Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), D->getIdentifier(), - InstParams); + D->getPosition(), D->isParameterPack(), + D->getIdentifier(), InstParams); Param->setDefaultArgument(D->getDefaultArgument(), false); // Introduce this template parameter's instantiation into the instantiation diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 4e01ec2407d..acb73144d92 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -78,7 +78,16 @@ namespace { return true; } - // FIXME: Record occurrences of template template parameter packs. + /// \brief Record occurrences of template template parameter packs. + bool TraverseTemplateName(TemplateName Template) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast_or_null<TemplateTemplateParmDecl>( + Template.getAsTemplateDecl())) + if (TTP->isParameterPack()) + Unexpanded.push_back(std::make_pair(TTP, SourceLocation())); + + return inherited::TraverseTemplateName(Template); + } //------------------------------------------------------------------------ // Pruning the search for unexpanded parameter packs. @@ -556,7 +565,6 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S, SourceLocation RParenLoc) { // C++0x [expr.sizeof]p5: // The identifier in a sizeof... expression shall name a parameter pack. - LookupResult R(*this, &Name, NameLoc, LookupOrdinaryName); LookupName(R, S); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 40f3ab7e1b1..239abbeb399 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -1173,6 +1173,7 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(F, Record, Idx); bool IsInherited = Record[Idx++]; D->setDefaultArgument(Arg, IsInherited); + D->ParameterPack = Record[Idx++]; } void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) { @@ -1433,7 +1434,8 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { QualType(), false, 0); break; case DECL_TEMPLATE_TEMPLATE_PARM: - D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(),0,0,0,0); + D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0, 0, + false, 0, 0); break; case DECL_STATIC_ASSERT: D = StaticAssertDecl::Create(*Context, 0, SourceLocation(), 0, 0); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index add6cd343da..ff1f4bf44b8 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -1011,6 +1011,7 @@ void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { // Rest of TemplateTemplateParmDecl. Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record); Record.push_back(D->defaultArgumentWasInherited()); + Record.push_back(D->isParameterPack()); Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM; } diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp index 47b7793da03..3e9e8f5fb27 100644 --- a/clang/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp @@ -138,3 +138,29 @@ namespace Indices { int check0[is_same<build_indices<5>::type, int_tuple<0, 1, 2, 3, 4>>::value? 1 : -1]; } + +namespace TemplateTemplateApply { + template<typename T, template<class> class ...Meta> + struct apply_each { + typedef tuple<typename Meta<T>::type...> type; + }; + + template<typename T> + struct add_reference { + typedef T& type; + }; + + template<typename T> + struct add_pointer { + typedef T* type; + }; + + template<typename T> + struct add_const { + typedef const T type; + }; + + int check0[is_same<apply_each<int, + add_reference, add_pointer, add_const>::type, + tuple<int&, int*, int const>>::value? 1 : -1]; +} diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp index 729a6a0bb28..f0822c34526 100644 --- a/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp @@ -154,6 +154,11 @@ void TestPPNameFunc(int i) { f(static_cast<Types>(i)); // expected-error{{expression contains unexpanded parameter pack 'Types'}} } +template<typename T, template<class> class ...Meta> +struct TestUnexpandedTTP { + typedef tuple<typename Meta<T>::type> type; // expected-error{{declaration type contains unexpanded parameter pack 'Meta'}} +}; + // Test for unexpanded parameter packs in declarations. // FIXME: Attributes? template<typename T, typename... Types> diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/parameter-matching.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/parameter-matching.cpp index 7352be2d72f..126a0961b1c 100644 --- a/clang/test/CXX/temp/temp.decls/temp.variadic/parameter-matching.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.variadic/parameter-matching.cpp @@ -19,3 +19,5 @@ template<template<typename T> class> struct X1tt; // expected-error{{template ty template<template<typename T> class> struct X2tt; // expected-note{{previous template type parameter declared here}} template<template<typename ...T> class> struct X2tt; // expected-error{{template type parameter pack conflicts with previous template type parameter}} + +// FIXME: Add checks for non-type template parameter packs, template parameter packs diff --git a/clang/test/CXX/temp/temp.param/p9-0x.cpp b/clang/test/CXX/temp/temp.param/p9-0x.cpp index 42d1adf2972..1980bc6eaa1 100644 --- a/clang/test/CXX/temp/temp.param/p9-0x.cpp +++ b/clang/test/CXX/temp/temp.param/p9-0x.cpp @@ -8,3 +8,7 @@ struct X0; template<int ...Values = 0> // expected-error{{template parameter pack cannot have a default argument}} struct X1; +template<typename T> struct vector; + +template<template<class> class ...Templates = vector> // expected-error{{template parameter pack cannot have a default argument}} +struct X2; |