227 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			227 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C
		
	
	
	
// RUN: %clang_analyze_cc1 -analyzer-checker=core,deadcode.DeadStores,alpha.deadcode.UnreachableCode -verify -analyzer-opt-analyze-nested-blocks -Wno-unused-value %s
 | 
						|
 | 
						|
extern void foo(int a);
 | 
						|
 | 
						|
// The first few tests are non-path specific - we should be able to find them
 | 
						|
 | 
						|
void test(unsigned a) {
 | 
						|
  switch (a) {
 | 
						|
    a += 5; // expected-warning{{never executed}}
 | 
						|
  case 2:
 | 
						|
    a *= 10;
 | 
						|
  case 3:
 | 
						|
    a %= 2;
 | 
						|
  }
 | 
						|
  foo(a);
 | 
						|
}
 | 
						|
 | 
						|
void test2(unsigned a) {
 | 
						|
 help:
 | 
						|
  if (a > 0)
 | 
						|
    return;
 | 
						|
  if (a == 0)
 | 
						|
    return;
 | 
						|
  foo(a); // expected-warning{{never executed}}
 | 
						|
  goto help;
 | 
						|
}
 | 
						|
 | 
						|
void test3(unsigned a) {
 | 
						|
  while(1);
 | 
						|
  if (a > 5) { // expected-warning{{never executed}}
 | 
						|
    return;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// These next tests are path-sensitive
 | 
						|
 | 
						|
void test4() {
 | 
						|
  int a = 5;
 | 
						|
 | 
						|
  while (a > 1)
 | 
						|
    a -= 2;
 | 
						|
 | 
						|
  if (a > 1) {
 | 
						|
    a = a + 56; // expected-warning{{never executed}}
 | 
						|
  }
 | 
						|
 | 
						|
  foo(a);
 | 
						|
}
 | 
						|
 | 
						|
extern void bar(char c);
 | 
						|
 | 
						|
void test5(const char *c) {
 | 
						|
  foo(c[0]);
 | 
						|
 | 
						|
  if (!c) {
 | 
						|
    bar(1); // expected-warning{{never executed}}
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// These next tests are false positives and should not generate warnings
 | 
						|
 | 
						|
void test6(const char *c) {
 | 
						|
  if (c) return;
 | 
						|
  if (!c) return;
 | 
						|
  __builtin_unreachable(); // no-warning
 | 
						|
  __builtin_assume(0); // no-warning
 | 
						|
}
 | 
						|
 | 
						|
// Compile-time constant false positives
 | 
						|
#define CONSTANT 0
 | 
						|
enum test_enum { Off, On };
 | 
						|
void test7() {
 | 
						|
  if (CONSTANT)
 | 
						|
    return; // no-warning
 | 
						|
 | 
						|
  if (sizeof(int))
 | 
						|
    return; // no-warning
 | 
						|
 | 
						|
  if (Off)
 | 
						|
    return; // no-warning
 | 
						|
}
 | 
						|
 | 
						|
void test8() {
 | 
						|
  static unsigned a = 0;
 | 
						|
 | 
						|
  if (a)
 | 
						|
    a = 123; // no-warning
 | 
						|
 | 
						|
  a = 5;
 | 
						|
}
 | 
						|
 | 
						|
// Check for bugs where multiple statements are reported
 | 
						|
void test9(unsigned a) {
 | 
						|
  switch (a) {
 | 
						|
    if (a) // expected-warning{{never executed}}
 | 
						|
      foo(a + 5); // no-warning
 | 
						|
    else          // no-warning
 | 
						|
      foo(a);     // no-warning
 | 
						|
    case 1:
 | 
						|
    case 2:
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Tests from flow-sensitive version
 | 
						|
void test10() {
 | 
						|
  goto c;
 | 
						|
  d:
 | 
						|
  goto e; // expected-warning {{never executed}}
 | 
						|
  c: ;
 | 
						|
  int i;
 | 
						|
  return;
 | 
						|
  goto b; // expected-warning {{never executed}}
 | 
						|
  goto a; // expected-warning {{never executed}}
 | 
						|
  b:
 | 
						|
  i = 1; // no-warning
 | 
						|
  a:
 | 
						|
  i = 2;  // no-warning
 | 
						|
  goto f;
 | 
						|
  e:
 | 
						|
  goto d;
 | 
						|
  f: ;
 | 
						|
}
 | 
						|
 | 
						|
// test11: we can actually end up in the default case, even if it is not
 | 
						|
// obvious: there might be something wrong with the given argument.
 | 
						|
enum foobar { FOO, BAR };
 | 
						|
extern void error();
 | 
						|
void test11(enum foobar fb) {
 | 
						|
  switch (fb) {
 | 
						|
    case FOO:
 | 
						|
      break;
 | 
						|
    case BAR:
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      error(); // no-warning
 | 
						|
      return;
 | 
						|
      error(); // expected-warning {{never executed}}
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void inlined(int condition) {
 | 
						|
  if (condition) {
 | 
						|
    foo(5); // no-warning
 | 
						|
  } else {
 | 
						|
    foo(6);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void testInlined() {
 | 
						|
  extern int coin();
 | 
						|
  int cond = coin();
 | 
						|
  if (!cond) {
 | 
						|
    inlined(0);
 | 
						|
    if (cond) {
 | 
						|
      foo(5); // expected-warning {{never executed}}
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Don't warn about unreachable VarDecl.
 | 
						|
void dostuff(int*A);
 | 
						|
void varDecl1(int X) {
 | 
						|
  switch (X) {
 | 
						|
    int A; // No warning here.
 | 
						|
  case 1:
 | 
						|
    dostuff(&A);
 | 
						|
    break;
 | 
						|
  case 2:
 | 
						|
    dostuff(&A);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
}
 | 
						|
void varDecl2(int X) {
 | 
						|
  switch (X) {
 | 
						|
    int A=1; // expected-warning {{never executed}}
 | 
						|
  case 1:
 | 
						|
    dostuff(&A);
 | 
						|
    break;
 | 
						|
  case 2:
 | 
						|
    dostuff(&A);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Ensure that ExplodedGraph and unoptimized CFG match.
 | 
						|
void test12(int x) {
 | 
						|
  switch (x) {
 | 
						|
  case 1:
 | 
						|
    break; // not unreachable
 | 
						|
  case 2:
 | 
						|
    do { } while (0);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Don't merge return nodes in ExplodedGraph unless they are same.
 | 
						|
extern int table[];
 | 
						|
static int inlineFunction(const int i) {
 | 
						|
  if (table[i] != 0)
 | 
						|
    return 1;
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
void test13(int i) {
 | 
						|
  int x = inlineFunction(i);
 | 
						|
  x && x < 10; // no-warning
 | 
						|
}
 | 
						|
 | 
						|
// Don't warn in a macro
 | 
						|
#define RETURN(X)  do { return; } while (0)
 | 
						|
void macro(void) {
 | 
						|
  RETURN(1); // no-warning
 | 
						|
}
 | 
						|
 | 
						|
// Avoid FP when macro argument is known
 | 
						|
void writeSomething(int *x);
 | 
						|
#define MACRO(C)        \
 | 
						|
  if (!C) {             \
 | 
						|
    static int x;       \
 | 
						|
    writeSomething(&x); \
 | 
						|
  }
 | 
						|
void macro2(void) {
 | 
						|
  MACRO(1);
 | 
						|
}
 |