[cfe-commits] r55710 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/AST/StmtNodes.def include/clang/Basic/DiagnosticKinds.def lib/AST/Expr.cpp lib/AST/StmtPrinter.cpp lib/AST/StmtSerialization.cpp lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaStmt.cpp

Steve Naroff snaroff at apple.com
Wed Sep 3 11:15:37 PDT 2008


Author: snaroff
Date: Wed Sep  3 13:15:37 2008
New Revision: 55710

URL: http://llvm.org/viewvc/llvm-project?rev=55710&view=rev
Log:
Add semantic analysis for "blocks". 

Highlights...

- 4 new AST nodes, BlockExpr, BlockStmtExpr, BlockExprExpr, BlockDeclRefExpr.
- Sema::ActOnBlockStart(), ActOnBlockError(), ActOnBlockStmtExpr(), ActOnBlockExprExpr(), ActOnBlockReturnStmt().

Next steps...

- hack Sema::ActOnIdentifierExpr() to deal with block decl refs.
- add attribute handler for byref decls.
- add test cases.


Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/include/clang/AST/StmtNodes.def
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/AST/StmtSerialization.cpp
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=55710&r1=55709&r2=55710&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Wed Sep  3 13:15:37 2008
@@ -1475,6 +1475,124 @@
   InitListExpr() : Expr(InitListExprClass, QualType()) {}
 };
 
+//===----------------------------------------------------------------------===//
+// Clang Extensions
+//===----------------------------------------------------------------------===//
+
+/// BlockExpr - Common base class between BlockStmtExpr and BlockExprExpr.
+class BlockExpr : public Expr {
+  SourceLocation CaretLocation;
+  llvm::SmallVector<ParmVarDecl*, 8> Args;
+protected:
+  BlockExpr(StmtClass SC, QualType ty, SourceLocation caretloc,
+              ParmVarDecl **args, unsigned numargs)
+    : Expr(SC, ty), CaretLocation(caretloc), Args(args, args+numargs) {}
+public:
+  SourceLocation getCaretLocation() const { return CaretLocation; }
+
+  /// getFunctionType - Return the underlying function type for this block.
+  const FunctionType *getFunctionType() const;
+  
+  /// arg_iterator - Iterate over the ParmVarDecl's for the arguments to this
+  /// block.
+  typedef llvm::SmallVector<ParmVarDecl*, 8>::const_iterator arg_iterator;
+  bool arg_empty() const { return Args.empty(); }
+  arg_iterator arg_begin() const { return Args.begin(); }
+  arg_iterator arg_end() const { return Args.end(); }
+  
+  static bool classof(const Stmt *T) { 
+    return T->getStmtClass() == BlockStmtExprClass ||
+           T->getStmtClass() == BlockExprExprClass; 
+  }
+  static bool classof(const BlockExpr *) { return true; }
+};
+  
+/// BlockStmtExpr - Represent a block literal with a syntax:
+/// ^{ statement-body }   or   ^(int arg1, float arg2){ statement-body }
+class BlockStmtExpr : public BlockExpr {
+  CompoundStmt *Body;
+public:
+  BlockStmtExpr(SourceLocation CaretLoc, QualType Ty, ParmVarDecl **args, 
+                   unsigned numargs, CompoundStmt *body) : 
+    BlockExpr(BlockStmtExprClass, Ty, CaretLoc,
+                args, numargs), Body(body) {}
+    
+  const CompoundStmt *getBody() const { return Body; }
+  CompoundStmt *getBody() { return Body; }
+
+  virtual SourceRange getSourceRange() const {
+    return SourceRange(getCaretLocation(), Body->getLocEnd());
+  }
+  
+  static bool classof(const Stmt *T) { 
+    return T->getStmtClass() == BlockStmtExprClass; 
+  }
+  static bool classof(const BlockStmtExpr *) { return true; }
+
+  // Iterators
+  virtual child_iterator child_begin();
+  virtual child_iterator child_end();
+    
+  virtual void EmitImpl(llvm::Serializer& S) const;
+  static BlockStmtExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
+};
+  
+/// BlockExprExpr - Represents a block literal with syntax:
+///   ^(expression)   or ^(int arg1, float arg2)(expression)
+class BlockExprExpr : public BlockExpr {
+  Expr *BodyExpr;
+public:
+  BlockExprExpr(SourceLocation CaretLoc, QualType Ty, ParmVarDecl **args, 
+                   unsigned numargs, Expr *body) : 
+    BlockExpr(BlockExprExprClass, Ty, CaretLoc,
+                args, numargs), BodyExpr(body) {}
+  
+  const Expr *getExpr() const { return BodyExpr; }
+  Expr *getExpr() { return BodyExpr; }
+
+  virtual SourceRange getSourceRange() const {
+    return SourceRange(getCaretLocation(), BodyExpr->getLocEnd());
+  }
+  
+  // Iterators
+  virtual child_iterator child_begin();
+  virtual child_iterator child_end();
+  
+  static bool classof(const Stmt *T) { 
+    return T->getStmtClass() == BlockExprExprClass; 
+  }
+  static bool classof(const BlockExprExpr *) { return true; }
+};
+
+/// BlockDeclRefExpr - A reference to a declared variable, function,
+/// enum, etc.
+class BlockDeclRefExpr : public Expr {
+  ValueDecl *D; 
+  SourceLocation Loc;
+  bool IsByRef;
+public:
+  BlockDeclRefExpr(ValueDecl *d, QualType t, SourceLocation l, bool ByRef) : 
+       Expr(BlockDeclRefExprClass, t), D(d), Loc(l), IsByRef(ByRef) {}
+  
+  ValueDecl *getDecl() { return D; }
+  const ValueDecl *getDecl() const { return D; }
+  virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
+  
+  bool isByRef() const { return IsByRef; }
+  
+  static bool classof(const Stmt *T) { 
+    return T->getStmtClass() == BlockDeclRefExprClass; 
+  }
+  static bool classof(const BlockDeclRefExpr *) { return true; }
+  
+  // Iterators
+  virtual child_iterator child_begin();
+  virtual child_iterator child_end();
+  
+  virtual void EmitImpl(llvm::Serializer& S) const;
+  static BlockDeclRefExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
+};
+
 }  // end namespace clang
 
 #endif

Modified: cfe/trunk/include/clang/AST/StmtNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtNodes.def?rev=55710&r1=55709&r2=55710&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/StmtNodes.def (original)
+++ cfe/trunk/include/clang/AST/StmtNodes.def Wed Sep  3 13:15:37 2008
@@ -108,8 +108,12 @@
 // Clang Extensions.
 STMT(77, OverloadExpr         , Expr)
 STMT(78, ShuffleVectorExpr    , Expr)
+STMT(79, BlockExpr            , Expr)
+STMT(80, BlockStmtExpr        , BlockExpr)
+STMT(81, BlockExprExpr        , BlockExpr)
+STMT(82, BlockDeclRefExpr     , Expr)
 
-LAST_EXPR(78)
+LAST_EXPR(82)
 
 #undef STMT
 #undef FIRST_STMT

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

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Sep  3 13:15:37 2008
@@ -868,6 +868,12 @@
      "qualifier specification on block pointer type not allowed")
 DIAG(err_nonfunction_block_type, ERROR,
      "block pointer to non-function type is invalid")
+DIAG(err_return_block_has_expr, ERROR,
+     "void block should not return a value")
+DIAG(err_block_return_missing_expr, ERROR,
+     "non-void block should return a value")
+DIAG(err_block_with_return_type_requires_args, ERROR,
+     "block with explicit return type requires argument list")
 
 // Expressions.
 DIAG(ext_sizeof_function_type, EXTENSION,
@@ -1124,6 +1130,10 @@
 // Blocks
 DIAG(err_expected_block_lbrace, ERROR,
      "expected '{' in block literal")
+DIAG(err_goto_in_block, ERROR,
+     "goto not allowed in closure literal")
+DIAG(err_return_in_block_expression, ERROR,
+     "return not allowed in block expression literal")
 
 // CFString checking
 DIAG(err_cfstring_literal_not_string_constant, ERROR,

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

==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Wed Sep  3 13:15:37 2008
@@ -282,6 +282,13 @@
     InitExprs.push_back(initexprs[i]);
 }
 
+/// getFunctionType - Return the underlying function type for this closure.
+///
+const FunctionType *BlockExpr::getFunctionType() const {
+  return getType()->getAsBlockPointerType()->
+                    getPointeeType()->getAsFunctionType();
+}
+
 //===----------------------------------------------------------------------===//
 // Generic Expression Routines
 //===----------------------------------------------------------------------===//
@@ -1432,3 +1439,18 @@
   return &SubExprs[0]+ARGS_START+getNumArgs();
 }
 
+// Blocks
+Stmt::child_iterator BlockStmtExpr::child_begin() {
+  return reinterpret_cast<Stmt**>(&Body);
+}
+Stmt::child_iterator BlockStmtExpr::child_end() {
+  return reinterpret_cast<Stmt**>(&Body)+1;
+}
+
+Stmt::child_iterator BlockExprExpr::child_begin() {
+  return reinterpret_cast<Stmt**>(&BodyExpr);
+}
+Stmt::child_iterator BlockExprExpr::child_end() {
+  return reinterpret_cast<Stmt**>(&BodyExpr)+1;
+}
+

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

==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Wed Sep  3 13:15:37 2008
@@ -874,6 +874,46 @@
   OS << "]";
 }
 
+void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
+  OS << "^";
+  
+  const FunctionType *AFT = Node->getFunctionType();
+  
+  if (isa<FunctionTypeNoProto>(AFT)) {
+    OS << "()";
+  } else if (!Node->arg_empty() || cast<FunctionTypeProto>(AFT)->isVariadic()) {
+    const FunctionTypeProto *FT = cast<FunctionTypeProto>(AFT);
+    OS << '(';
+    std::string ParamStr;
+    for (BlockStmtExpr::arg_iterator AI = Node->arg_begin(),
+         E = Node->arg_end(); AI != E; ++AI) {
+      if (AI != Node->arg_begin()) OS << ", ";
+      ParamStr = (*AI)->getName();
+      (*AI)->getType().getAsStringInternal(ParamStr);
+      OS << ParamStr;
+    }
+    
+    if (FT->isVariadic()) {
+      if (!Node->arg_empty()) OS << ", ";
+      OS << "...";
+    }
+    OS << ')';
+  }
+}
+
+void StmtPrinter::VisitBlockStmtExpr(BlockStmtExpr *Node) {
+  VisitBlockExpr(Node);
+  PrintRawCompoundStmt(Node->getBody());
+}
+
+void StmtPrinter::VisitBlockExprExpr(BlockExprExpr *Node) {
+  VisitBlockExpr(Node);
+  PrintExpr(Node->getExpr());
+}
+
+void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) {
+  OS << Node->getDecl()->getName();
+}
 //===----------------------------------------------------------------------===//
 // Stmt method implementations
 //===----------------------------------------------------------------------===//

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

==============================================================================
--- cfe/trunk/lib/AST/StmtSerialization.cpp (original)
+++ cfe/trunk/lib/AST/StmtSerialization.cpp Wed Sep  3 13:15:37 2008
@@ -1109,6 +1109,38 @@
 }
 
 //===----------------------------------------------------------------------===//
+//   Serialization for Clang Extensions.
+//===----------------------------------------------------------------------===//
+
+void BlockStmtExpr::EmitImpl(Serializer& S) const {
+  S.Emit(getType());
+  S.Emit(getCaretLocation());
+  S.EmitOwnedPtr(Body);
+}
+
+BlockStmtExpr* BlockStmtExpr::CreateImpl(Deserializer& D, ASTContext& C) {
+  QualType Q = QualType::ReadVal(D);
+  SourceLocation L = SourceLocation::ReadVal(D);
+  /*CompoundStmt* BodyStmt = cast<CompoundStmt>(*/D.ReadOwnedPtr<Stmt>(C)/*)*/;
+  assert(0 && "Cannot deserialize BlockBlockExpr yet");
+  // FIXME: need to handle parameters.
+  //return new BlockBlockExpr(L, Q, BodyStmt);
+  return 0;
+}
+
+void BlockDeclRefExpr::EmitImpl(Serializer& S) const {
+  S.Emit(Loc);
+  S.Emit(getType());
+  S.EmitBool(false);
+  S.EmitPtr(getDecl());
+}
+
+BlockDeclRefExpr* BlockDeclRefExpr::CreateImpl(Deserializer& D, ASTContext& C) {
+  assert(0 && "Cannot deserialize BlockDeclRefExpr yet");
+  return 0;
+}
+
+//===----------------------------------------------------------------------===//
 //   C++ Serialization
 //===----------------------------------------------------------------------===//
 void CXXDefaultArgExpr::EmitImpl(Serializer& S) const {

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Wed Sep  3 13:15:37 2008
@@ -87,7 +87,7 @@
 }
 
 Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer)
-  : PP(pp), Context(ctxt), Consumer(consumer), CurContext(0) {
+  : PP(pp), Context(ctxt), Consumer(consumer), CurContext(0), CurBlock(0) {
   
   // Get IdentifierInfo objects for known functions for which we
   // do extra checking.  

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Sep  3 13:15:37 2008
@@ -64,6 +64,7 @@
   class ObjCIvarDecl;
   class ObjCMethodDecl;
   class ObjCPropertyDecl;
+  struct BlockSemaInfo;
 
 /// Sema - This implements semantic analysis and AST building for C.
 class Sema : public Action {
@@ -75,6 +76,10 @@
   /// CurContext - This is the current declaration context of parsing.
   DeclContext *CurContext;
 
+  /// CurBlock - If inside of a block definition, this contains a pointer to
+  /// the active block object that represents it.
+  BlockSemaInfo *CurBlock;
+
   /// LabelMap - This is a mapping from label identifiers to the LabelStmt for
   /// it (which acts like the label decl in some ways).  Forward referenced
   /// labels have a LabelStmt created for them with a null location & SubStmt.
@@ -408,6 +413,7 @@
   
   virtual StmtResult ActOnReturnStmt(SourceLocation ReturnLoc,
                                      ExprTy *RetValExp);
+  StmtResult ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp);
   
   virtual StmtResult ActOnAsmStmt(SourceLocation AsmLoc,
                                   bool IsSimple,
@@ -536,6 +542,27 @@
   virtual ExprResult ActOnVAArg(SourceLocation BuiltinLoc,
                                 ExprTy *expr, TypeTy *type,
                                 SourceLocation RPLoc);
+
+  //===------------------------- "Block" Extension ------------------------===//
+
+  /// ActOnBlockStart - This callback is invoked when a block literal is
+  /// started.
+  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);
+
+  /// 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);
   
   // Act on C++ namespaces
   virtual DeclTy *ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc,
@@ -960,6 +987,27 @@
   bool HadError() { return hadError; }
 };
 
+/// BlockSemaInfo - When a block is being parsed, this contains information
+/// about the block.  It is pointed to from Sema::CurBlock.
+struct BlockSemaInfo {
+  llvm::SmallVector<ParmVarDecl*, 8> Params;
+  llvm::SmallPtrSet<Decl*, 4> ByRefVars;
+  bool hasPrototype;
+  bool isVariadic;
+  
+  /// TheScope - This is the scope for the block itself, which contains
+  /// arguments etc.
+  Scope *TheScope;
+  
+  /// ReturnType - This will get set to block result type, by looking at
+  /// return types, if any, in the block body.
+  Type *ReturnType;
+  
+  /// PrevBlockInfo - If this is nested inside another block, this points
+  /// to the outer block.
+  BlockSemaInfo *PrevBlockInfo;
+};
+
 
 }  // end namespace clang
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Sep  3 13:15:37 2008
@@ -21,6 +21,8 @@
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
 using namespace clang;
 
 //===----------------------------------------------------------------------===//
@@ -2607,6 +2609,124 @@
   return new ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, resType, RPLoc);
 }
 
+//===----------------------------------------------------------------------===//
+// Clang Extensions.
+//===----------------------------------------------------------------------===//
+
+/// ActOnBlockStart - This callback is invoked when a block literal is started.
+void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope,
+                           Declarator &ParamInfo) {
+  // Analyze block parameters.
+  BlockSemaInfo *BSI = new BlockSemaInfo();
+  
+  // Add BSI to CurBlock.
+  BSI->PrevBlockInfo = CurBlock;
+  CurBlock = BSI;
+  
+  BSI->ReturnType = 0;
+  BSI->TheScope = BlockScope;
+  
+  // Analyze arguments to block.
+  assert(ParamInfo.getTypeObject(0).Kind == DeclaratorChunk::Function &&
+         "Not a function declarator!");
+  DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getTypeObject(0).Fun;
+  
+  BSI->hasPrototype = FTI.hasPrototype;
+  BSI->isVariadic = true;
+  
+  // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs function that takes
+  // no arguments, not a function that takes a single void argument.
+  if (FTI.hasPrototype &&
+      FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
+      (!((ParmVarDecl *)FTI.ArgInfo[0].Param)->getType().getCVRQualifiers() &&
+        ((ParmVarDecl *)FTI.ArgInfo[0].Param)->getType()->isVoidType())) {
+    // empty arg list, don't push any params.
+    BSI->isVariadic = false;
+  } else if (FTI.hasPrototype) {
+    for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
+      BSI->Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param);
+    BSI->isVariadic = FTI.isVariadic;
+  }
+}
+
+/// ActOnBlockError - If there is an error parsing a block, this callback
+/// is invoked to pop the information about the block from the action impl.
+void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {
+  // Ensure that CurBlock is deleted.
+  llvm::OwningPtr<BlockSemaInfo> CC(CurBlock);
+  
+  // Pop off CurBlock, handle nested blocks.
+  CurBlock = CurBlock->PrevBlockInfo;
+  
+  // FIXME: Delete the ParmVarDecl objects as well???
+  
+}
+
+/// ActOnBlockStmtExpr - This is called when the body of a block statement
+/// literal was successfully completed.  ^(int x){...}
+Sema::ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, StmtTy *body,
+                                          Scope *CurScope) {
+  // Ensure that CurBlock is deleted.
+  llvm::OwningPtr<BlockSemaInfo> BSI(CurBlock);
+  llvm::OwningPtr<CompoundStmt> Body(static_cast<CompoundStmt*>(body));
+
+  // Pop off CurBlock, handle nested blocks.
+  CurBlock = CurBlock->PrevBlockInfo;
+  
+  QualType RetTy = Context.VoidTy;
+  if (BSI->ReturnType)
+    RetTy = QualType(BSI->ReturnType, 0);
+  
+  llvm::SmallVector<QualType, 8> ArgTypes;
+  for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i)
+    ArgTypes.push_back(BSI->Params[i]->getType());
+  
+  QualType BlockTy;
+  if (!BSI->hasPrototype)
+    BlockTy = Context.getFunctionTypeNoProto(RetTy);
+  else
+    BlockTy = Context.getFunctionType(RetTy, &ArgTypes[0], ArgTypes.size(),
+                                      BSI->isVariadic);
+  
+  BlockTy = Context.getBlockPointerType(BlockTy);
+  return new BlockStmtExpr(CaretLoc, BlockTy, 
+                           &BSI->Params[0], BSI->Params.size(), Body.take());
+}
+
+/// ActOnBlockExprExpr - This is called when the body of a block
+/// expression literal was successfully completed.  ^(int x)[foo bar: x]
+Sema::ExprResult Sema::ActOnBlockExprExpr(SourceLocation CaretLoc, ExprTy *body,
+                                      Scope *CurScope) {
+  // Ensure that CurBlock is deleted.
+  llvm::OwningPtr<BlockSemaInfo> BSI(CurBlock);
+  llvm::OwningPtr<Expr> Body(static_cast<Expr*>(body));
+
+  // Pop off CurBlock, handle nested blocks.
+  CurBlock = CurBlock->PrevBlockInfo;
+  
+  if (BSI->ReturnType) {
+    Diag(CaretLoc, diag::err_return_in_block_expression);
+    return true;
+  }
+  
+  QualType RetTy = Body->getType();
+  
+  llvm::SmallVector<QualType, 8> ArgTypes;
+  for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i)
+    ArgTypes.push_back(BSI->Params[i]->getType());
+  
+  QualType BlockTy;
+  if (!BSI->hasPrototype)
+    BlockTy = Context.getFunctionTypeNoProto(RetTy);
+  else
+    BlockTy = Context.getFunctionType(RetTy, &ArgTypes[0], ArgTypes.size(),
+                                      BSI->isVariadic);
+  
+  BlockTy = Context.getBlockPointerType(BlockTy);
+  return new BlockExprExpr(CaretLoc, BlockTy, 
+                           &BSI->Params[0], BSI->Params.size(), Body.take());
+}
+
 /// ExprsMatchFnType - return true if the Exprs in array Args have
 /// QualTypes that match the QualTypes of the arguments of the FnType.
 /// The number of arguments has already been validated to match the number of

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Wed Sep  3 13:15:37 2008
@@ -588,6 +588,10 @@
 Action::StmtResult 
 Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,
                     IdentifierInfo *LabelII) {
+  // If we are in a block, reject all gotos for now.
+  if (CurBlock)
+    return Diag(GotoLoc, diag::err_goto_in_block);
+
   // Look up the record for this label identifier.
   LabelStmt *&LabelDecl = LabelMap[LabelII];
 
@@ -630,10 +634,61 @@
   return new BreakStmt(BreakLoc);
 }
 
+/// ActOnBlockReturnStmt - Utilty routine to figure out block's return type.
+///
+Action::StmtResult
+Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
+ 
+  // If this is the first return we've seen in the block, infer the type of
+  // the block from it.
+  if (CurBlock->ReturnType == 0) {
+    if (RetValExp)
+      CurBlock->ReturnType = RetValExp->getType().getTypePtr();
+    else
+      CurBlock->ReturnType = Context.VoidTy.getTypePtr();
+    return new ReturnStmt(ReturnLoc, RetValExp);
+  }
+  
+  // 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
+  // compatibility to worry about here.
+  if (CurBlock->ReturnType->isVoidType()) {
+    if (RetValExp) {
+      Diag(ReturnLoc, diag::err_return_block_has_expr);
+      delete RetValExp;
+      RetValExp = 0;
+    }
+    return new ReturnStmt(ReturnLoc, RetValExp);
+  }
+  
+  if (!RetValExp) {
+    Diag(ReturnLoc, diag::err_block_return_missing_expr);
+    return true;
+  }
+  
+  // 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()) {
+    DiagnoseAssignmentResult(Incompatible, ReturnLoc, BlockQT,
+                             RetValType, RetValExp, "returning");
+    return true;
+  }
+  
+  if (RetValExp) CheckReturnStackAddr(RetValExp, BlockQT, ReturnLoc);
+  
+  return new ReturnStmt(ReturnLoc, (Expr*)RetValExp);
+}
 
 Action::StmtResult
 Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprTy *rex) {
   Expr *RetValExp = static_cast<Expr *>(rex);
+  if (CurBlock)
+    return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
   QualType FnRetType =
         getCurFunctionDecl() ? getCurFunctionDecl()->getResultType() : 
                                getCurMethodDecl()->getResultType();





More information about the cfe-commits mailing list