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