410 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			410 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C++
		
	
	
	
// 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}}
 | 
						|
}
 | 
						|
 | 
						|
void test4() {
 | 
						|
  struct S {
 | 
						|
    int mem;
 | 
						|
  } s;
 | 
						|
  S &foor();
 | 
						|
  halt(), foor()// expected-warning {{will never be executed}}
 | 
						|
    .mem;       
 | 
						|
}
 | 
						|
 | 
						|
void test5() {
 | 
						|
  struct S {
 | 
						|
    int mem;
 | 
						|
  } s;
 | 
						|
  S &foonr() __attribute__((noreturn));
 | 
						|
  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 explict 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();
 | 
						|
}
 |