From 03f1eb031b84e93415b792c4b45d8da71c88e92d Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 15 Jun 2012 16:59:29 +0000 Subject: [PATCH] Check the parameter lists and return type of both blocks and lambdas for unexpanded parameter packs. Fixes the crash-on-invalid in PR13117. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158525 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 8 +++---- include/clang/Parse/Parser.h | 2 +- include/clang/Sema/Sema.h | 11 ++++++++-- lib/Parse/ParseExpr.cpp | 10 ++++----- lib/Sema/SemaExpr.cpp | 15 ++++++++++++- lib/Sema/SemaLambda.cpp | 19 ++++++++++++++++- .../expr/expr.prim/expr.prim.lambda/blocks.mm | 21 +++++++++++++++++++ 7 files changed, 72 insertions(+), 14 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 235c6abdae..e98c9f613b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2859,28 +2859,28 @@ def err_unexpanded_parameter_pack_0 : Error< "size|static assertion|fixed underlying type|enumerator value|" "using declaration|friend declaration|qualifier|initializer|default argument|" "non-type template parameter type|exception type|partial specialization|" - "__if_exists name|__if_not_exists name}0 " + "__if_exists name|__if_not_exists name|lambda|block}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|default argument|" "non-type template parameter type|exception type|partial specialization|" - "__if_exists name|__if_not_exists name}0 " + "__if_exists name|__if_not_exists name|lambda|block}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|default argument|" "non-type template parameter type|exception type|partial specialization|" - "__if_exists name|__if_not_exists name}0 " + "__if_exists name|__if_not_exists name|lambda|block}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|default argument|" "non-type template parameter type|exception type|partial specialization|" - "__if_exists name|__if_not_exists name}0 " + "__if_exists name|__if_not_exists name|lambda|block}0 " "contains unexpanded parameter packs %1, %2, ...">; def err_pack_expansion_without_parameter_packs : Error< diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index c69e5cea7d..395c5e0c1f 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1711,7 +1711,7 @@ private: = Declarator::TypeNameContext, AccessSpecifier AS = AS_none, Decl **OwnedType = 0); - void ParseBlockId(); + void ParseBlockId(SourceLocation CaretLoc); // Check for the start of a C++11 attribute-specifier-seq in a context where // an attribute is not allowed. diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 0aeba1d892..868fab74cb 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3118,7 +3118,8 @@ public: /// ActOnBlockArguments - This callback allows processing of block arguments. /// If there are no arguments, this is still invoked. - void ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope); + void ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, + Scope *CurScope); /// ActOnBlockError - If there is an error parsing a block, this callback /// is invoked to pop the information about the block from the action impl. @@ -4960,7 +4961,13 @@ public: UPPC_IfExists, /// \brief Microsoft __if_not_exists. - UPPC_IfNotExists + UPPC_IfNotExists, + + /// \brief Lambda expression. + UPPC_Lambda, + + /// \brief Block expression, + UPPC_Block }; /// \brief Diagnose unexpanded parameter packs. diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index cc5e1932e0..f9c148d810 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -2299,7 +2299,7 @@ bool Parser::ParseExpressionList(SmallVectorImpl &Exprs, /// [clang] block-id: /// [clang] specifier-qualifier-list block-declarator /// -void Parser::ParseBlockId() { +void Parser::ParseBlockId(SourceLocation CaretLoc) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); return cutOffParsing(); @@ -2319,7 +2319,7 @@ void Parser::ParseBlockId() { MaybeParseGNUAttributes(DeclaratorInfo); // Inform sema that we are starting a block. - Actions.ActOnBlockArguments(DeclaratorInfo, getCurScope()); + Actions.ActOnBlockArguments(CaretLoc, DeclaratorInfo, getCurScope()); } /// ParseBlockLiteralExpression - Parse a block literal, which roughly looks @@ -2376,9 +2376,9 @@ ExprResult Parser::ParseBlockLiteralExpression() { MaybeParseGNUAttributes(ParamInfo); // Inform sema that we are starting a block. - Actions.ActOnBlockArguments(ParamInfo, getCurScope()); + Actions.ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope()); } else if (!Tok.is(tok::l_brace)) { - ParseBlockId(); + ParseBlockId(CaretLoc); } else { // Otherwise, pretend we saw (void). ParsedAttributes attrs(AttrFactory); @@ -2399,7 +2399,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { MaybeParseGNUAttributes(ParamInfo); // Inform sema that we are starting a block. - Actions.ActOnBlockArguments(ParamInfo, getCurScope()); + Actions.ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope()); } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 0ca46d0505..bc0188f10b 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9086,7 +9086,8 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) { PushExpressionEvaluationContext(PotentiallyEvaluated); } -void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { +void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, + Scope *CurScope) { assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!"); assert(ParamInfo.getContext() == Declarator::BlockLiteralContext); BlockScopeInfo *CurBlock = getCurBlock(); @@ -9094,6 +9095,18 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { TypeSourceInfo *Sig = GetTypeForDeclarator(ParamInfo, CurScope); QualType T = Sig->getType(); + // FIXME: We should allow unexpanded parameter packs here, but that would, + // in turn, make the block expression contain unexpanded parameter packs. + if (DiagnoseUnexpandedParameterPack(CaretLoc, Sig, UPPC_Block)) { + // Drop the parameters. + FunctionProtoType::ExtProtoInfo EPI; + EPI.HasTrailingReturn = false; + EPI.TypeQuals |= DeclSpec::TQ_const; + T = Context.getFunctionType(Context.DependentTy, /*Args=*/0, /*NumArgs=*/0, + EPI); + Sig = Context.getTrivialTypeSourceInfo(T); + } + // GetTypeForDeclarator always produces a function type for a block // literal signature. Furthermore, it is always a FunctionProtoType // unless the function was written with a typedef. diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index f64be51744..07ee890562 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -269,9 +269,26 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, FunctionProtoTypeLoc Proto = cast(TL); Params = llvm::ArrayRef(Proto.getParmArray(), Proto.getNumArgs()); + + // Check for unexpanded parameter packs in the method type. + // FIXME: We should allow unexpanded parameter packs here, but that would, + // in turn, make the lambda expression contain unexpanded parameter packs. + if (DiagnoseUnexpandedParameterPack(Intro.Range.getBegin(), MethodTyInfo, + UPPC_Lambda)) { + // Drop the parameters. + Params = llvm::ArrayRef(); + FunctionProtoType::ExtProtoInfo EPI; + EPI.HasTrailingReturn = false; + EPI.TypeQuals |= DeclSpec::TQ_const; + QualType MethodTy = Context.getFunctionType(Context.DependentTy, + /*Args=*/0, /*NumArgs=*/0, EPI); + MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy); + ExplicitParams = false; + ExplicitResultType = false; + } } - CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range, + CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params); if (ExplicitParams) diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm b/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm index 0c3fdb2d80..6a6e0d9c90 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm @@ -86,3 +86,24 @@ namespace overloading { int &ir = accept_lambda_conv([](int x) { return x + 1; }); } } + +namespace PR13117 { + struct A { + template static void f1() + { + (void)^(Args args) { // expected-error{{block contains unexpanded parameter pack 'Args'}} + }; + } + + template static void f2() + { + (void)[](Args args) { // expected-error{{lambda contains unexpanded parameter pack 'Args'}} + }; + } + }; + + void g() { + A::f1(); + A::f2(); + } +} -- 2.40.0