// 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 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(); test_unreachable_templates(); } // Do warn about explicit template specializations, as they represent // actual concrete functions that somebody wrote. template void funcToSpecialize() {} template <> void funcToSpecialize() { 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 struct basic_string { basic_string(const T* x) {} ~basic_string() {}; }; typedef basic_string 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(); }