forked from OSchip/llvm-project
648 lines
14 KiB
C++
648 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) { // 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
|
|
|
|
void continue_scope_check() {
|
|
// These are OK.
|
|
for (; ({break; true;});) {}
|
|
for (; ({continue; true;});) {}
|
|
for (; int n = ({break; 0;});) {}
|
|
for (; int n = 0; ({break;})) {}
|
|
for (; int n = 0; ({continue;})) {}
|
|
|
|
// This would jump past the initialization of 'n' to the increment (where 'n'
|
|
// is in scope).
|
|
for (; int n = ({continue; 0;});) {} // expected-error {{cannot jump from this continue statement to the loop increment; jump bypasses initialization of loop condition variable}}
|
|
|
|
// An intervening loop makes it OK again.
|
|
for (; int n = ({while (true) continue; 0;});) {}
|
|
}
|