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