diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 12 | ||||
-rw-r--r-- | lib/Sema/JumpDiagnostics.cpp | 32 | ||||
-rw-r--r-- | test/SemaCXX/scope-check.cpp | 193 |
3 files changed, 232 insertions, 5 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 5669415c26..f9dd56f222 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4291,6 +4291,12 @@ def note_protected_by_cxx_try : Note< "jump bypasses initialization of try block">; def note_protected_by_cxx_catch : Note< "jump bypasses initialization of catch block">; +def note_protected_by_seh_try : Note< + "jump bypasses initialization of __try block">; +def note_protected_by_seh_except : Note< + "jump bypasses initialization of __except block">; +def note_protected_by_seh_finally : Note< + "jump bypasses initialization of __finally block">; def note_protected_by___block : Note< "jump bypasses setup of __block variable">; def note_protected_by_objc_ownership : Note< @@ -4323,6 +4329,12 @@ def note_exits_cxx_try : Note< "jump exits try block">; def note_exits_cxx_catch : Note< "jump exits catch block">; +def note_exits_seh_try : Note< + "jump exits __try block">; +def note_exits_seh_except : Note< + "jump exits __except block">; +def note_exits_seh_finally : Note< + "jump exits __finally block">; def note_exits_objc_autoreleasepool : Note< "jump exits autoreleasepool block">; def note_exits_objc_ownership : Note< diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index 9a9215174b..ac8733fe19 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -338,9 +338,35 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) return; } - case Stmt::SEHTryStmtClass: - // FIXME: Implement jump diagnostics for bad SEH jumps. - break; + case Stmt::SEHTryStmtClass: { + SEHTryStmt *TS = cast<SEHTryStmt>(S); + unsigned newParentScope; + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_seh_try, + diag::note_exits_seh_try, + TS->getSourceRange().getBegin())); + if (Stmt *TryBlock = TS->getTryBlock()) + BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1)); + + // Jump from __except or __finally into the __try are not allowed either. + if (SEHExceptStmt *Except = TS->getExceptHandler()) { + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_seh_except, + diag::note_exits_seh_except, + Except->getSourceRange().getBegin())); + BuildScopeInformation(Except->getBlock(), + (newParentScope = Scopes.size()-1)); + } else if (SEHFinallyStmt *Finally = TS->getFinallyHandler()) { + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_seh_finally, + diag::note_exits_seh_finally, + Finally->getSourceRange().getBegin())); + BuildScopeInformation(Finally->getBlock(), + (newParentScope = Scopes.size()-1)); + } + + return; + } default: break; diff --git a/test/SemaCXX/scope-check.cpp b/test/SemaCXX/scope-check.cpp index ac700999c2..c7638aea10 100644 --- a/test/SemaCXX/scope-check.cpp +++ b/test/SemaCXX/scope-check.cpp @@ -1,5 +1,5 @@ -// 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 +// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -fcxx-exceptions -fms-extensions %s -Wno-unreachable-code +// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -fcxx-exceptions -fms-extensions -std=gnu++11 %s -Wno-unreachable-code namespace testInvalid { Invalid inv; // expected-error {{unknown type name}} @@ -441,3 +441,192 @@ namespace test_recovery { } } } + +namespace seh { + +// Jumping into SEH try blocks is not permitted. + +void jump_into_except() { + goto into_try_except_try; // expected-error {{cannot jump from this goto statement to its label}} + __try { // expected-note {{jump bypasses initialization of __try block}} + into_try_except_try: + ; + } __except(0) { + } + + goto into_try_except_except; // expected-error {{cannot jump from this goto statement to its label}} + __try { + } __except(0) { // expected-note {{jump bypasses initialization of __except block}} + into_try_except_except: + ; + } +} + +void jump_into_finally() { + goto into_try_except_try; // expected-error {{cannot jump from this goto statement to its label}} + __try { // expected-note {{jump bypasses initialization of __try block}} + into_try_except_try: + ; + } __finally { + } + + goto into_try_except_finally; // expected-error {{cannot jump from this goto statement to its label}} + __try { + } __finally { // expected-note {{jump bypasses initialization of __finally block}} + into_try_except_finally: + ; + } +} + +// Jumping out of SEH try blocks ok in general. (Jumping out of a __finally +// has undefined behavior.) + +void jump_out_of_except() { + __try { + goto out_of_except_try; + } __except(0) { + } +out_of_except_try: + ; + + __try { + } __except(0) { + goto out_of_except_except; + } +out_of_except_except: + ; +} + +void jump_out_of_finally() { + __try { + goto out_of_finally_try; + } __finally { + } +out_of_finally_try: + ; + + __try { + } __finally { + // FIXME: This should warn that jumping out of __finally has undefined + // behavior. + // FIXME: Once that warns, check that + // __try { __try {} __finally { __leave; } } __except (0) {} + // warns in the same way. + goto out_of_finally_finally; + } +out_of_finally_finally: + ; +} + +// Jumping between protected scope and handler is not permitted. + +void jump_try_except() { + __try { + goto from_try_to_except; // expected-error {{cannot jump from this goto statement to its label}} + } __except(0) { // expected-note {{jump bypasses initialization of __except block}} + from_try_to_except: + ; + } + + __try { // expected-note {{jump bypasses initialization of __try block}} + from_except_to_try: + ; + } __except(0) { + goto from_except_to_try; // expected-error {{cannot jump from this goto statement to its label}} + } +} + +void jump_try_finally() { + __try { + goto from_try_to_finally; // expected-error {{cannot jump from this goto statement to its label}} + } __finally { // expected-note {{jump bypasses initialization of __finally block}} + from_try_to_finally: + ; + } + + __try { // expected-note {{jump bypasses initialization of __try block}} + from_finally_to_try: + ; + } __finally { + goto from_finally_to_try; // expected-error {{cannot jump from this goto statement to its label}} + } +} + +void nested() { + // These are not permitted. + __try { + __try { + } __finally { + goto outer_except; // expected-error {{cannot jump from this goto statement to its label}} + } + } __except(0) { // expected-note {{jump bypasses initialization of __except bloc}} + outer_except: + ; + } + + __try { + __try{ + } __except(0) { + goto outer_finally; // expected-error {{cannot jump from this goto statement to its label}} + } + } __finally { // expected-note {{jump bypasses initialization of __finally bloc}} + outer_finally: + ; + } + + // These are permitted. + __try { + __try { + } __finally { + // FIXME: This should warn that jumping out of __finally has undefined + // behavior. + goto after_outer_except; + } + } __except(0) { + } +after_outer_except: + ; + + __try { + __try{ + } __except(0) { + goto after_outer_finally; + } + } __finally { + } +after_outer_finally: + ; +} + +// This section is academic, as MSVC doesn't support indirect gotos. + +void indirect_jumps(void **ip) { + static void *ips[] = { &&l }; + + __try { // expected-note {{jump exits __try block}} + // FIXME: Should this be allowed? Jumping out of the guarded section of a + // __try/__except doesn't require unwinding. + goto *ip; // expected-error {{cannot jump from this indirect goto statement to one of its possible targets}} + } __except(0) { + } + + __try { + } __except(0) { // expected-note {{jump exits __except block}} + // FIXME: What about here? + goto *ip; // expected-error {{cannot jump from this indirect goto statement to one of its possible targets}} + } + + __try { // expected-note {{jump exits __try block}} + goto *ip; // expected-error {{cannot jump from this indirect goto statement to one of its possible targets}} + } __finally { + } + + __try { + } __finally { // expected-note {{jump exits __finally block}} + goto *ip; // expected-error {{cannot jump from this indirect goto statement to one of its possible targets}} + } +l: // expected-note 4 {{possible target of indirect goto statement}} + ; +} + +} // namespace seh |