| // RUN: %clang_cc1 -triple x86_64-windows -fsyntax-only -verify -fblocks -fcxx-exceptions -fms-extensions %s -Wno-unreachable-code |
| // RUN: %clang_cc1 -triple x86_64-windows -fsyntax-only -verify -fblocks -fcxx-exceptions -fms-extensions -std=gnu++11 %s -Wno-unreachable-code |
| |
| namespace testInvalid { |
| Invalid inv; // expected-error {{unknown type name}} |
| // Make sure this doesn't assert. |
| void fn() |
| { |
| int c = 0; |
| if (inv) |
| Here: ; |
| goto Here; |
| } |
| } |
| |
| namespace test0 { |
| struct D { ~D(); }; |
| |
| int f(bool b) { |
| if (b) { |
| D d; |
| goto end; |
| } |
| |
| end: |
| return 1; |
| } |
| } |
| |
| namespace test1 { |
| struct C { C(); }; |
| |
| int f(bool b) { |
| if (b) |
| goto foo; // expected-error {{cannot jump}} |
| C c; // expected-note {{jump bypasses variable initialization}} |
| foo: |
| return 1; |
| } |
| } |
| |
| namespace test2 { |
| struct C { C(); }; |
| |
| int f(void **ip) { |
| static void *ips[] = { &&lbl1, &&lbl2 }; |
| |
| C c; |
| goto *ip; |
| lbl1: |
| return 0; |
| lbl2: |
| return 1; |
| } |
| } |
| |
| namespace test3 { |
| struct C { C(); }; |
| |
| int f(void **ip) { |
| static void *ips[] = { &&lbl1, &&lbl2 }; |
| |
| goto *ip; |
| lbl1: { |
| C c; |
| return 0; |
| } |
| lbl2: |
| return 1; |
| } |
| } |
| |
| namespace test4 { |
| struct C { C(); }; |
| struct D { ~D(); }; |
| |
| int f(void **ip) { |
| static void *ips[] = { &&lbl1, &&lbl2 }; |
| |
| C c0; |
| |
| goto *ip; // expected-error {{cannot jump}} |
| C c1; // expected-note {{jump bypasses variable initialization}} |
| lbl1: // expected-note {{possible target of indirect goto}} |
| return 0; |
| lbl2: |
| return 1; |
| } |
| } |
| |
| namespace test5 { |
| struct C { C(); }; |
| struct D { ~D(); }; |
| |
| int f(void **ip) { |
| static void *ips[] = { &&lbl1, &&lbl2 }; |
| C c0; |
| |
| goto *ip; |
| lbl1: // expected-note {{possible target of indirect goto}} |
| return 0; |
| lbl2: |
| if (ip[1]) { |
| D d; // expected-note {{jump exits scope of variable with non-trivial destructor}} |
| ip += 2; |
| goto *ip; // expected-error {{cannot jump}} |
| } |
| return 1; |
| } |
| } |
| |
| namespace test6 { |
| struct C { C(); }; |
| |
| unsigned f(unsigned s0, unsigned s1, void **ip) { |
| static void *ips[] = { &&lbl1, &&lbl2, &&lbl3, &&lbl4 }; |
| C c0; |
| |
| goto *ip; |
| lbl1: |
| s0++; |
| goto *++ip; |
| lbl2: |
| s0 -= s1; |
| goto *++ip; |
| lbl3: { |
| unsigned tmp = s0; |
| s0 = s1; |
| s1 = tmp; |
| goto *++ip; |
| } |
| lbl4: |
| return s0; |
| } |
| } |
| |
| // C++0x says it's okay to skip non-trivial initializers on static |
| // locals, and we implement that in '03 as well. |
| namespace test7 { |
| struct C { C(); }; |
| |
| void test() { |
| goto foo; |
| static C c; |
| foo: |
| return; |
| } |
| } |
| |
| // PR7789 |
| namespace test8 { |
| void test1(int c) { |
| switch (c) { |
| case 0: |
| int x = 56; // expected-note {{jump bypasses variable initialization}} |
| case 1: // expected-error {{cannot jump}} |
| x = 10; |
| } |
| } |
| |
| void test2() { |
| goto l2; // expected-error {{cannot jump}} |
| l1: int x = 5; // expected-note {{jump bypasses variable initialization}} |
| l2: x++; |
| } |
| } |
| |
| namespace test9 { |
| struct S { int i; }; |
| void test1() { |
| goto foo; |
| S s; |
| foo: |
| return; |
| } |
| unsigned test2(unsigned x, unsigned y) { |
| switch (x) { |
| case 2: |
| S s; |
| if (y > 42) return x + y; |
| default: |
| return x - 2; |
| } |
| } |
| } |
| |
| // http://llvm.org/PR10462 |
| namespace PR10462 { |
| enum MyEnum { |
| something_valid, |
| something_invalid |
| }; |
| |
| bool recurse() { |
| MyEnum K; |
| switch (K) { // do not warn that 'something_invalid' is not listed; |
| // 'what_am_i_thinking' might have been intended to be that case. |
| case something_valid: |
| case what_am_i_thinking: // expected-error {{use of undeclared identifier}} |
| int *X = 0; |
| if (recurse()) { |
| } |
| |
| break; |
| } |
| } |
| } |
| |
| namespace test10 { |
| int test() { |
| static void *ps[] = { &&a0 }; |
| goto *&&a0; // expected-error {{cannot jump}} |
| int a = 3; // expected-note {{jump bypasses variable initialization}} |
| a0: |
| return 0; |
| } |
| } |
| |
| // pr13812 |
| namespace test11 { |
| struct C { |
| C(int x); |
| ~C(); |
| }; |
| void f(void **ip) { |
| static void *ips[] = { &&l0 }; |
| l0: // expected-note {{possible target of indirect goto}} |
| C c0 = 42; // expected-note {{jump exits scope of variable with non-trivial destructor}} |
| goto *ip; // expected-error {{cannot jump}} |
| } |
| } |
| |
| namespace test12 { |
| struct C { |
| C(int x); |
| ~C(); |
| }; |
| void f(void **ip) { |
| static void *ips[] = { &&l0 }; |
| const C c0 = 17; |
| l0: // expected-note {{possible target of indirect goto}} |
| const C &c1 = 42; // expected-note {{jump exits scope of lifetime-extended temporary with non-trivial destructor}} |
| const C &c2 = c0; |
| goto *ip; // expected-error {{cannot jump}} |
| } |
| } |
| |
| namespace test13 { |
| struct C { |
| C(int x); |
| ~C(); |
| int i; |
| }; |
| void f(void **ip) { |
| static void *ips[] = { &&l0 }; |
| l0: // expected-note {{possible target of indirect goto}} |
| const int &c1 = C(1).i; // expected-note {{jump exits scope of lifetime-extended temporary with non-trivial destructor}} |
| goto *ip; // expected-error {{cannot jump}} |
| } |
| } |
| |
| namespace test14 { |
| struct C { |
| C(int x); |
| ~C(); |
| operator int&() const; |
| }; |
| void f(void **ip) { |
| static void *ips[] = { &&l0 }; |
| l0: |
| // no warning since the C temporary is destructed before the goto. |
| const int &c1 = C(1); |
| goto *ip; |
| } |
| } |
| |
| // PR14225 |
| namespace test15 { |
| void f1() try { |
| goto x; // expected-error {{cannot jump}} |
| } 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 {{cannot jump}} |
| } |
| } |
| |
| namespace test16 { |
| struct S { int n; }; |
| int f() { |
| goto x; // expected-error {{cannot jump}} |
| const S &s = S(); // expected-note {{jump bypasses variable initialization}} |
| x: return s.n; |
| } |
| } |
| |
| #if __cplusplus >= 201103L |
| namespace test17 { |
| struct S { int get(); private: int n; }; |
| int f() { |
| goto x; // expected-error {{cannot jump}} |
| S s = {}; // expected-note {{jump bypasses variable initialization}} |
| x: return s.get(); |
| } |
| } |
| #endif |
| |
| namespace test18 { |
| struct A { ~A(); }; |
| struct B { const int &r; const A &a; }; |
| int f() { |
| void *p = &&x; |
| const A a = A(); |
| x: |
| B b = { 0, a }; // ok |
| goto *p; |
| } |
| int g() { |
| void *p = &&x; |
| x: // expected-note {{possible target of indirect goto}} |
| B b = { 0, A() }; // expected-note {{jump exits scope of lifetime-extended temporary with non-trivial destructor}} |
| goto *p; // expected-error {{cannot jump}} |
| } |
| } |
| |
| #if __cplusplus >= 201103L |
| namespace std { |
| typedef decltype(sizeof(int)) size_t; |
| template<typename T> struct initializer_list { |
| const T *begin; |
| size_t size; |
| initializer_list(const T *, size_t); |
| }; |
| } |
| namespace test19 { |
| struct A { ~A(); }; |
| |
| int f() { |
| void *p = &&x; |
| A a; |
| x: // expected-note {{possible target of indirect goto}} |
| std::initializer_list<A> il = { a }; // expected-note {{jump exits scope of lifetime-extended temporary with non-trivial destructor}} |
| goto *p; // expected-error {{cannot jump}} |
| } |
| } |
| |
| namespace test20 { |
| struct A { ~A(); }; |
| struct B { |
| const A &a; |
| }; |
| |
| int f() { |
| void *p = &&x; |
| A a; |
| x: |
| std::initializer_list<B> il = { |
| a, |
| a |
| }; |
| goto *p; |
| } |
| int g() { |
| void *p = &&x; |
| A a; |
| x: // expected-note {{possible target of indirect goto}} |
| std::initializer_list<B> il = { |
| a, |
| { A() } // expected-note {{jump exits scope of lifetime-extended temporary with non-trivial destructor}} |
| }; |
| goto *p; // expected-error {{cannot jump}} |
| } |
| } |
| #endif |
| |
| namespace test21 { |
| template<typename T> void f() { |
| goto x; // expected-error {{cannot jump}} |
| T t; // expected-note {{bypasses}} |
| x: return; |
| } |
| |
| template void f<int>(); |
| struct X { ~X(); }; |
| template void f<X>(); // expected-note {{instantiation of}} |
| } |
| |
| namespace PR18217 { |
| typedef int *X; |
| |
| template <typename T> |
| class MyCl { |
| T mem; |
| }; |
| |
| class Source { |
| MyCl<X> m; |
| public: |
| int getKind() const; |
| }; |
| |
| bool b; |
| template<typename TT> |
| static void foo(const Source &SF, MyCl<TT *> Source::*m) { |
| switch (SF.getKind()) { |
| case 1: return; |
| case 2: break; |
| case 3: |
| case 4: return; |
| }; |
| if (b) { |
| auto &y = const_cast<MyCl<TT *> &>(SF.*m); // expected-warning 0-1{{extension}} |
| } |
| } |
| |
| int Source::getKind() const { |
| foo(*this, &Source::m); |
| return 0; |
| } |
| } |
| |
| namespace test_recovery { |
| // Test that jump scope checking recovers when there are unspecified errors |
| // in the function declaration or body. |
| |
| void test(nexist, int c) { // expected-error {{}} |
| nexist_fn(); // expected-error {{}} |
| goto nexist_label; // expected-error {{use of undeclared label}} |
| goto a0; // expected-error {{cannot jump}} |
| int a = 0; // expected-note {{jump bypasses variable initialization}} |
| a0:; |
| |
| switch (c) { |
| case $: // expected-error {{}} |
| case 0: |
| int x = 56; // expected-note {{jump bypasses variable initialization}} |
| case 1: // expected-error {{cannot jump}} |
| x = 10; |
| } |
| } |
| } |
| |
| 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 { |
| goto out_of_finally_finally; // expected-warning {{jump out of __finally block has undefined behavior}} |
| } |
| |
| __try { |
| } __finally { |
| goto *&&out_of_finally_finally; // expected-warning {{jump out of __finally block has undefined behavior}} |
| } |
| 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}} expected-warning {{jump out of __finally block has undefined behavior}} |
| } |
| } |
| |
| 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 { |
| goto after_outer_except; // expected-warning {{jump out of __finally block has undefined behavior}} |
| } |
| } __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 |