]> granicus.if.org Git - clang/commitdiff
Check the parameter lists and return type of both blocks and lambdas
authorDouglas Gregor <dgregor@apple.com>
Fri, 15 Jun 2012 16:59:29 +0000 (16:59 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 15 Jun 2012 16:59:29 +0000 (16:59 +0000)
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
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
lib/Parse/ParseExpr.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaLambda.cpp
test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm

index 235c6abdaee349fdf01587b32f395f8f309a77b9..e98c9f613b6863d1572bbdae3dc434263f1cee0a 100644 (file)
@@ -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<
index c69e5cea7ddaeb266faa3915850a0f20b19fcb4d..395c5e0c1f544daadb443a2ad5ebb8a6b894156f 100644 (file)
@@ -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.
index 0aeba1d892f6f419d7783b24fed2eed4e562b082..868fab74cb30461991fc17c62d53dcfca5de634e 100644 (file)
@@ -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.
index cc5e1932e000bb13e6be9849c6bc839a577a5909..f9c148d810aa2655c181ae912f1ea9882c795181 100644 (file)
@@ -2299,7 +2299,7 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &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());
   }
 
 
index 0ca46d05056934eaf770474968043d55ccacc1cc..bc0188f10b42d2a81a4995e2125834758e397fea 100644 (file)
@@ -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.
index f64be51744d432092cea117110091e1a63f8f1ad..07ee8905629bbc49ccc4dc8f31a3a04fcb838233 100644 (file)
@@ -269,9 +269,26 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
     FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
     Params = llvm::ArrayRef<ParmVarDecl *>(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<ParmVarDecl *>();
+      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)
index 0c3fdb2d80eb39cc020661b0b71cc560d2d7765d..6a6e0d9c909ea2ec8af2b335b7b4ed98f8c4529d 100644 (file)
@@ -86,3 +86,24 @@ namespace overloading {
     int &ir = accept_lambda_conv([](int x) { return x + 1; });
   }
 }
+
+namespace PR13117 {
+  struct A {
+    template<typename ... Args> static void f1()
+    {
+      (void)^(Args args) { // expected-error{{block contains unexpanded parameter pack 'Args'}}
+      };
+    }
+
+    template<typename ... Args> static void f2()
+    {
+      (void)[](Args args) { // expected-error{{lambda contains unexpanded parameter pack 'Args'}}
+      };
+    }
+  };
+
+  void g() {
+    A::f1<int, int>();
+    A::f2<int, int>();
+  }
+}