forked from OSchip/llvm-project
505 lines
13 KiB
C
505 lines
13 KiB
C
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -Wunreachable-code-aggressive -Wno-unused-value -Wno-covered-switch-default -I %S/Inputs %s
|
|
// RUN: %clang_cc1 -fsyntax-only -fblocks -Wunreachable-code-aggressive -Wno-unused-value -Wno-covered-switch-default -fdiagnostics-parseable-fixits -I %S/Inputs %s 2>&1 | FileCheck %s
|
|
|
|
#include "warn-unreachable.h"
|
|
|
|
int halt(void) __attribute__((noreturn));
|
|
int live(void);
|
|
int dead(void);
|
|
|
|
void test1(void) {
|
|
goto c;
|
|
d:
|
|
goto e; // expected-warning {{will never be executed}}
|
|
c: ;
|
|
int i;
|
|
return;
|
|
goto b; // expected-warning {{will never be executed}}
|
|
goto a; // expected-warning {{will never be executed}}
|
|
b:
|
|
i = 1;
|
|
a:
|
|
i = 2;
|
|
goto f;
|
|
e:
|
|
goto d;
|
|
f: ;
|
|
}
|
|
|
|
void test2(void) {
|
|
int i;
|
|
switch (live()) {
|
|
case 1:
|
|
halt(),
|
|
dead(); // expected-warning {{will never be executed}}
|
|
|
|
case 2:
|
|
live(), halt(),
|
|
dead(); // expected-warning {{will never be executed}}
|
|
|
|
case 3:
|
|
live()
|
|
+ // expected-warning {{will never be executed}}
|
|
halt();
|
|
dead();
|
|
|
|
case 4:
|
|
a4:
|
|
live(),
|
|
halt();
|
|
goto a4; // expected-warning {{will never be executed}}
|
|
|
|
case 5:
|
|
goto a5;
|
|
c5:
|
|
dead(); // expected-warning {{will never be executed}}
|
|
goto b5;
|
|
a5:
|
|
live(),
|
|
halt();
|
|
b5:
|
|
goto c5;
|
|
|
|
case 6:
|
|
if (live())
|
|
goto e6;
|
|
live(),
|
|
halt();
|
|
d6:
|
|
dead(); // expected-warning {{will never be executed}}
|
|
goto b6;
|
|
c6:
|
|
dead();
|
|
goto b6;
|
|
e6:
|
|
live(),
|
|
halt();
|
|
b6:
|
|
goto c6;
|
|
case 7:
|
|
halt()
|
|
+
|
|
dead(); // expected-warning {{will never be executed}}
|
|
- // expected-warning {{will never be executed}}
|
|
halt();
|
|
case 8:
|
|
i
|
|
+= // expected-warning {{will never be executed}}
|
|
halt();
|
|
case 9:
|
|
halt()
|
|
? // expected-warning {{will never be executed}}
|
|
dead() : dead();
|
|
case 10:
|
|
( // expected-warning {{will never be executed}}
|
|
float)halt();
|
|
case 11: {
|
|
int a[5];
|
|
live(),
|
|
a[halt()
|
|
]; // expected-warning {{will never be executed}}
|
|
}
|
|
}
|
|
}
|
|
|
|
enum Cases { C1, C2, C3 };
|
|
int test_enum_cases(enum Cases C) {
|
|
switch (C) {
|
|
case C1:
|
|
case C2:
|
|
case C3:
|
|
return 1;
|
|
default: {
|
|
int i = 0; // no-warning
|
|
++i;
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle unreachable code triggered by macro expansions.
|
|
void __myassert_rtn(const char *, const char *, int, const char *) __attribute__((__noreturn__));
|
|
|
|
#define myassert(e) \
|
|
(__builtin_expect(!(e), 0) ? __myassert_rtn(__func__, __FILE__, __LINE__, #e) : (void)0)
|
|
|
|
void test_assert(void) {
|
|
myassert(0 && "unreachable");
|
|
return; // no-warning
|
|
}
|
|
|
|
// Test case for PR 9774. Tests that dead code in macros aren't warned about.
|
|
#define MY_MAX(a,b) ((a) >= (b) ? (a) : (b))
|
|
void PR9774(int *s) {
|
|
for (int i = 0; i < MY_MAX(2, 3); i++) // no-warning
|
|
s[i] = 0;
|
|
}
|
|
|
|
// Test case for <rdar://problem/11005770>. We should treat code guarded
|
|
// by 'x & 0' and 'x * 0' as unreachable.
|
|
int calledFun(void);
|
|
void test_mul_and_zero(int x) {
|
|
if (x & 0) calledFun(); // expected-warning {{will never be executed}}
|
|
if (0 & x) calledFun(); // expected-warning {{will never be executed}}
|
|
if (x * 0) calledFun(); // expected-warning {{will never be executed}}
|
|
if (0 * x) calledFun(); // expected-warning {{will never be executed}}
|
|
}
|
|
|
|
void raze(void) __attribute__((noreturn));
|
|
void warn_here(void);
|
|
|
|
int test_break_preceded_by_noreturn(int i) {
|
|
switch (i) {
|
|
case 1:
|
|
raze();
|
|
break; // expected-warning {{'break' will never be executed}}
|
|
case 2:
|
|
raze();
|
|
break; // expected-warning {{'break' will never be executed}}
|
|
warn_here(); // expected-warning {{will never be executed}}
|
|
case 3:
|
|
return 1;
|
|
break; // expected-warning {{will never be executed}}
|
|
default:
|
|
break;
|
|
break; // expected-warning {{will never be executed}}
|
|
}
|
|
return i;
|
|
}
|
|
|
|
// Don't warn about unreachable 'default' cases, as that is covered
|
|
// by -Wcovered-switch-default.
|
|
typedef enum { Value1 = 1 } MyEnum;
|
|
void unreachable_default(MyEnum e) {
|
|
switch (e) {
|
|
case Value1:
|
|
calledFun();
|
|
break;
|
|
case 2: // expected-warning {{case value not in enumerated type 'MyEnum'}}
|
|
calledFun();
|
|
break;
|
|
default:
|
|
calledFun(); // no-warning
|
|
break;
|
|
}
|
|
}
|
|
void unreachable_in_default(MyEnum e) {
|
|
switch (e) {
|
|
default:
|
|
raze();
|
|
calledFun(); // expected-warning {{will never be executed}}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Don't warn about trivial dead returns.
|
|
int trivial_dead_return(void) {
|
|
raze();
|
|
return ((0)); // expected-warning {{'return' will never be executed}}
|
|
}
|
|
|
|
void trivial_dead_return_void(void) {
|
|
raze();
|
|
return; // expected-warning {{'return' will never be executed}}
|
|
}
|
|
|
|
MyEnum trivial_dead_return_enum(void) {
|
|
raze();
|
|
return Value1; // expected-warning {{'return' will never be executed}}
|
|
}
|
|
|
|
MyEnum trivial_dead_return_enum_2(int x) {
|
|
switch (x) {
|
|
case 1: return 1;
|
|
case 2: return 2;
|
|
case 3: return 3;
|
|
default: return 4;
|
|
}
|
|
|
|
return 2; // expected-warning {{will never be executed}}
|
|
}
|
|
|
|
const char *trivial_dead_return_cstr(void) {
|
|
raze();
|
|
return ""; // expected-warning {{return' will never be executed}}
|
|
}
|
|
|
|
char trivial_dead_return_char(void) {
|
|
raze();
|
|
return ' '; // expected-warning {{return' will never be executed}}
|
|
}
|
|
|
|
MyEnum nontrivial_dead_return_enum_2(int x) {
|
|
switch (x) {
|
|
case 1: return 1;
|
|
case 2: return 2;
|
|
case 3: return 3;
|
|
default: return 4;
|
|
}
|
|
|
|
return calledFun(); // expected-warning {{will never be executed}}
|
|
}
|
|
|
|
enum X { A, B, C };
|
|
|
|
int covered_switch(enum X x) {
|
|
switch (x) {
|
|
case A: return 1;
|
|
case B: return 2;
|
|
case C: return 3;
|
|
}
|
|
return 4; // no-warning
|
|
}
|
|
|
|
// Test unreachable code depending on configuration values
|
|
#define CONFIG_CONSTANT 1
|
|
int test_config_constant(int x) {
|
|
if (!CONFIG_CONSTANT) {
|
|
calledFun(); // no-warning
|
|
return 1;
|
|
}
|
|
if (!1) { // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
|
|
calledFun(); // expected-warning {{will never be executed}}
|
|
return 1;
|
|
}
|
|
if (sizeof(int) > sizeof(char)) {
|
|
calledFun(); // no-warning
|
|
return 1;
|
|
}
|
|
if (x > 10)
|
|
return CONFIG_CONSTANT ? calledFun() : calledFun(); // no-warning
|
|
else
|
|
return 1 ? // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
|
|
calledFun() :
|
|
calledFun(); // expected-warning {{will never be executed}}
|
|
}
|
|
|
|
int sizeof_int(int x, int y) {
|
|
if (sizeof(long) == sizeof(int))
|
|
return 1; // no-warning
|
|
if (sizeof(long) != sizeof(int))
|
|
return 0; // no-warning
|
|
if (x && y && sizeof(long) < sizeof(char))
|
|
return 0; // no-warning
|
|
return 2; // no-warning
|
|
}
|
|
|
|
enum MyEnum2 {
|
|
ME_A = CONFIG_CONSTANT,
|
|
ME_B = 1
|
|
};
|
|
|
|
int test_MyEnum(void) {
|
|
if (!ME_A)
|
|
return 1; // no-warning
|
|
if (ME_A)
|
|
return 2; // no-warning
|
|
if (ME_B)
|
|
return 3;
|
|
if (!ME_B) // expected-warning {{will never be executed}}
|
|
return 4; // expected-warning {{will never be executed}}
|
|
return 5;
|
|
}
|
|
|
|
// Test for idiomatic do..while.
|
|
int test_do_while(int x) {
|
|
do {
|
|
if (x == calledFun())
|
|
break;
|
|
++x;
|
|
break;
|
|
}
|
|
while (0); // no-warning
|
|
return x;
|
|
}
|
|
|
|
int test_do_while_nontrivial_cond(int x) {
|
|
do {
|
|
if (x == calledFun())
|
|
break;
|
|
++x;
|
|
break;
|
|
}
|
|
while (calledFun()); // expected-warning {{will never be executed}}
|
|
return x;
|
|
}
|
|
|
|
// Diagnostic control: -Wunreachable-code-return.
|
|
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wunreachable-code-return"
|
|
|
|
void trivial_dead_return_void_SUPPRESSED(void) {
|
|
raze();
|
|
return; // no-warning
|
|
}
|
|
|
|
MyEnum trivial_dead_return_enum_SUPPRESSED(void) {
|
|
raze();
|
|
return Value1; // no-warning
|
|
}
|
|
|
|
#pragma clang diagnostic pop
|
|
|
|
// Diagnostic control: -Wunreachable-code-break.
|
|
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wunreachable-code-break"
|
|
|
|
int test_break_preceded_by_noreturn_SUPPRESSED(int i) {
|
|
switch (i) {
|
|
case 1:
|
|
raze();
|
|
break; // no-warning
|
|
case 2:
|
|
raze();
|
|
break; // no-warning
|
|
warn_here(); // expected-warning {{will never be executed}}
|
|
case 3:
|
|
return 1;
|
|
break; // no-warning
|
|
default:
|
|
break;
|
|
break; // no-warning
|
|
}
|
|
return i;
|
|
}
|
|
|
|
#pragma clang diagnostic pop
|
|
|
|
// Test "silencing" with parentheses.
|
|
void test_with_paren_silencing(int x) {
|
|
if (0) calledFun(); // expected-warning {{will never be executed}} expected-note {{silence by adding parentheses to mark code as explicitly dead}}
|
|
if ((0)) calledFun(); // no-warning
|
|
|
|
if (1) // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
|
|
calledFun();
|
|
else
|
|
calledFun(); // expected-warning {{will never be executed}}
|
|
|
|
if ((1))
|
|
calledFun();
|
|
else
|
|
calledFun(); // no-warning
|
|
|
|
if (!1) // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
|
|
calledFun(); // expected-warning {{code will never be executed}}
|
|
else
|
|
calledFun();
|
|
|
|
if ((!1))
|
|
calledFun(); // no-warning
|
|
else
|
|
calledFun();
|
|
|
|
if (!(1))
|
|
calledFun(); // no-warning
|
|
else
|
|
calledFun();
|
|
}
|
|
|
|
// rdar://24570531
|
|
|
|
struct StructWithPointer {
|
|
void *p;
|
|
};
|
|
|
|
void emitJustOneWarningForOr(struct StructWithPointer *s) {
|
|
if (1 || !s->p) // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
|
|
return; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:7-[[@LINE-1]]:7}:"/* DISABLES CODE */ ("
|
|
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:8-[[@LINE-2]]:8}:")"
|
|
emitJustOneWarningForOr(s); // expected-warning {{code will never be executed}}
|
|
}
|
|
|
|
void emitJustOneWarningForOrSilenced(struct StructWithPointer *s) {
|
|
if ((1) || !s->p)
|
|
return;
|
|
|
|
emitJustOneWarningForOrSilenced(s); // no warning
|
|
}
|
|
|
|
void emitJustOneWarningForOr2(struct StructWithPointer *s) {
|
|
if (1 || !s->p) // expected-warning {{code will never be executed}}
|
|
return; // expected-note@-1 {{silence by adding parentheses to mark code as explicitly dead}}
|
|
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:7-[[@LINE-2]]:7}:"/* DISABLES CODE */ ("
|
|
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:8-[[@LINE-3]]:8}:")"
|
|
}
|
|
|
|
void wrapOneInFixit(struct StructWithPointer *s) {
|
|
if (!s->p || 1) // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
|
|
return; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:16-[[@LINE-1]]:16}:"/* DISABLES CODE */ ("
|
|
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:17-[[@LINE-2]]:17}:")"
|
|
wrapOneInFixit(s); // expected-warning {{code will never be executed}}
|
|
}
|
|
|
|
void unaryOpNoFixit(void) {
|
|
if (~ 1)
|
|
return; // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
|
|
unaryOpNoFixit(); // expected-warning {{code will never be executed}}
|
|
}
|
|
|
|
void unaryOpStrictFixit(struct StructWithPointer *s) {
|
|
if (!(s->p && 0)) // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
|
|
return; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:17-[[@LINE-1]]:17}:"/* DISABLES CODE */ ("
|
|
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:18-[[@LINE-2]]:18}:")"
|
|
unaryOpStrictFixit(s); // expected-warning {{code will never be executed}}
|
|
}
|
|
|
|
void unaryOpFixitCastSubExpr(int x) {
|
|
if (! (int)0) // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
|
|
return; // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:7-[[@LINE-1]]:7}:"/* DISABLES CODE */ ("
|
|
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:")"
|
|
unaryOpFixitCastSubExpr(x); // expected-warning {{code will never be executed}}
|
|
}
|
|
|
|
#define false 0
|
|
#define true 1
|
|
|
|
void testTrueFalseMacros(void) {
|
|
if (false) // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
|
|
testTrueFalseMacros(); // expected-warning {{code will never be executed}}
|
|
if (!true) // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
|
|
testTrueFalseMacros(); // expected-warning {{code will never be executed}}
|
|
}
|
|
|
|
int pr13910_foo(int x) {
|
|
if (x == 1)
|
|
return 0;
|
|
else
|
|
return x;
|
|
__builtin_unreachable(); // expected no warning
|
|
__builtin_assume(0); // expected no warning
|
|
}
|
|
|
|
int pr13910_bar(int x) {
|
|
switch (x) {
|
|
default:
|
|
return x + 1;
|
|
}
|
|
pr13910_foo(x); // expected-warning {{code will never be executed}}
|
|
}
|
|
|
|
int pr13910_bar2(int x) {
|
|
if (x == 1)
|
|
return 0;
|
|
else
|
|
return x;
|
|
pr13910_foo(x); // expected-warning {{code will never be executed}}
|
|
__builtin_unreachable(); // expected no warning
|
|
__builtin_assume(0); // expected no warning
|
|
pr13910_foo(x); // expected-warning {{code will never be executed}}
|
|
}
|
|
|
|
void pr13910_noreturn(void) {
|
|
raze();
|
|
__builtin_unreachable(); // expected no warning
|
|
__builtin_assume(0); // expected no warning
|
|
}
|
|
|
|
void pr13910_assert(void) {
|
|
myassert(0 && "unreachable");
|
|
return;
|
|
__builtin_unreachable(); // expected no warning
|
|
__builtin_assume(0); // expected no warning
|
|
}
|