[cfe-commits] r55495 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def include/clang/Parse/Action.h include/clang/Parse/DeclSpec.h include/clang/Parse/Parser.h include/clang/Parse/Scope.h lib/AST/ASTContext.cpp lib/Parse/ParseExpr.cpp test/Parser/block-pointer-decl.c

Steve Naroff snaroff at apple.com
Thu Aug 28 12:20:44 PDT 2008


Author: snaroff
Date: Thu Aug 28 14:20:44 2008
New Revision: 55495

URL: http://llvm.org/viewvc/llvm-project?rev=55495&view=rev
Log:
Add parser/action support for block literal expressions.
Parser support for blocks is almost complete...just need to add support for the __block() storage class qualifier.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/DeclSpec.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Parse/Scope.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/test/Parser/block-pointer-decl.c

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=55495&r1=55494&r2=55495&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Thu Aug 28 14:20:44 2008
@@ -1116,6 +1116,10 @@
 // CHECK: use of uninitialized values
 DIAG(warn_uninit_val, WARNING, "use of uninitialized variable")
 
+// Blocks
+DIAG(err_expected_block_lbrace, ERROR,
+     "expected '{' in block literal")
+
 // CFString checking
 DIAG(err_cfstring_literal_not_string_constant, ERROR,
   "CFString literal is not a string constant")

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

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Thu Aug 28 14:20:44 2008
@@ -533,6 +533,27 @@
     return 0;
   }
 
+  //===------------------------- "Block" Extension ------------------------===//
+
+  /// ActOnBlockStart - This callback is invoked when a block literal is
+  /// started.  The result pointer is passed into the block finalizers.
+  virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope,
+                               Declarator &ParamInfo) {}
+  
+  /// ActOnBlockError - If there is an error parsing a block, this callback
+  /// is invoked to pop the information about the block from the action impl.
+  virtual void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {}
+  
+  /// ActOnBlockStmtExpr - This is called when the body of a block statement
+  /// literal was successfully completed.  ^(int x){...}
+  virtual ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, StmtTy *Body,
+                                        Scope *CurScope) { return 0; }
+
+  /// ActOnBlockExprExpr - This is called when the body of a block
+  /// expression literal was successfully completed.  ^(int x)[foo bar: x]
+  virtual ExprResult ActOnBlockExprExpr(SourceLocation CaretLoc, ExprTy *Body,
+                                        Scope *CurScope) { return 0; }
+
   //===------------------------- C++ Declarations -------------------------===//
 
   /// ActOnStartNamespaceDef - This is called at the start of a namespace

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

==============================================================================
--- cfe/trunk/include/clang/Parse/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Parse/DeclSpec.h Thu Aug 28 14:20:44 2008
@@ -481,6 +481,7 @@
     case Reference: return Ref.AttrList;
     case Array:    return 0;
     case Function:  return 0;
+    case BlockPointer: return 0; // FIXME: Do blocks have attr list?
     }
   }
   

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

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Thu Aug 28 14:20:44 2008
@@ -442,6 +442,11 @@
   ExprResult ParseInitializerWithPotentialDesignator();
   
   //===--------------------------------------------------------------------===//
+  // clang Expressions
+  
+  ExprResult ParseBlockLiteralExpression();  // ^{...}
+
+  //===--------------------------------------------------------------------===//
   // Objective-C Expressions
   
   bool isTokObjCMessageIdentifierReceiver() const {

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

==============================================================================
--- cfe/trunk/include/clang/Parse/Scope.h (original)
+++ cfe/trunk/include/clang/Parse/Scope.h Thu Aug 28 14:20:44 2008
@@ -45,7 +45,13 @@
     DeclScope = 0x08,
 
     /// CXXClassScope - The scope of a C++ struct/union/class definition.
-    CXXClassScope = 0x10
+    CXXClassScope = 0x10,
+    
+    /// BlockScope - This is a scope that corresponds to a block object.
+    /// Blocks serve as top-level scopes for some objects like labels, they
+    /// also prevent things like break and continue.  BlockScopes have the
+    /// other flags set as well.
+    BlockScope = 0x20
   };
 private:
   /// The parent scope for this scope.  This is null for the translation-unit

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=55495&r1=55494&r2=55495&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Thu Aug 28 14:20:44 2008
@@ -613,8 +613,8 @@
 /// getBlockPointerType - Return the uniqued reference to the type for 
 /// a pointer to the specified block.
 QualType ASTContext::getBlockPointerType(QualType T) {
-  assert(T->isFunctionType() && "closure of function types only");
-  // Unique pointers, to guarantee there is only one closure of a particular
+  assert(T->isFunctionType() && "block of function types only");
+  // Unique pointers, to guarantee there is only one block of a particular
   // structure.
   llvm::FoldingSetNodeID ID;
   BlockPointerType::Profile(ID, T);
@@ -624,7 +624,7 @@
         BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos))
     return QualType(PT, 0);
   
-  // If the closure pointee type isn't canonical, this won't be a canonical 
+  // If the block pointee type isn't canonical, this won't be a canonical 
   // type either so fill in the canonical type field.
   QualType Canonical;
   if (!T->isCanonical()) {

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Thu Aug 28 14:20:44 2008
@@ -21,6 +21,7 @@
 
 #include "clang/Parse/Parser.h"
 #include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
 #include "clang/Basic/Diagnostic.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/SmallString.h"
@@ -380,6 +381,7 @@
 /// [C++]   'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
 /// [C++]   'static_cast' '<' type-name '>' '(' expression ')'      [C++ 5.2p1]
 /// [C++]   'this'          [C++ 9.3.2]
+/// [clang] '^' block-literal
 ///
 ///       constant: [C99 6.4.4]
 ///         integer-constant
@@ -595,6 +597,11 @@
     if (getLang().ObjC1)
       return ParsePostfixExpressionSuffix(ParseObjCMessageExpression());
     // FALL THROUGH.
+  case tok::caret:
+    if (getLang().Blocks)
+      return ParsePostfixExpressionSuffix(ParseBlockLiteralExpression());
+    Diag(Tok, diag::err_expected_expression);
+    return ExprResult(true);
   default:
   UnhandledToken:
     Diag(Tok, diag::err_expected_expression);
@@ -1068,3 +1075,74 @@
     CommaLocs.push_back(ConsumeToken());
   }
 }
+
+/// ParseBlockLiteralExpression - Parse a block literal, which roughly looks
+/// like ^(int x){ return x+1; }  or   ^(int y)foo(4, y, z)
+///
+///         block-literal:
+/// [clang]   '^' block-args[opt] compound-statement
+/// [clang]   '^' block-args cast-expression
+/// [clang] block-args:
+/// [clang]   '(' parameter-list ')'
+///
+Parser::ExprResult Parser::ParseBlockLiteralExpression() {
+  assert(Tok.is(tok::caret) && "block literal starts with ^");
+  SourceLocation CaretLoc = ConsumeToken();
+  
+  // Enter a scope to hold everything within the block.  This includes the 
+  // argument decls, decls within the compound expression, etc.  This also
+  // allows determining whether a variable reference inside the block is
+  // within or outside of the block.
+  EnterScope(Scope::BlockScope|Scope::FnScope|Scope::BreakScope|
+             Scope::ContinueScope|Scope::DeclScope);
+  
+  // Parse the return type if present.
+  DeclSpec DS;
+  Declarator ParamInfo(DS, Declarator::PrototypeContext);
+  
+  // If this block has arguments, parse them.  There is no ambiguity here with
+  // the expression case, because the expression case requires a parameter list.
+  if (Tok.is(tok::l_paren)) {
+    ParseParenDeclarator(ParamInfo);
+    // 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.
+      ExitScope();
+      return true;
+    }
+  } else {
+    // Otherwise, pretend we saw (void).
+    ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
+                                                       0, 0, CaretLoc));
+  }
+
+  // Inform sema that we are starting a block.
+  Actions.ActOnBlockStart(CaretLoc, CurScope, ParamInfo);
+  
+  ExprResult Result;
+  if (Tok.is(tok::l_brace)) {
+    StmtResult Stmt = ParseCompoundStatementBody();
+    if (!Stmt.isInvalid) {
+      Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.Val, CurScope);
+    } else {
+      Actions.ActOnBlockError(CaretLoc, CurScope);
+      Result = true;
+    }
+  } else {
+    ExprResult Expr = ParseCastExpression(false);
+    if (!Expr.isInvalid) {
+      Result = Actions.ActOnBlockExprExpr(CaretLoc, Expr.Val, CurScope);
+    } else {
+      Actions.ActOnBlockError(CaretLoc, CurScope);
+      Diag(Tok, diag::err_expected_block_lbrace);
+      Result = true;
+    }
+  }
+
+  ExitScope();
+  return Result;
+}
+

Modified: cfe/trunk/test/Parser/block-pointer-decl.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/block-pointer-decl.c?rev=55495&r1=55494&r2=55495&view=diff

==============================================================================
--- cfe/trunk/test/Parser/block-pointer-decl.c (original)
+++ cfe/trunk/test/Parser/block-pointer-decl.c Thu Aug 28 14:20:44 2008
@@ -7,12 +7,20 @@
 
 int blockTaker (int (^myBlock)(int), int other_input)
 {
-  return 0;
+  return 5 * myBlock (other_input);
 }
 
 int main (int argc, char **argv)
 {
-  int (^blockptr) (int);
+  int (^blockptr) (int) = ^(int inval) {
+    printf ("Inputs: %d, %d.\n", argc, inval);
+    return argc * inval;
+  };
+
+
+  argc = 10;
+  printf ("I got: %d.\n",
+          blockTaker (blockptr, 6));
   return 0;
 }
 





More information about the cfe-commits mailing list