| // 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(); |
| } |