forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			631 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			631 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
// 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) { // expected-warning {{enumeration value 'something_invalid' not handled in switch}}
 | 
						|
    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
 |