]> granicus.if.org Git - clang/commitdiff
reject invalid jumps among pieces of @try blocks. This seems to work
authorChris Lattner <sabre@nondot.org>
Sat, 18 Apr 2009 21:28:52 +0000 (21:28 +0000)
committerChris Lattner <sabre@nondot.org>
Sat, 18 Apr 2009 21:28:52 +0000 (21:28 +0000)
reasonably well except for the problem that @catches are nested within
each other in the AST, giving the ugly diagnostics in L8.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69477 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Stmt.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDecl.cpp
test/SemaObjC/scope-check.m

index d76bc0b3c9166dd2a298025fe237613e5d06f47f..f665cfd58265aac00550ec924c7afca0d1c1f944 100644 (file)
@@ -1290,6 +1290,7 @@ public:
     return ExceptionDecl; 
   }
   
+  SourceLocation getAtCatchLoc() const { return AtCatchLoc; }
   SourceLocation getRParenLoc() const { return RParenLoc; }
   
   virtual SourceRange getSourceRange() const { 
@@ -1319,13 +1320,15 @@ public:
   : Stmt(ObjCAtFinallyStmtClass), 
     AtFinallyStmt(atFinallyStmt), AtFinallyLoc(atFinallyLoc) {}
   
-  const Stmt *getFinallyBody () const { return AtFinallyStmt; }
-  Stmt *getFinallyBody () { return AtFinallyStmt; }
+  const Stmt *getFinallyBody() const { return AtFinallyStmt; }
+  Stmt *getFinallyBody() { return AtFinallyStmt; }
 
   virtual SourceRange getSourceRange() const { 
     return SourceRange(AtFinallyLoc, AtFinallyStmt->getLocEnd()); 
   }
   
+  SourceLocation getAtFinallyLoc() const { return AtFinallyLoc; }
+  
   static bool classof(const Stmt *T) {
     return T->getStmtClass() == ObjCAtFinallyStmtClass;
   }
index f0a7e848dbbc2d67287fc7c9c955785a96e85916..8330a02b2a6cc0cb140dff22b78351fd57454ad8 100644 (file)
@@ -842,6 +842,10 @@ def note_protected_by_cleanup : Note<
   "jump bypasses initialization of declaration with __attribute__((cleanup))">;
 def note_protected_by_objc_try : Note<
   "jump bypasses initialization of @try block">;
+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 err_func_returning_array_function : Error<
   "function cannot return array or function type %0">;
index 9424fc685c84899c121b8abb3c8a6b8ceafa3ca3..903ddf26001bb6c2763f796fc1ffbd8f7bc1d4fb 100644 (file)
@@ -3022,6 +3022,13 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
     // it.  This makes the second scan not have to walk the AST again.
     LabelAndGotoScopes[S] = ParentScope;
     Jumps.push_back(S);
+  } else if (ObjCAtCatchStmt *AC = dyn_cast<ObjCAtCatchStmt>(S)) {
+    // @catch always starts a new scope.
+    // FIXME: We have to do this because @catches are nested inside each other,
+    // which seems weird and causes us to emit wierd diagnostics.
+    Scopes.push_back(GotoScope(ParentScope,diag::note_protected_by_objc_catch,
+                               AC->getAtCatchLoc()));
+    ParentScope = Scopes.size()-1;
   }
 
   for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E;
@@ -3050,10 +3057,24 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
     // Disallow jumps into any part of an @try statement by pushing a scope and
     // walking all sub-stmts in that scope.
     if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) {
-      Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_objc_try,
+      // Recursively walk the AST for the @try part.
+      Scopes.push_back(GotoScope(ParentScope,diag::note_protected_by_objc_try,
                                  AT->getAtTryLoc()));
-      // Recursively walk the AST.
-      BuildScopeInformation(SubStmt, Scopes.size()-1);
+      if (Stmt *TryPart = AT->getTryBody())
+        BuildScopeInformation(TryPart, Scopes.size()-1);
+
+      // Jump from the catch or finally to the try is not valid.
+      if (ObjCAtCatchStmt *AC = AT->getCatchStmts())
+        // @catches are nested and it isn't 
+        BuildScopeInformation(AC, ParentScope);
+      
+      if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) {
+        Scopes.push_back(GotoScope(ParentScope,
+                                   diag::note_protected_by_objc_finally,
+                                   AF->getAtFinallyLoc()));
+        BuildScopeInformation(AF, Scopes.size()-1);
+      }
+      
       continue;
     }
     // FIXME: what about jumps into C++ catch blocks, what are the rules?
index 7a28ebbed3e7d9a65bc30b3c1eb93a78dba665ed..0833a1696d13de34e499fa6271398dda883962bb 100644 (file)
@@ -6,15 +6,46 @@ void test1() {
   goto L; // expected-error{{illegal goto into protected scope}}
   goto L2; // expected-error{{illegal goto into protected scope}}
   goto L3; // expected-error{{illegal goto into protected scope}}
-  @try {   // expected-note {{jump bypasses initialization of @try block}}
+  @try {   // expected-note {{jump bypasses initialization of @try block}}
 L: ;
-  } @catch (A *x) {
+  } @catch (A *x) { // expected-note {{jump bypasses initialization of @catch block}}
 L2: ;
   } @catch (B *x) {
   } @catch (C *c) {
-  } @finally {
+  } @finally {// expected-note {{jump bypasses initialization of @finally block}}
 L3: ;
   }
+  
+  @try {
+    goto L4; // expected-error{{illegal goto into protected scope}}
+    goto L5; // expected-error{{illegal goto into protected scope}}
+  } @catch (C *c) { // expected-note {{jump bypasses initialization of @catch block}}
+  L5: ;
+    goto L6; // expected-error{{illegal goto into protected scope}}
+  } @catch (B *c) { // expected-note {{jump bypasses initialization of @catch block}}
+  L6: ;
+  } @finally { // expected-note {{jump bypasses initialization of @finally block}}
+  L4: ;
+  }
+  
+  @try { // expected-note 2 {{jump bypasses initialization of @try block}}
+  L7: ;
+  } @catch (C *c) {
+    goto L7; // expected-error{{illegal goto into protected scope}}
+  } @finally {
+    goto L7; // expected-error{{illegal goto into protected scope}}
+  }
+  
+  goto L8;  // expected-error{{illegal goto into protected scope}}
+  @try { 
+  } @catch (A *c) { // expected-note {{jump bypasses initialization of @catch block}}
+  } @catch (B *c) { // expected-note {{jump bypasses initialization of @catch block}}
+  } @catch (C *c) { // expected-note {{jump bypasses initialization of @catch block}}
+  L8: ;
+  }
+  
+  
 }
 
 void test2(int a) {