blob: a14e4226861c1ba18a6d37a9faf97b975c5f8326 [file] [log] [blame]
// RUN: %clang_cc1 %s -fcxx-exceptions -fexceptions -fsyntax-only -verify -fblocks -std=c++11 -Wunreachable-code-aggressive -Wno-unused-value -Wno-tautological-compare
int &halt() __attribute__((noreturn));
int &live();
int dead();
int liveti() throw(int);
int (*livetip)() throw(int);
int test1() {
try {
live();
} catch (int i) {
live();
}
return 1;
}
void test2() {
try {
live();
} catch (int i) {
live();
}
try {
liveti();
} catch (int i) {
live();
}
try {
livetip();
} catch (int i) {
live();
}
throw 1;
dead(); // expected-warning {{will never be executed}}
}
void test3() {
halt()
--; // expected-warning {{will never be executed}}
// FIXME: The unreachable part is just the '?', but really all of this
// code is unreachable and shouldn't be separately reported.
halt() // expected-warning {{will never be executed}}
?
dead() : dead();
live(),
float
(halt()); // expected-warning {{will never be executed}}
}
namespace Test4 {
struct S {
int mem;
} s;
S &foor();
void test4() {
halt(), foor()// expected-warning {{will never be executed}}
.mem;
}
}
namespace Test5 {
struct S {
int mem;
} s;
S &foonr() __attribute__((noreturn));
void test5() {
foonr()
.mem; // expected-warning {{will never be executed}}
}
}
void test6() {
struct S {
~S() { }
S(int i) { }
};
live(),
S
(halt()); // expected-warning {{will never be executed}}
}
// Don't warn about unreachable code in template instantiations, as
// they may only be unreachable in that specific instantiation.
void isUnreachable();
template <typename T> void test_unreachable_templates() {
T::foo();
isUnreachable(); // no-warning
}
struct TestUnreachableA {
static void foo() __attribute__((noreturn));
};
struct TestUnreachableB {
static void foo();
};
void test_unreachable_templates_harness() {
test_unreachable_templates<TestUnreachableA>();
test_unreachable_templates<TestUnreachableB>();
}
// Do warn about explicit template specializations, as they represent
// actual concrete functions that somebody wrote.
template <typename T> void funcToSpecialize() {}
template <> void funcToSpecialize<int>() {
halt();
dead(); // expected-warning {{will never be executed}}
}
// Handle 'try' code dominating a dead return.
enum PR19040_test_return_t
{ PR19040_TEST_FAILURE };
namespace PR19040_libtest
{
class A {
public:
~A ();
};
}
PR19040_test_return_t PR19040_fn1 ()
{
try
{
throw PR19040_libtest::A ();
} catch (...)
{
return PR19040_TEST_FAILURE;
}
return PR19040_TEST_FAILURE; // expected-warning {{will never be executed}}
}
__attribute__((noreturn))
void raze();
namespace std {
template<typename T> struct basic_string {
basic_string(const T* x) {}
~basic_string() {};
};
typedef basic_string<char> string;
}
std::string testStr() {
raze();
return ""; // expected-warning {{'return' will never be executed}}
}
std::string testStrWarn(const char *s) {
raze();
return s; // expected-warning {{will never be executed}}
}
bool testBool() {
raze();
return true; // expected-warning {{'return' will never be executed}}
}
static const bool ConditionVar = 1;
int test_global_as_conditionVariable() {
if (ConditionVar)
return 1;
return 0; // no-warning
}
// Handle unreachable temporary destructors.
class A {
public:
A();
~A();
};
__attribute__((noreturn))
void raze(const A& x);
void test_with_unreachable_tmp_dtors(int x) {
raze(x ? A() : A()); // no-warning
}
// Test sizeof - sizeof in enum declaration.
enum { BrownCow = sizeof(long) - sizeof(char) };
enum { CowBrown = 8 - 1 };
int test_enum_sizeof_arithmetic() {
if (BrownCow)
return 1;
return 2;
}
int test_enum_arithmetic() {
if (CowBrown)
return 1;
return 2; // expected-warning {{never be executed}}
}
int test_arithmetic() {
if (8 -1)
return 1;
return 2; // expected-warning {{never be executed}}
}
int test_treat_const_bool_local_as_config_value() {
const bool controlValue = false;
if (!controlValue)
return 1;
test_treat_const_bool_local_as_config_value(); // no-warning
return 0;
}
int test_treat_non_const_bool_local_as_non_config_value() {
bool controlValue = false;
if (!controlValue)
return 1;
// There is no warning here because 'controlValue' isn't really
// a control value at all. The CFG will not treat this
// branch as unreachable.
test_treat_non_const_bool_local_as_non_config_value(); // no-warning
return 0;
}
void test_do_while(int x) {
// Handle trivial expressions with
// implicit casts to bool.
do {
break;
} while (0); // no-warning
}
class Frobozz {
public:
Frobozz(int x);
~Frobozz();
};
Frobozz test_return_object(int flag) {
return Frobozz(flag);
return Frobozz(42); // expected-warning {{'return' will never be executed}}
}
Frobozz test_return_object_control_flow(int flag) {
return Frobozz(flag);
return Frobozz(flag ? 42 : 24); // expected-warning {{code will never be executed}}
}
void somethingToCall();
static constexpr bool isConstExprConfigValue() { return true; }
int test_const_expr_config_value() {
if (isConstExprConfigValue()) {
somethingToCall();
return 0;
}
somethingToCall(); // no-warning
return 1;
}
int test_const_expr_config_value_2() {
if (!isConstExprConfigValue()) {
somethingToCall(); // no-warning
return 0;
}
somethingToCall();
return 1;
}
class Frodo {
public:
static const bool aHobbit = true;
};
void test_static_class_var() {
if (Frodo::aHobbit)
somethingToCall();
else
somethingToCall(); // no-warning
}
void test_static_class_var(Frodo &F) {
if (F.aHobbit)
somethingToCall();
else
somethingToCall(); // no-warning
}
void test_unreachable_for_null_increment() {
for (unsigned i = 0; i < 10 ; ) // no-warning
break;
}
void test_unreachable_forrange_increment() {
int x[10] = { 0 };
for (auto i : x) { // expected-warning {{loop will run at most once (loop increment never executed)}}
break;
}
}
void calledFun() {}
// Test "silencing" with parentheses.
void test_with_paren_silencing(int x) {
if (false) calledFun(); // expected-warning {{will never be executed}} expected-note {{silence by adding parentheses to mark code as explicitly dead}}
if ((false)) calledFun(); // no-warning
if (true) // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
calledFun();
else
calledFun(); // expected-warning {{will never be executed}}
if ((true))
calledFun();
else
calledFun(); // no-warning
if (!true) // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
calledFun(); // expected-warning {{code will never be executed}}
else
calledFun();
if ((!true))
calledFun(); // no-warning
else
calledFun();
if (!(true))
calledFun(); // no-warning
else
calledFun();
}
void test_with_paren_silencing_impcast(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();
}
void tautological_compare(bool x, int y) {
if (x > 10) // expected-note {{silence}}
calledFun(); // expected-warning {{will never be executed}}
if (10 < x) // expected-note {{silence}}
calledFun(); // expected-warning {{will never be executed}}
if (x == 10) // expected-note {{silence}}
calledFun(); // expected-warning {{will never be executed}}
if (x < 10) // expected-note {{silence}}
calledFun();
else
calledFun(); // expected-warning {{will never be executed}}
if (10 > x) // expected-note {{silence}}
calledFun();
else
calledFun(); // expected-warning {{will never be executed}}
if (x != 10) // expected-note {{silence}}
calledFun();
else
calledFun(); // expected-warning {{will never be executed}}
if (y != 5 && y == 5) // expected-note {{silence}}
calledFun(); // expected-warning {{will never be executed}}
if (y > 5 && y < 4) // expected-note {{silence}}
calledFun(); // expected-warning {{will never be executed}}
if (y < 10 || y > 5) // expected-note {{silence}}
calledFun();
else
calledFun(); // expected-warning {{will never be executed}}
// TODO: Extend warning to the following code:
if (x < -1)
calledFun();
if (x == -1)
calledFun();
if (x != -1)
calledFun();
else
calledFun();
if (-1 > x)
calledFun();
else
calledFun();
if (y == -1 && y != -1)
calledFun();
}