From: Douglas Gregor Date: Thu, 16 Dec 2010 08:48:57 +0000 (+0000) Subject: Check for unexpanded parameter packs in default arguments. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6f52675ec400a0ee89ec6214c4845b8ee274304a;p=clang Check for unexpanded parameter packs in default arguments. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@121962 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 617bc62bc9..1d3239b3d4 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1824,22 +1824,26 @@ def note_template_parameter_pack_here : Note< def err_unexpanded_parameter_pack_0 : Error< "%select{expression|base type|declaration type|data member type|bit-field " "size|static assertion|fixed underlying type|enumerator value|" - "using declaration|friend declaration|qualifier|initializer}0 " + "using declaration|friend declaration|qualifier|initializer|default argument" + "}0 " "contains an unexpanded parameter pack">; def err_unexpanded_parameter_pack_1 : Error< "%select{expression|base type|declaration type|data member type|bit-field " "size|static assertion|fixed underlying type|enumerator value|" - "using declaration|friend declaration|qualifier|initializer}0 " + "using declaration|friend declaration|qualifier|initializer|default argument" + "}0 " "contains unexpanded parameter pack %1">; def err_unexpanded_parameter_pack_2 : Error< "%select{expression|base type|declaration type|data member type|bit-field " "size|static assertion|fixed underlying type|enumerator value|" - "using declaration|friend declaration|qualifier|initializer}0 " + "using declaration|friend declaration|qualifier|initializer|default argument" + "}0 " "contains unexpanded parameter packs %1 and %2">; def err_unexpanded_parameter_pack_3_or_more : Error< "%select{expression|base type|declaration type|data member type|bit-field " "size|static assertion|fixed underlying type|enumerator value|" - "using declaration|friend declaration|qualifier|initializer}0 " + "using declaration|friend declaration|qualifier|initializer|default argument" + "}0 " "contains unexpanded parameter packs %1, %2, ...">; def err_unexpected_typedef : Error< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 32a658ae4b..db0faa806d 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3169,7 +3169,10 @@ public: UPPC_DeclarationQualifier, /// \brief An initializer. - UPPC_Initializer + UPPC_Initializer, + + /// \brief A default argument. + UPPC_DefaultArgument }; /// \brief If the given type contains an unexpanded parameter pack, @@ -3214,6 +3217,19 @@ public: bool DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, UnexpandedParameterPackContext UPPC); + /// \brief If the given template name contains an unexpanded parameter pack, + /// diagnose the error. + /// + /// \param Loc The location of the template name. + /// + /// \param Template The template name that is being checked for unexpanded + /// parameter packs. + /// + /// \returns true if an error ocurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, + TemplateName Template, + UnexpandedParameterPackContext UPPC); + /// \brief Describes the result of template argument deduction. /// /// The TemplateDeductionResult enumeration describes the result of diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 30e8b1e28e..54e69a1111 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -177,6 +177,12 @@ Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc, return; } + // Check for unexpanded parameter packs. + if (DiagnoseUnexpandedParameterPack(DefaultArg, UPPC_DefaultArgument)) { + Param->setInvalidDecl(); + return; + } + // Check that the default argument is well-formed CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg, this); if (DefaultArgChecker.Visit(DefaultArg)) { diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 4b8c455731..a79c17cdbf 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -536,6 +536,11 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, Diag(EqualLoc, diag::err_template_param_pack_default_arg); return Param; } + + // Check for unexpanded parameter packs. + if (DiagnoseUnexpandedParameterPack(Loc, DefaultTInfo, + UPPC_DefaultArgument)) + return Param; // Check the template argument itself. if (CheckTemplateArgument(Param, DefaultTInfo)) { @@ -642,6 +647,10 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, // Check the well-formedness of the default template argument, if provided. if (Default) { + // Check for unexpanded parameter packs. + if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument)) + return Param; + TemplateArgument Converted; if (CheckTemplateArgument(Param, Param->getType(), Default, Converted)) { Param->setInvalidDecl(); @@ -683,6 +692,12 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, IdResolver.AddDecl(Param); } + if (Params->size() == 0) { + Diag(Param->getLocation(), diag::err_template_template_parm_no_parms) + << SourceRange(Params->getLAngleLoc(), Params->getRAngleLoc()); + Param->setInvalidDecl(); + } + 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 @@ -699,14 +714,15 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, return Param; } + // Check for unexpanded parameter packs. + if (DiagnoseUnexpandedParameterPack(DefaultArg.getLocation(), + DefaultArg.getArgument().getAsTemplate(), + UPPC_DefaultArgument)) + return Param; + Param->setDefaultArgument(DefaultArg, false); } - if (Params->size() == 0) { - Diag(Param->getLocation(), diag::err_template_template_parm_no_parms) - << SourceRange(Params->getLAngleLoc(), Params->getRAngleLoc()); - Param->setInvalidDecl(); - } return Param; } diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 07873efdac..20b05d59d3 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -238,3 +238,19 @@ bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, DiagnoseUnexpandedParameterPacks(*this, NameInfo.getLoc(), UPPC, Unexpanded); return true; } + +bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc, + TemplateName Template, + UnexpandedParameterPackContext UPPC) { + + if (Template.isNull() || !Template.containsUnexpandedParameterPack()) + return false; + + llvm::SmallVector Unexpanded; + CollectUnexpandedParameterPacksVisitor(Unexpanded) + .TraverseTemplateName(Template); + assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); + DiagnoseUnexpandedParameterPacks(*this, Loc, UPPC, Unexpanded); + return true; +} + diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp index 94bcfe6ed2..2352234f86 100644 --- a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp +++ b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp @@ -132,6 +132,15 @@ struct TestUnexpandedDecls : T{ T direct_init(0, static_cast(0)); // expected-error{{expression contains unexpanded parameter pack 'Types'}} T list_init = { static_cast(0) }; // expected-error{{initializer contains unexpanded parameter pack 'Types'}} } + + void default_function_args(T = static_cast(0)); // expected-error{{default argument contains unexpanded parameter pack 'Types'}} + + template // expected-error{{default argument contains unexpanded parameter pack 'Types'}} + struct default_template_args_1; + template(0)> // expected-error{{default argument contains unexpanded parameter pack 'Types'}} + struct default_template_args_2; + template class = Types::template apply> // expected-error{{default argument contains unexpanded parameter pack 'Types'}} + struct default_template_args_3; }; // Test for diagnostics in the presence of multiple unexpanded