1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,deadcode.DeadStores,alpha.deadcode.UnreachableCode -verify -analyzer-opt-analyze-nested-blocks -Wno-unused-value %s |
2 | |
3 | extern void foo(int a); |
4 | |
5 | // The first few tests are non-path specific - we should be able to find them |
6 | |
7 | void test(unsigned a) { |
8 | switch (a) { |
9 | a += 5; // expected-warning{{never executed}} |
10 | case 2: |
11 | a *= 10; |
12 | case 3: |
13 | a %= 2; |
14 | } |
15 | foo(a); |
16 | } |
17 | |
18 | void test2(unsigned a) { |
19 | help: |
20 | if (a > 0) |
21 | return; |
22 | if (a == 0) |
23 | return; |
24 | foo(a); // expected-warning{{never executed}} |
25 | goto help; |
26 | } |
27 | |
28 | void test3(unsigned a) { |
29 | while(1); |
30 | if (a > 5) { // expected-warning{{never executed}} |
31 | return; |
32 | } |
33 | } |
34 | |
35 | // These next tests are path-sensitive |
36 | |
37 | void test4() { |
38 | int a = 5; |
39 | |
40 | while (a > 1) |
41 | a -= 2; |
42 | |
43 | if (a > 1) { |
44 | a = a + 56; // expected-warning{{never executed}} |
45 | } |
46 | |
47 | foo(a); |
48 | } |
49 | |
50 | extern void bar(char c); |
51 | |
52 | void test5(const char *c) { |
53 | foo(c[0]); |
54 | |
55 | if (!c) { |
56 | bar(1); // expected-warning{{never executed}} |
57 | } |
58 | } |
59 | |
60 | // These next tests are false positives and should not generate warnings |
61 | |
62 | void test6(const char *c) { |
63 | if (c) return; |
64 | if (!c) return; |
65 | __builtin_unreachable(); // no-warning |
66 | __builtin_assume(0); // no-warning |
67 | } |
68 | |
69 | // Compile-time constant false positives |
70 | #define CONSTANT 0 |
71 | enum test_enum { Off, On }; |
72 | void test7() { |
73 | if (CONSTANT) |
74 | return; // no-warning |
75 | |
76 | if (sizeof(int)) |
77 | return; // no-warning |
78 | |
79 | if (Off) |
80 | return; // no-warning |
81 | } |
82 | |
83 | void test8() { |
84 | static unsigned a = 0; |
85 | |
86 | if (a) |
87 | a = 123; // no-warning |
88 | |
89 | a = 5; |
90 | } |
91 | |
92 | // Check for bugs where multiple statements are reported |
93 | void test9(unsigned a) { |
94 | switch (a) { |
95 | if (a) // expected-warning{{never executed}} |
96 | foo(a + 5); // no-warning |
97 | else // no-warning |
98 | foo(a); // no-warning |
99 | case 1: |
100 | case 2: |
101 | break; |
102 | default: |
103 | break; |
104 | } |
105 | } |
106 | |
107 | // Tests from flow-sensitive version |
108 | void test10() { |
109 | goto c; |
110 | d: |
111 | goto e; // expected-warning {{never executed}} |
112 | c: ; |
113 | int i; |
114 | return; |
115 | goto b; // expected-warning {{never executed}} |
116 | goto a; // expected-warning {{never executed}} |
117 | b: |
118 | i = 1; // no-warning |
119 | a: |
120 | i = 2; // no-warning |
121 | goto f; |
122 | e: |
123 | goto d; |
124 | f: ; |
125 | } |
126 | |
127 | // test11: we can actually end up in the default case, even if it is not |
128 | // obvious: there might be something wrong with the given argument. |
129 | enum foobar { FOO, BAR }; |
130 | extern void error(); |
131 | void test11(enum foobar fb) { |
132 | switch (fb) { |
133 | case FOO: |
134 | break; |
135 | case BAR: |
136 | break; |
137 | default: |
138 | error(); // no-warning |
139 | return; |
140 | error(); // expected-warning {{never executed}} |
141 | } |
142 | } |
143 | |
144 | void inlined(int condition) { |
145 | if (condition) { |
146 | foo(5); // no-warning |
147 | } else { |
148 | foo(6); |
149 | } |
150 | } |
151 | |
152 | void testInlined() { |
153 | extern int coin(); |
154 | int cond = coin(); |
155 | if (!cond) { |
156 | inlined(0); |
157 | if (cond) { |
158 | foo(5); // expected-warning {{never executed}} |
159 | } |
160 | } |
161 | } |
162 | |
163 | // Don't warn about unreachable VarDecl. |
164 | void dostuff(int*A); |
165 | void varDecl1(int X) { |
166 | switch (X) { |
167 | int A; // No warning here. |
168 | case 1: |
169 | dostuff(&A); |
170 | break; |
171 | case 2: |
172 | dostuff(&A); |
173 | break; |
174 | } |
175 | } |
176 | void varDecl2(int X) { |
177 | switch (X) { |
178 | int A=1; // expected-warning {{never executed}} |
179 | case 1: |
180 | dostuff(&A); |
181 | break; |
182 | case 2: |
183 | dostuff(&A); |
184 | break; |
185 | } |
186 | } |
187 | |
188 | // Ensure that ExplodedGraph and unoptimized CFG match. |
189 | void test12(int x) { |
190 | switch (x) { |
191 | case 1: |
192 | break; // not unreachable |
193 | case 2: |
194 | do { } while (0); |
195 | break; |
196 | } |
197 | } |
198 | |
199 | // Don't merge return nodes in ExplodedGraph unless they are same. |
200 | extern int table[]; |
201 | static int inlineFunction(const int i) { |
202 | if (table[i] != 0) |
203 | return 1; |
204 | return 0; |
205 | } |
206 | void test13(int i) { |
207 | int x = inlineFunction(i); |
208 | x && x < 10; // no-warning |
209 | } |
210 | |
211 | // Don't warn in a macro |
212 | #define RETURN(X) do { return; } while (0) |
213 | void macro(void) { |
214 | RETURN(1); // no-warning |
215 | } |
216 | |
217 | // Avoid FP when macro argument is known |
218 | void writeSomething(int *x); |
219 | #define MACRO(C) \ |
220 | if (!C) { \ |
221 | static int x; \ |
222 | writeSomething(&x); \ |
223 | } |
224 | void macro2(void) { |
225 | MACRO(1); |
226 | } |
227 | |