[cfe-commits] r56064 - in /cfe/trunk: include/clang/Parse/Scope.h lib/Sema/SemaChecking.cpp lib/Sema/SemaExpr.cpp test/Sema/block-literal.c

Steve Naroff snaroff at apple.com
Wed Sep 10 12:17:50 PDT 2008


Author: snaroff
Date: Wed Sep 10 14:17:48 2008
New Revision: 56064

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

Added:
    cfe/trunk/test/Sema/block-literal.c
Modified:
    cfe/trunk/include/clang/Parse/Scope.h
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp

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

==============================================================================
--- cfe/trunk/include/clang/Parse/Scope.h (original)
+++ cfe/trunk/include/clang/Parse/Scope.h Wed Sep 10 14:17:48 2008
@@ -77,6 +77,10 @@
   /// preceeding BreakParent/ContinueParent if this scope is not one, or null if
   /// there is no containing break/continue scope.
   Scope *BreakParent, *ContinueParent;
+
+  /// BlockParent - This is a direct link to the immediately containing
+  /// BlockScope if this scope is not one, or null if there is none.
+  Scope *BlockParent;
   
   /// DeclsInScope - This keeps track of all declarations in this scope.  When
   /// the declaration is added to the scope, it is set as the current
@@ -96,6 +100,10 @@
   ///
   unsigned getFlags() const { return Flags; }
 
+  /// isBlockScope - Return true if this scope does not correspond to a
+  /// closure.
+  bool isBlockScope() const { return Flags & BlockScope; }
+
   /// getParent - Return the scope that this is nested in.
   ///
   const Scope *getParent() const { return AnyParent; }
@@ -107,15 +115,32 @@
   Scope *getFnParent() { return FnParent; }
   
   /// getContinueParent - Return the closest scope that a continue statement
-  /// would be affected by.
-  const Scope *getContinueParent() const { return ContinueParent; }
-  Scope *getContinueParent() { return ContinueParent; }
+  /// would be affected by.  If the closest scope is a closure scope, we know 
+  /// that there is no loop *inside* the closure.
+  Scope *getContinueParent() {
+    if (ContinueParent && !ContinueParent->isBlockScope())
+      return ContinueParent;
+    return 0;
+  }
+
+  const Scope *getContinueParent() const {
+    return const_cast<Scope*>(this)->getContinueParent();
+  }
   
   /// getBreakParent - Return the closest scope that a break statement
-  /// would be affected by.
-  const Scope *getBreakParent() const { return BreakParent; }
-  Scope *getBreakParent() { return BreakParent; }
-  
+  /// would be affected by.  If the closest scope is a block scope, we know 
+  /// that there is no loop *inside* the block.
+  Scope *getBreakParent() {
+    if (BreakParent && !BreakParent->isBlockScope())
+      return BreakParent;
+    return 0;
+  }
+  const Scope *getBreakParent() const {
+    return const_cast<Scope*>(this)->getBreakParent();
+  }
+ 
+  Scope *getBlockParent() { return BlockParent; }
+  const Scope *getBlockParent() const { return BlockParent; }  
  
   typedef DeclSetTy::iterator decl_iterator;
   decl_iterator decl_begin() const { return DeclsInScope.begin(); }
@@ -158,14 +183,16 @@
       FnParent       = AnyParent->FnParent;
       BreakParent    = AnyParent->BreakParent;
       ContinueParent = AnyParent->ContinueParent;
+      BlockParent  = AnyParent->BlockParent;
     } else {
-      FnParent = BreakParent = ContinueParent = 0;
+      FnParent = BreakParent = ContinueParent = BlockParent = 0;
     }
     
     // If this scope is a function or contains breaks/continues, remember it.
     if (Flags & FnScope)       FnParent = this;
     if (Flags & BreakScope)    BreakParent = this;
     if (Flags & ContinueScope) ContinueParent = this;
+    if (Flags & BlockScope)  BlockParent = this;
     
     DeclsInScope.clear();
   }      

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Sep 10 14:17:48 2008
@@ -717,7 +717,7 @@
            DR->getDecl()->getIdentifier()->getName(),
            RetValExp->getSourceRange());
            
-    if (BlockExpr *C = dyn_cast_or_null<BlockExpr>(EvalAddr(RetValExp)))
+    if (BlockExpr *C = dyn_cast_or_null<BlockExpr>(RetValExp))
       Diag(C->getLocStart(), diag::err_ret_local_block,
            C->getSourceRange());
   }
@@ -797,7 +797,7 @@
     assert (Base->getType()->isPointerType());
     return EvalAddr(Base);
   }
-    
+
   // For conditional operators we need to see if either the LHS or RHS are
   // valid DeclRefExpr*s.  If one of them is valid, we return it.
   case Stmt::ConditionalOperatorClass: {

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Sep 10 14:17:48 2008
@@ -1296,11 +1296,13 @@
   }
   // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has
   // the type of the other operand."
-  if (lexT->isPointerType() && rex->isNullPointerConstant(Context)) {
+  if ((lexT->isPointerType() || lexT->isBlockPointerType()) &&
+      rex->isNullPointerConstant(Context)) {
     ImpCastExprToType(rex, lexT); // promote the null to a pointer.
     return lexT;
   }
-  if (rexT->isPointerType() && lex->isNullPointerConstant(Context)) {
+  if ((rexT->isPointerType() || rexT->isBlockPointerType()) &&
+      lex->isNullPointerConstant(Context)) {
     ImpCastExprToType(lex, rexT); // promote the null to a pointer.
     return rexT;
   }
@@ -1381,6 +1383,11 @@
       return compositeType;
     }
   }
+  // Selection between block pointer types is ok as long as they are the same.
+  if (lexT->isBlockPointerType() && rexT->isBlockPointerType() &&
+      Context.getCanonicalType(lexT) == Context.getCanonicalType(rexT))
+    return lexT;
+
   // Otherwise, the operands are not compatible.
   Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands,
        lexT.getAsString(), rexT.getAsString(),

Added: cfe/trunk/test/Sema/block-literal.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/block-literal.c?rev=56064&view=auto

==============================================================================
--- cfe/trunk/test/Sema/block-literal.c (added)
+++ cfe/trunk/test/Sema/block-literal.c Wed Sep 10 14:17:48 2008
@@ -0,0 +1,116 @@
+// RUN: clang -fsyntax-only %s -verify
+
+void I( void (^)(void));
+void (^noop)(void);
+
+void nothing();
+int printf(const char*, ...);
+
+typedef void (^T) (void);
+
+void takeclosure(T);
+int takeintint(int (^C)(int)) { return C(4); }
+
+T somefunction() {
+	if (^{ })
+	  nothing();
+
+	noop = ^{};
+
+	noop = ^{printf("\nClosure\n"); };
+
+	I(^{ });
+
+  noop = ^noop; // expected-error {{incompatible block pointer types}}
+
+	return ^{printf("\nClosure\n"); };  // expected-error {{returning block that lives on the local stack}}
+}
+void test2() {
+	int x = 4;
+
+	takeclosure(^{ printf("%d\n", x); });
+
+  while (1) {
+	  takeclosure(^{ 
+      break;  // expected-error {{'break' statement not in loop or switch statement}}
+	    continue; // expected-error {{'continue' statement not in loop statement}}
+	    while(1) break;  // ok
+      goto foo; // expected-error {{goto not allowed}}
+    });
+    break;
+	}
+
+foo:
+	takeclosure(^{ x = 4; });  // expected-error {{expression is not assignable}}
+  
+  takeclosure(^test2());
+  takeclosure(^(void)(void)printf("hello world!\n"));
+
+}
+
+
+void (^test3())(void) { 
+  return ^{};   // expected-error {{returning block that lives on the local stack}}
+}
+
+void test4() {
+  void (^noop)(void) = ^{};
+  void (*noop2)() = 0;
+}
+
+void *X;
+
+void test_arguments() {
+  takeintint(^(int x)(x+1));
+
+  // Closure expr of statement expr.
+  takeintint(^(int x)({ return 42; }));  // expected-error {{return not allowed in block expression literal}}
+  
+  int y;
+  takeintint(^(int x)(x+y));
+#if 0
+  // FIXME: this causes clang to crash.
+  X = ^(x+r); // expected-error {{expected ')' in argument list}}
+#endif
+  int (^c)(char);
+  (1 ? c : 0)('x');
+  (1 ? 0 : c)('x');
+
+  (1 ? c : c)('x');
+}
+
+#if 0
+// Old syntax. FIXME: convert/test.
+void test_byref() {
+  int i;
+  
+  X = ^{| g |};  // expected-error {{use of undeclared identifier 'g'}}
+
+  X = ^{| i,i,i | };
+
+  X = ^{|i| i = 0; };
+
+}
+
+// TODO: global closures someday.
+void *A = ^{};
+void *B = ^(int){ A = 0; };
+
+
+// Closures can not take return types at this point.
+void test_retvals() {
+  // Explicit return value.
+  ^int{};   // expected-error {{closure with explicit return type requires argument list}}
+  X = ^void(){};
+
+  // Optional specification of return type.
+  X = ^char{ return 'x'; };  // expected-error {{closure with explicit return type requires argument list}}
+
+  X = ^/*missing declspec*/ *() { return (void*)0; };
+  X = ^void*() { return (void*)0; };
+  
+  //X = ^char(short c){ if (c) return c; else return (int)4; };
+  
+}
+
+#endif





More information about the cfe-commits mailing list