[cfe-commits] r63784 - in /cfe/trunk: include/clang/Parse/Action.h include/clang/Parse/DeclSpec.h include/clang/Parse/Parser.h lib/Parse/ParseExpr.cpp lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaStmt.cpp lib/Sema/SemaType.cpp test/Sema/block-explicit-return-type.c test/Sema/block-return.c test/Sema/block-syntax-error.c

Mike Stump mrs at apple.com
Wed Feb 4 14:31:33 PST 2009


Author: mrs
Date: Wed Feb  4 16:31:32 2009
New Revision: 63784

URL: http://llvm.org/viewvc/llvm-project?rev=63784&view=rev
Log:
Add support for blocks with explicit return types.

Added:
    cfe/trunk/test/Sema/block-explicit-return-type.c
Modified:
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/DeclSpec.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/Sema/block-return.c
    cfe/trunk/test/Sema/block-syntax-error.c

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=63784&r1=63783&r2=63784&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Wed Feb  4 16:31:32 2009
@@ -772,7 +772,7 @@
 
   /// ActOnBlockArguments - This callback allows processing of block arguments.
   /// If there are no arguments, this is still invoked.
-  virtual void ActOnBlockArguments(Declarator &ParamInfo) {}
+  virtual void ActOnBlockArguments(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.

Modified: cfe/trunk/include/clang/Parse/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/DeclSpec.h?rev=63784&r1=63783&r2=63784&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Parse/DeclSpec.h Wed Feb  4 16:31:32 2009
@@ -695,7 +695,8 @@
     ForContext,          // Declaration within first part of a for loop.
     ConditionContext,    // Condition declaration in a C++ if/switch/while/for.
     TemplateParamContext,// Within a template parameter list.
-    CXXCatchContext      // C++ catch exception-declaration
+    CXXCatchContext,     // C++ catch exception-declaration
+    BlockLiteralContext  // Block literal declarator.
   };
 
   /// DeclaratorKind - The kind of declarator this represents.
@@ -813,14 +814,15 @@
   /// parameter lists.
   bool mayOmitIdentifier() const {
     return Context == TypeNameContext || Context == PrototypeContext ||
-           Context == TemplateParamContext || Context == CXXCatchContext;
+           Context == TemplateParamContext || Context == CXXCatchContext ||
+           Context == BlockLiteralContext;
   }
 
   /// mayHaveIdentifier - Return true if the identifier is either optional or
   /// required.  This is true for normal declarators and prototypes, but not
   /// typenames.
   bool mayHaveIdentifier() const {
-    return Context != TypeNameContext;
+    return Context != TypeNameContext && Context != BlockLiteralContext;
   }
 
   /// mayBeFollowedByCXXDirectInit - Return true if the declarator can be

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=63784&r1=63783&r2=63784&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Wed Feb  4 16:31:32 2009
@@ -898,6 +898,7 @@
 
 
   TypeTy *ParseTypeName();
+  void ParseBlockId();
   AttributeList *ParseAttributes();
   void FuzzyParseMicrosoftDeclSpec();
   void ParseTypeofSpecifier(DeclSpec &DS);

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=63784&r1=63783&r2=63784&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Wed Feb  4 16:31:32 2009
@@ -1211,11 +1211,29 @@
   }
 }
 
+/// ParseBlockId - Parse a block-id, which roughly looks like int (int x).
+///
+/// [clang] block-id:
+/// [clang]   specifier-qualifier-list block-declarator
+///
+void Parser::ParseBlockId() {
+  // Parse the specifier-qualifier-list piece.
+  DeclSpec DS;
+  ParseSpecifierQualifierList(DS);
+
+  // Parse the block-declarator.
+  Declarator DeclaratorInfo(DS, Declarator::BlockLiteralContext);
+  ParseDeclarator(DeclaratorInfo);
+  // Inform sema that we are starting a block.
+  Actions.ActOnBlockArguments(DeclaratorInfo, CurScope);
+}
+
 /// ParseBlockLiteralExpression - Parse a block literal, which roughly looks
 /// like ^(int x){ return x+1; }
 ///
 ///         block-literal:
 /// [clang]   '^' block-args[opt] compound-statement
+/// [clang]   '^' block-id compound-statement
 /// [clang] block-args:
 /// [clang]   '(' parameter-list ')'
 ///
@@ -1235,7 +1253,7 @@
 
   // Parse the return type if present.
   DeclSpec DS;
-  Declarator ParamInfo(DS, Declarator::PrototypeContext);
+  Declarator ParamInfo(DS, Declarator::BlockLiteralContext);
 
   // If this block has arguments, parse them.  There is no ambiguity here with
   // the expression case, because the expression case requires a parameter list.
@@ -1244,20 +1262,24 @@
     // Parse the pieces after the identifier as if we had "int(...)".
     ParamInfo.SetIdentifier(0, CaretLoc);
     if (ParamInfo.getInvalidType()) {
-      // If there was an error parsing the arguments, they may have tried to use
-      // ^(x+y) which requires an argument list.  Just skip the whole block
-      // literal.
+      // If there was an error parsing the arguments, they may have
+      // tried to use ^(x+y) which requires an argument list.  Just
+      // skip the whole block literal.
       return ExprError();
     }
+    // Inform sema that we are starting a block.
+    Actions.ActOnBlockArguments(ParamInfo, CurScope);
+  } else if (! Tok.is(tok::l_brace)) {
+    ParseBlockId();
   } else {
     // Otherwise, pretend we saw (void).
     ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
                                                        0, 0, 0, CaretLoc,
                                                        ParamInfo));
+    // Inform sema that we are starting a block.
+    Actions.ActOnBlockArguments(ParamInfo, CurScope);
   }
 
-  // Inform sema that we are starting a block.
-  Actions.ActOnBlockArguments(ParamInfo);
 
   OwningExprResult Result(Actions, true);
   if (Tok.is(tok::l_brace)) {

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=63784&r1=63783&r2=63784&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Feb  4 16:31:32 2009
@@ -1209,7 +1209,7 @@
   
   /// ActOnBlockArguments - This callback allows processing of block arguments.
   /// If there are no arguments, this is still invoked.
-  virtual void ActOnBlockArguments(Declarator &ParamInfo);
+  virtual void ActOnBlockArguments(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.

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=63784&r1=63783&r2=63784&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Feb  4 16:31:32 2009
@@ -4179,12 +4179,36 @@
   PushDeclContext(BlockScope, BSI->TheDecl);
 }
 
-void Sema::ActOnBlockArguments(Declarator &ParamInfo) {
+void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
+  assert(ParamInfo.getIdentifier() == 0 && "block-id should have no identifier!");
+
+  if (ParamInfo.getNumTypeObjects() == 0
+      || ParamInfo.getTypeObject(0).Kind != DeclaratorChunk::Function) {
+    QualType T = GetTypeForDeclarator(ParamInfo, CurScope);
+
+    // The type is entirely optional as well, if none, use DependentTy.
+    if (T.isNull())
+      T = Context.DependentTy;
+
+    // The parameter list is optional, if there was none, assume ().
+    if (!T->isFunctionType())
+      T = Context.getFunctionType(T, NULL, 0, 0, 0);
+
+    CurBlock->hasPrototype = true;
+    CurBlock->isVariadic = false;
+    Type *RetTy = T.getTypePtr()->getAsFunctionType()->getResultType()
+      .getTypePtr();
+
+    if (!RetTy->isDependentType())
+      CurBlock->ReturnType = RetTy;
+    return;
+  }
+
   // Analyze arguments to block.
   assert(ParamInfo.getTypeObject(0).Kind == DeclaratorChunk::Function &&
          "Not a function declarator!");
   DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getTypeObject(0).Fun;
-  
+ 
   CurBlock->hasPrototype = FTI.hasPrototype;
   CurBlock->isVariadic = true;
   
@@ -4200,6 +4224,13 @@
     for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
       CurBlock->Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param);
     CurBlock->isVariadic = FTI.isVariadic;
+    QualType T = GetTypeForDeclarator (ParamInfo, CurScope);
+
+    Type* RetTy = T.getTypePtr()->getAsFunctionType()->getResultType()
+      .getTypePtr();
+
+    if (!RetTy->isDependentType())
+      CurBlock->ReturnType = RetTy;
   }
   CurBlock->TheDecl->setArgs(&CurBlock->Params[0], CurBlock->Params.size());
   

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=63784&r1=63783&r2=63784&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Wed Feb  4 16:31:32 2009
@@ -731,8 +731,8 @@
       CurBlock->ReturnType = RetValExp->getType().getTypePtr();
     } else
       CurBlock->ReturnType = Context.VoidTy.getTypePtr();
-    return Owned(new ReturnStmt(ReturnLoc, RetValExp));
   }
+  QualType FnRetType = QualType(CurBlock->ReturnType, 0);
 
   // Otherwise, verify that this result type matches the previous one.  We are
   // pickier with blocks than for normal functions because we don't have GCC
@@ -749,21 +749,22 @@
   if (!RetValExp)
     return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));
 
-  // we have a non-void block with an expression, continue checking
-  QualType RetValType = RetValExp->getType();
+  if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
+    // we have a non-void block with an expression, continue checking
+    QualType RetValType = RetValExp->getType();
 
-  // For now, restrict multiple return statements in a block to have 
-  // strict compatible types only.
-  QualType BlockQT = QualType(CurBlock->ReturnType, 0);
-  if (Context.getCanonicalType(BlockQT).getTypePtr() 
-      != Context.getCanonicalType(RetValType).getTypePtr()) {
-    // FIXME: non-localizable string in diagnostic
-    DiagnoseAssignmentResult(Incompatible, ReturnLoc, BlockQT,
-                             RetValType, RetValExp, "returning");
-    return StmtError();
-  }
+    // C99 6.8.6.4p3(136): The return statement is not an assignment. The 
+    // overlap restriction of subclause 6.5.16.1 does not apply to the case of 
+    // function return.
 
-  if (RetValExp) CheckReturnStackAddr(RetValExp, BlockQT, ReturnLoc);
+    // In C++ the return statement is handled via a copy initialization.
+    // the C version of which boils down to CheckSingleAssignmentConstraints.
+    // FIXME: Leaks RetValExp.
+    if (PerformCopyInitialization(RetValExp, FnRetType, "returning"))
+      return StmtError();
+
+    if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+  }
 
   return Owned(new ReturnStmt(ReturnLoc, RetValExp));
 }

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=63784&r1=63783&r2=63784&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Wed Feb  4 16:31:32 2009
@@ -251,9 +251,20 @@
   return Result;
 }
 
-/// GetTypeForDeclarator - Convert the type for the specified declarator to Type
-/// instances. Skip the outermost Skip type objects.
+/// GetTypeForDeclarator - Convert the type for the specified
+/// declarator to Type instances. Skip the outermost Skip type
+/// objects.
 QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {
+  bool OmittedReturnType = false;
+
+  if (D.getContext() == Declarator::BlockLiteralContext
+      && Skip == 0
+      && !D.getDeclSpec().hasTypeSpecifier()
+      && (D.getNumTypeObjects() == 0
+          || (D.getNumTypeObjects() == 1
+              && D.getTypeObject(0).Kind == DeclaratorChunk::Function)))
+    OmittedReturnType = true;
+
   // long long is a C99 feature.
   if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x &&
       D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong)
@@ -265,9 +276,16 @@
   switch (D.getKind()) {
   case Declarator::DK_Abstract:
   case Declarator::DK_Normal:
-  case Declarator::DK_Operator:
-    T = ConvertDeclSpecToType(D.getDeclSpec());
+  case Declarator::DK_Operator: {
+    const DeclSpec& DS = D.getDeclSpec();
+    if (OmittedReturnType)
+      // We default to a dependent type initially.  Can be modified by
+      // the first return statement.
+      T = Context.DependentTy;
+    else
+      T = ConvertDeclSpecToType(DS);
     break;
+  }
 
   case Declarator::DK_Constructor:
   case Declarator::DK_Destructor:
@@ -279,8 +297,9 @@
     break;
   }
 
-  // Walk the DeclTypeInfo, building the recursive type as we go.  DeclTypeInfos
-  // are ordered from the identifier out, which is opposite of what we want :).
+  // Walk the DeclTypeInfo, building the recursive type as we go.
+  // DeclTypeInfos are ordered from the identifier out, which is
+  // opposite of what we want :).
   for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) {
     DeclaratorChunk &DeclType = D.getTypeObject(e-i-1+Skip);
     switch (DeclType.Kind) {

Added: cfe/trunk/test/Sema/block-explicit-return-type.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/block-explicit-return-type.c?rev=63784&view=auto

==============================================================================
--- cfe/trunk/test/Sema/block-explicit-return-type.c (added)
+++ cfe/trunk/test/Sema/block-explicit-return-type.c Wed Feb  4 16:31:32 2009
@@ -0,0 +1,81 @@
+// RUN: clang -ObjC -fsyntax-only %s -verify -fblocks
+// FIXME: should compile
+// Test for blocks with explicit return type specified.
+
+typedef float * PF;
+float gf;
+
+ at interface NSView
+  - (id) some_method_that_returns_id;
+ at end
+
+NSView *some_object;
+
+void some_func (NSView * (^) (id));
+
+typedef struct dispatch_item_s *dispatch_item_t;
+typedef void (^completion_block_t)(void);
+
+typedef double (^myblock)(int);
+double test(myblock I);
+
+int main()
+{
+	 __block int x = 1;
+ 	__block int y = 2;
+
+	(void)^void *{ return 0; };
+
+	(void)^float(float y){ return y; };
+
+	(void)^double (float y, double d)
+           {
+	      if (y)
+	       return d;
+	      else
+	       return y;
+	   };
+
+	const char * (^chb) (int flag, const char *arg, char *arg1) = ^ const char * (int flag, const char *arg, char *arg1) {
+	  if (flag)
+	    return 0;
+	  if (flag == 1)
+	    return arg;
+          else if (flag == 2)
+	    return "";
+	  return arg1; 
+	};
+
+	(void)^PF { return &gf; };
+
+	some_func(^ NSView * (id whatever) { return [some_object some_method_that_returns_id]; });
+
+	double res = test(^(int z){x = y+z; return (double)z; });	
+}
+
+void func()
+{
+  completion_block_t X;
+
+  completion_block_t (^blockx)(dispatch_item_t) = ^completion_block_t (dispatch_item_t item) {
+    return X;
+  };
+
+  completion_block_t (^blocky)(dispatch_item_t) = ^(dispatch_item_t item) {
+    return X;
+  };
+
+  blockx = blocky;
+
+}
+
+
+// intent: block taking int returning block that takes char,int and returns int
+int (^(^block)(double x))(char, short);
+
+void foo() {
+   int one = 1;
+   block = ^(double x){ return ^(char c, short y) { return one + c + y; };};  // expected-error {{returning block that lives on the local stack}}
+   // or:
+   block = ^(double x){ return ^(char c, short y) { return one + (int)c + y; };};  // expected-error {{returning block that lives on the local stack}}
+}

Modified: cfe/trunk/test/Sema/block-return.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/block-return.c?rev=63784&r1=63783&r2=63784&view=diff

==============================================================================
--- cfe/trunk/test/Sema/block-return.c (original)
+++ cfe/trunk/test/Sema/block-return.c Wed Feb  4 16:31:32 2009
@@ -3,24 +3,23 @@
 typedef void (^CL)(void);
 
 CL foo() {
-
-	short y;
-
+  short y;
   short (^add1)(void) = ^{ return y+1; }; // expected-warning {{incompatible block pointer types initializing 'int (^)(void)', expected 'short (^)(void)'}}
 
-	CL X = ^{ 
-    if (2) 
-      return; 
+  CL X = ^{
+    if (2)
+      return;
     return 1;  // expected-error {{void block should not return a value}}
   };
-	int (^Y) (void)  = ^{ 
+
+  int (^Y) (void)  = ^{
     if (3)
       return 1;
     else
       return; // expected-error {{non-void block should return a value}}
   };
 
-	char *(^Z)(void) = ^{ 
+  char *(^Z)(void) = ^{
     if (3)
       return "";
     else
@@ -28,20 +27,20 @@
   };
 
   double (^A)(void) = ^ { // expected-warning {{incompatible block pointer types initializing 'float (^)(void)', expected 'double (^)(void)'}}
-    if (1)	
-      return (float)1.0; 
+    if (1)
+      return (float)1.0;
     else
       if (2)
-       return (double)2.0; // expected-error {{incompatible type returning 'double', expected 'float'}}
-    return 1; // expected-error {{incompatible type returning 'int', expected 'float'}}
+	return (double)2.0;
+    return 1;
   };
-  
-  char *(^B)(void) = ^{ 
+  char *(^B)(void) = ^{
     if (3)
       return "";
     else
-      return 2; // expected-error {{incompatible type returning 'int', expected 'char *'}}
+      return 2; // expected-warning {{incompatible integer to pointer conversion returning 'int', expected 'char *'}}
   };
+
   return ^{ return 1; }; // expected-warning {{incompatible block pointer types returning 'int (^)(void)', expected 'CL'}} expected-error {{returning block that lives on the local stack}}
 }
 

Modified: cfe/trunk/test/Sema/block-syntax-error.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/block-syntax-error.c?rev=63784&r1=63783&r2=63784&view=diff

==============================================================================
--- cfe/trunk/test/Sema/block-syntax-error.c (original)
+++ cfe/trunk/test/Sema/block-syntax-error.c Wed Feb  4 16:31:32 2009
@@ -3,7 +3,5 @@
 void (^noop)(void);
 
 void somefunction() {
-  noop = ^int *{}; // expected-error {{expected expression}}
-
-  noop = ^noop;	// expected-error {{expected expression}}
+  noop = ^noop;	// expected-error {{type name requires a specifier or qualifier}} expected-error {{expected expression}}
 }





More information about the cfe-commits mailing list