diff options
-rw-r--r-- | clang/include/clang/AST/Stmt.h | 10 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | clang/lib/Sema/JumpDiagnostics.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 2 | ||||
-rw-r--r-- | clang/test/SemaObjC/scope-check.m | 10 |
5 files changed, 36 insertions, 4 deletions
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 3c1e04f47aa..0d01d88e372 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -1410,10 +1410,12 @@ public: ObjCAtSynchronizedStmt(SourceLocation atSynchronizedLoc, Stmt *synchExpr, Stmt *synchBody) : Stmt(ObjCAtSynchronizedStmtClass) { - SubStmts[SYNC_EXPR] = synchExpr; - SubStmts[SYNC_BODY] = synchBody; - AtSynchronizedLoc = atSynchronizedLoc; - } + SubStmts[SYNC_EXPR] = synchExpr; + SubStmts[SYNC_BODY] = synchBody; + AtSynchronizedLoc = atSynchronizedLoc; + } + + SourceLocation getAtSynchronizedLoc() const { return AtSynchronizedLoc; } const CompoundStmt *getSynchBody() const { return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]); diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 28a97f87631..b270feccc88 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -868,6 +868,8 @@ def note_protected_by_objc_catch : Note< "jump bypasses initialization of @catch block">; def note_protected_by_objc_finally : Note< "jump bypasses initialization of @finally block">; +def note_protected_by_objc_synchronized : Note< + "jump bypasses initialization of @synchronized block">; def err_func_returning_array_function : Error< "function cannot return array or function type %0">; diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp index 82db0bbd2c3..b812f06f76b 100644 --- a/clang/lib/Sema/JumpDiagnostics.cpp +++ b/clang/lib/Sema/JumpDiagnostics.cpp @@ -168,6 +168,22 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { continue; } + // Disallow jumps into the protected statement of an @synchronized, but + // allow jumps into the object expression it protects. + if (ObjCAtSynchronizedStmt *AS = dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)){ + // Recursively walk the AST for the @synchronized object expr, it is + // evaluated in the normal scope. + BuildScopeInformation(AS->getSynchExpr(), ParentScope); + + // Recursively walk the AST for the @synchronized part, protected by a new + // scope. + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_objc_synchronized, + AS->getAtSynchronizedLoc())); + BuildScopeInformation(AS->getSynchBody(), Scopes.size()-1); + continue; + } + // Recursively walk the AST. BuildScopeInformation(SubStmt, ParentScope); } diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 35dffa10f2a..26cba5bec74 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -1090,6 +1090,8 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) { Action::OwningStmtResult Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr, StmtArg SynchBody) { + CurFunctionNeedsScopeChecking = true; + return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc, static_cast<Stmt*>(SynchExpr.release()), static_cast<Stmt*>(SynchBody.release()))); diff --git a/clang/test/SemaObjC/scope-check.m b/clang/test/SemaObjC/scope-check.m index 7da4e429a68..0835373ba74 100644 --- a/clang/test/SemaObjC/scope-check.m +++ b/clang/test/SemaObjC/scope-check.m @@ -44,6 +44,16 @@ L3: ; } @catch (C *c) { // expected-note {{jump bypasses initialization of @catch block}} L8: ; } + + // rdar://6810106 + id X; + goto L9; // expected-error{{illegal goto into protected scope}} + goto L10; // ok + @synchronized // expected-note {{jump bypasses initialization of @synchronized block}} + ( ({ L10: ; X; })) { + L9: + ; + } } void test2(int a) { |