mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 08:16:06 +00:00

It was previously reverted by 8406839d1926486de900c7cabeea9f841bd3edf2. --- This flag was introduced by6818991d71
commit 6818991d7165f68fe196922d9e5c6648dd57cc47 Author: Ted Kremenek <kremenek@apple.com> Date: Mon Dec 7 22:06:12 2009 +0000 Add clang-cc option '-analyzer-opt-analyze-nested-blocks' to treat block literals as an entry point for analyzer checks. The last reference was removed by this commit:5c32dfc5fb
commit 5c32dfc5fb1cfcff8ae3671284e17daa8da3a188 Author: Anna Zaks <ganna@apple.com> Date: Fri Dec 21 01:19:15 2012 +0000 [analyzer] Add blocks and ObjC messages to the call graph. This paves the road for constructing a better function dependency graph. If we analyze a function before the functions it calls and inlines, there is more opportunity for optimization. Note, we add call edges to the called methods that correspond to function definitions (declarations with bodies). Consequently, we should remove this dead flag. However, this arises a couple of burning questions. - Should the `cc1` frontend still accept this flag - to keep tools/users passing this flag directly to `cc1` (which is unsupported, unadvertised) working. - If we should remain backward compatible, how long? - How can we get rid of deprecated and obsolete flags at some point? Reviewed By: martong Differential Revision: https://reviews.llvm.org/D126067
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 -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(void) {
|
|
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(void) {
|
|
if (CONSTANT)
|
|
return; // no-warning
|
|
|
|
if (sizeof(int))
|
|
return; // no-warning
|
|
|
|
if (Off)
|
|
return; // no-warning
|
|
}
|
|
|
|
void test8(void) {
|
|
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(void) {
|
|
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);
|
|
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(void) {
|
|
extern int coin(void);
|
|
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);
|
|
}
|