[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