Correctly reject gotos in function-level try blocks. PR14225.

llvm-svn: 167184
This commit is contained in:
Eli Friedman 2012-10-31 23:55:28 +00:00
parent d9c2370b33
commit 1e95d4bb1e
2 changed files with 39 additions and 26 deletions

View File

@ -332,6 +332,29 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
Jumps.push_back(S);
break;
case Stmt::CXXTryStmtClass: {
CXXTryStmt *TS = cast<CXXTryStmt>(S);
unsigned newParentScope;
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_cxx_try,
diag::note_exits_cxx_try,
TS->getSourceRange().getBegin()));
if (Stmt *TryBlock = TS->getTryBlock())
BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1));
// Jump from the catch into the try is not allowed either.
for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) {
CXXCatchStmt *CS = TS->getHandler(I);
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_cxx_catch,
diag::note_exits_cxx_catch,
CS->getSourceRange().getBegin()));
BuildScopeInformation(CS->getHandlerBlock(),
(newParentScope = Scopes.size()-1));
}
return;
}
default:
break;
}
@ -428,30 +451,6 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
continue;
}
// Disallow jumps into any part of a C++ try statement. This is pretty
// much the same as for Obj-C.
if (CXXTryStmt *TS = dyn_cast<CXXTryStmt>(SubStmt)) {
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_cxx_try,
diag::note_exits_cxx_try,
TS->getSourceRange().getBegin()));
if (Stmt *TryBlock = TS->getTryBlock())
BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1));
// Jump from the catch into the try is not allowed either.
for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) {
CXXCatchStmt *CS = TS->getHandler(I);
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_cxx_catch,
diag::note_exits_cxx_catch,
CS->getSourceRange().getBegin()));
BuildScopeInformation(CS->getHandlerBlock(),
(newParentScope = Scopes.size()-1));
}
continue;
}
// Disallow jumps into the protected statement of an @autoreleasepool.
if (ObjCAutoreleasePoolStmt *AS = dyn_cast<ObjCAutoreleasePoolStmt>(SubStmt)){
// Recursively walk the AST for the @autoreleasepool part, protected by a new

View File

@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s -Wno-unreachable-code
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -std=gnu++11 %s -Wno-unreachable-code
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -fcxx-exceptions %s -Wno-unreachable-code
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -fcxx-exceptions -std=gnu++11 %s -Wno-unreachable-code
namespace test0 {
struct D { ~D(); };
@ -260,3 +260,17 @@ namespace test14 {
goto *ip;
}
}
// PR14225
namespace test15 {
void f1() try {
goto x; // expected-error {{goto into protected scope}}
} catch(...) { // expected-note {{jump bypasses initialization of catch block}}
x: ;
}
void f2() try { // expected-note {{jump bypasses initialization of try block}}
x: ;
} catch(...) {
goto x; // expected-error {{goto into protected scope}}
}
}