diff options
author | Steve Naroff <snaroff@apple.com> | 2008-12-05 17:03:39 +0000 |
---|---|---|
committer | Steve Naroff <snaroff@apple.com> | 2008-12-05 17:03:39 +0000 |
commit | 8c56515a0c61b73fc2f02cc96dc3e37650d89d45 (patch) | |
tree | 2fc4d46a778f1f87f7cfd56fa3e56b2f7321f317 | |
parent | 49184b2916f2f6535ac22f8517dc1e996225d2f1 (diff) |
Fixed <rdar://problem/6213808> clang ObjC rewriter: @finally is not always executed
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60593 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | Driver/RewriteObjC.cpp | 24 | ||||
-rw-r--r-- | test/Rewriter/finally.m | 26 |
2 files changed, 49 insertions, 1 deletions
diff --git a/Driver/RewriteObjC.cpp b/Driver/RewriteObjC.cpp index 6fc4a83fcf..d08633f728 100644 --- a/Driver/RewriteObjC.cpp +++ b/Driver/RewriteObjC.cpp @@ -41,7 +41,8 @@ namespace { Diagnostic &Diags; const LangOptions &LangOpts; unsigned RewriteFailedDiag; - + unsigned TryFinallyContainsReturnDiag; + ASTContext *Context; SourceManager *SM; TranslationUnitDecl *TUDecl; @@ -216,6 +217,7 @@ namespace { Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp); Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp); Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp); + void WarnAboutReturnGotoContinueOrBreakStmts(Stmt *S); Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S); Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S); Stmt *RewriteObjCCatchStmt(ObjCAtCatchStmt *S); @@ -368,6 +370,8 @@ RewriteObjC::RewriteObjC(std::string inFile, std::string outFile, OutFileName = outFile; RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning, "rewriting sub-expression within a macro (may not be correct)"); + TryFinallyContainsReturnDiag = Diags.getCustomDiagID(Diagnostic::Warning, + "rewriter doesn't support user-specified control flow semantics for @try/@finally (code may not execute properly)"); } ASTConsumer *clang::CreateCodeRewriterTest(const std::string& InFile, @@ -1420,6 +1424,21 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { return 0; } +void RewriteObjC::WarnAboutReturnGotoContinueOrBreakStmts(Stmt *S) { + // Perform a bottom up traversal of all children. + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) + WarnAboutReturnGotoContinueOrBreakStmts(*CI); + + if (isa<ReturnStmt>(S) || isa<ContinueStmt>(S) || + isa<BreakStmt>(S) || isa<GotoStmt>(S)) { + Diags.Report(Context->getFullLoc(S->getLocStart()), + TryFinallyContainsReturnDiag); + } + return; +} + Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { // Get the start location and compute the semi location. SourceLocation startLoc = S->getLocStart(); @@ -1570,6 +1589,9 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { // Set lastCurlyLoc lastCurlyLoc = body->getLocEnd(); + + // Now check for any return/continue/go statements within the @try. + WarnAboutReturnGotoContinueOrBreakStmts(S->getTryBody()); } else { /* no finally clause - make sure we synthesize an implicit one */ buf = "{ /* implicit finally clause */\n"; buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; diff --git a/test/Rewriter/finally.m b/test/Rewriter/finally.m new file mode 100644 index 0000000000..903cdec1f7 --- /dev/null +++ b/test/Rewriter/finally.m @@ -0,0 +1,26 @@ +// RUN: clang -rewrite-objc -verify %s -o - + +int main() { + @try { + printf("executing try"); + return(0); // expected-warning{{rewriter doesn't support user-specified control flow semantics for @try/@finally (code may not execute properly)}} + } @finally { + printf("executing finally"); + } + while (1) { + @try { + printf("executing try"); + break; // expected-warning{{rewriter doesn't support user-specified control flow semantics for @try/@finally (code may not execute properly)}} + } @finally { + printf("executing finally"); + } + printf("executing after finally block"); + } + @try { + printf("executing try"); + } @finally { + printf("executing finally"); + } + return 0; +} + |