From 07e775d5a1d5262a9cfe1ff333af713535b8cbab Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 18 Apr 2009 21:28:52 +0000 Subject: [PATCH] reject invalid jumps among pieces of @try blocks. This seems to work 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 | 7 ++-- include/clang/Basic/DiagnosticSemaKinds.td | 4 +++ lib/Sema/SemaDecl.cpp | 27 ++++++++++++++-- test/SemaObjC/scope-check.m | 37 ++++++++++++++++++++-- 4 files changed, 67 insertions(+), 8 deletions(-) diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index d76bc0b3c9..f665cfd582 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -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; } diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index f0a7e848db..8330a02b2a 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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">; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 9424fc685c..903ddf2600 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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(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(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? diff --git a/test/SemaObjC/scope-check.m b/test/SemaObjC/scope-check.m index 7a28ebbed3..0833a1696d 100644 --- a/test/SemaObjC/scope-check.m +++ b/test/SemaObjC/scope-check.m @@ -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 3 {{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) { -- 2.40.0