1 | // RUN: %clang_cc1 %s -fcxx-exceptions -fexceptions -fsyntax-only -verify -fblocks -std=c++11 -Wunreachable-code-aggressive -Wno-unused-value -Wno-tautological-compare |
2 | |
3 | int &halt() __attribute__((noreturn)); |
4 | int &live(); |
5 | int dead(); |
6 | int liveti() throw(int); |
7 | int (*livetip)() throw(int); |
8 | |
9 | int test1() { |
10 | try { |
11 | live(); |
12 | } catch (int i) { |
13 | live(); |
14 | } |
15 | return 1; |
16 | } |
17 | |
18 | void test2() { |
19 | try { |
20 | live(); |
21 | } catch (int i) { |
22 | live(); |
23 | } |
24 | try { |
25 | liveti(); |
26 | } catch (int i) { |
27 | live(); |
28 | } |
29 | try { |
30 | livetip(); |
31 | } catch (int i) { |
32 | live(); |
33 | } |
34 | throw 1; |
35 | dead(); // expected-warning {{will never be executed}} |
36 | } |
37 | |
38 | |
39 | void test3() { |
40 | halt() |
41 | --; // expected-warning {{will never be executed}} |
42 | // FIXME: The unreachable part is just the '?', but really all of this |
43 | // code is unreachable and shouldn't be separately reported. |
44 | halt() // expected-warning {{will never be executed}} |
45 | ? |
46 | dead() : dead(); |
47 | live(), |
48 | float |
49 | (halt()); // expected-warning {{will never be executed}} |
50 | } |
51 | |
52 | namespace Test4 { |
53 | struct S { |
54 | int mem; |
55 | } s; |
56 | S &foor(); |
57 | void test4() { |
58 | halt(), foor()// expected-warning {{will never be executed}} |
59 | .mem; |
60 | } |
61 | } |
62 | |
63 | namespace Test5 { |
64 | struct S { |
65 | int mem; |
66 | } s; |
67 | S &foonr() __attribute__((noreturn)); |
68 | void test5() { |
69 | foonr() |
70 | .mem; // expected-warning {{will never be executed}} |
71 | } |
72 | } |
73 | |
74 | void test6() { |
75 | struct S { |
76 | ~S() { } |
77 | S(int i) { } |
78 | }; |
79 | live(), |
80 | S |
81 | (halt()); // expected-warning {{will never be executed}} |
82 | } |
83 | |
84 | // Don't warn about unreachable code in template instantiations, as |
85 | // they may only be unreachable in that specific instantiation. |
86 | void isUnreachable(); |
87 | |
88 | template <typename T> void test_unreachable_templates() { |
89 | T::foo(); |
90 | isUnreachable(); // no-warning |
91 | } |
92 | |
93 | struct TestUnreachableA { |
94 | static void foo() __attribute__((noreturn)); |
95 | }; |
96 | struct TestUnreachableB { |
97 | static void foo(); |
98 | }; |
99 | |
100 | void test_unreachable_templates_harness() { |
101 | test_unreachable_templates<TestUnreachableA>(); |
102 | test_unreachable_templates<TestUnreachableB>(); |
103 | } |
104 | |
105 | // Do warn about explicit template specializations, as they represent |
106 | // actual concrete functions that somebody wrote. |
107 | |
108 | template <typename T> void funcToSpecialize() {} |
109 | template <> void funcToSpecialize<int>() { |
110 | halt(); |
111 | dead(); // expected-warning {{will never be executed}} |
112 | } |
113 | |
114 | // Handle 'try' code dominating a dead return. |
115 | enum PR19040_test_return_t |
116 | { PR19040_TEST_FAILURE }; |
117 | namespace PR19040_libtest |
118 | { |
119 | class A { |
120 | public: |
121 | ~A (); |
122 | }; |
123 | } |
124 | PR19040_test_return_t PR19040_fn1 () |
125 | { |
126 | try |
127 | { |
128 | throw PR19040_libtest::A (); |
129 | } catch (...) |
130 | { |
131 | return PR19040_TEST_FAILURE; |
132 | } |
133 | return PR19040_TEST_FAILURE; // expected-warning {{will never be executed}} |
134 | } |
135 | |
136 | __attribute__((noreturn)) |
137 | void raze(); |
138 | |
139 | namespace std { |
140 | template<typename T> struct basic_string { |
141 | basic_string(const T* x) {} |
142 | ~basic_string() {}; |
143 | }; |
144 | typedef basic_string<char> string; |
145 | } |
146 | |
147 | std::string testStr() { |
148 | raze(); |
149 | return ""; // expected-warning {{'return' will never be executed}} |
150 | } |
151 | |
152 | std::string testStrWarn(const char *s) { |
153 | raze(); |
154 | return s; // expected-warning {{will never be executed}} |
155 | } |
156 | |
157 | bool testBool() { |
158 | raze(); |
159 | return true; // expected-warning {{'return' will never be executed}} |
160 | } |
161 | |
162 | static const bool ConditionVar = 1; |
163 | int test_global_as_conditionVariable() { |
164 | if (ConditionVar) |
165 | return 1; |
166 | return 0; // no-warning |
167 | } |
168 | |
169 | // Handle unreachable temporary destructors. |
170 | class A { |
171 | public: |
172 | A(); |
173 | ~A(); |
174 | }; |
175 | |
176 | __attribute__((noreturn)) |
177 | void raze(const A& x); |
178 | |
179 | void test_with_unreachable_tmp_dtors(int x) { |
180 | raze(x ? A() : A()); // no-warning |
181 | } |
182 | |
183 | // Test sizeof - sizeof in enum declaration. |
184 | enum { BrownCow = sizeof(long) - sizeof(char) }; |
185 | enum { CowBrown = 8 - 1 }; |
186 | |
187 | |
188 | int test_enum_sizeof_arithmetic() { |
189 | if (BrownCow) |
190 | return 1; |
191 | return 2; |
192 | } |
193 | |
194 | int test_enum_arithmetic() { |
195 | if (CowBrown) |
196 | return 1; |
197 | return 2; // expected-warning {{never be executed}} |
198 | } |
199 | |
200 | int test_arithmetic() { |
201 | if (8 -1) |
202 | return 1; |
203 | return 2; // expected-warning {{never be executed}} |
204 | } |
205 | |
206 | int test_treat_const_bool_local_as_config_value() { |
207 | const bool controlValue = false; |
208 | if (!controlValue) |
209 | return 1; |
210 | test_treat_const_bool_local_as_config_value(); // no-warning |
211 | return 0; |
212 | } |
213 | |
214 | int test_treat_non_const_bool_local_as_non_config_value() { |
215 | bool controlValue = false; |
216 | if (!controlValue) |
217 | return 1; |
218 | // There is no warning here because 'controlValue' isn't really |
219 | // a control value at all. The CFG will not treat this |
220 | // branch as unreachable. |
221 | test_treat_non_const_bool_local_as_non_config_value(); // no-warning |
222 | return 0; |
223 | } |
224 | |
225 | void test_do_while(int x) { |
226 | // Handle trivial expressions with |
227 | // implicit casts to bool. |
228 | do { |
229 | break; |
230 | } while (0); // no-warning |
231 | } |
232 | |
233 | class Frobozz { |
234 | public: |
235 | Frobozz(int x); |
236 | ~Frobozz(); |
237 | }; |
238 | |
239 | Frobozz test_return_object(int flag) { |
240 | return Frobozz(flag); |
241 | return Frobozz(42); // expected-warning {{'return' will never be executed}} |
242 | } |
243 | |
244 | Frobozz test_return_object_control_flow(int flag) { |
245 | return Frobozz(flag); |
246 | return Frobozz(flag ? 42 : 24); // expected-warning {{code will never be executed}} |
247 | } |
248 | |
249 | void somethingToCall(); |
250 | |
251 | static constexpr bool isConstExprConfigValue() { return true; } |
252 | |
253 | int test_const_expr_config_value() { |
254 | if (isConstExprConfigValue()) { |
255 | somethingToCall(); |
256 | return 0; |
257 | } |
258 | somethingToCall(); // no-warning |
259 | return 1; |
260 | } |
261 | int test_const_expr_config_value_2() { |
262 | if (!isConstExprConfigValue()) { |
263 | somethingToCall(); // no-warning |
264 | return 0; |
265 | } |
266 | somethingToCall(); |
267 | return 1; |
268 | } |
269 | |
270 | class Frodo { |
271 | public: |
272 | static const bool aHobbit = true; |
273 | }; |
274 | |
275 | void test_static_class_var() { |
276 | if (Frodo::aHobbit) |
277 | somethingToCall(); |
278 | else |
279 | somethingToCall(); // no-warning |
280 | } |
281 | |
282 | void test_static_class_var(Frodo &F) { |
283 | if (F.aHobbit) |
284 | somethingToCall(); |
285 | else |
286 | somethingToCall(); // no-warning |
287 | } |
288 | |
289 | void test_unreachable_for_null_increment() { |
290 | for (unsigned i = 0; i < 10 ; ) // no-warning |
291 | break; |
292 | } |
293 | |
294 | void test_unreachable_forrange_increment() { |
295 | int x[10] = { 0 }; |
296 | for (auto i : x) { // expected-warning {{loop will run at most once (loop increment never executed)}} |
297 | break; |
298 | } |
299 | } |
300 | |
301 | void calledFun() {} |
302 | |
303 | // Test "silencing" with parentheses. |
304 | void test_with_paren_silencing(int x) { |
305 | if (false) calledFun(); // expected-warning {{will never be executed}} expected-note {{silence by adding parentheses to mark code as explicitly dead}} |
306 | if ((false)) calledFun(); // no-warning |
307 | |
308 | if (true) // expected-note {{silence by adding parentheses to mark code as explicitly dead}} |
309 | calledFun(); |
310 | else |
311 | calledFun(); // expected-warning {{will never be executed}} |
312 | |
313 | if ((true)) |
314 | calledFun(); |
315 | else |
316 | calledFun(); // no-warning |
317 | |
318 | if (!true) // expected-note {{silence by adding parentheses to mark code as explicitly dead}} |
319 | calledFun(); // expected-warning {{code will never be executed}} |
320 | else |
321 | calledFun(); |
322 | |
323 | if ((!true)) |
324 | calledFun(); // no-warning |
325 | else |
326 | calledFun(); |
327 | |
328 | if (!(true)) |
329 | calledFun(); // no-warning |
330 | else |
331 | calledFun(); |
332 | } |
333 | |
334 | void test_with_paren_silencing_impcast(int x) { |
335 | if (0) calledFun(); // expected-warning {{will never be executed}} expected-note {{silence by adding parentheses to mark code as explicitly dead}} |
336 | if ((0)) calledFun(); // no-warning |
337 | |
338 | if (1) // expected-note {{silence by adding parentheses to mark code as explicitly dead}} |
339 | calledFun(); |
340 | else |
341 | calledFun(); // expected-warning {{will never be executed}} |
342 | |
343 | if ((1)) |
344 | calledFun(); |
345 | else |
346 | calledFun(); // no-warning |
347 | |
348 | if (!1) // expected-note {{silence by adding parentheses to mark code as explicitly dead}} |
349 | calledFun(); // expected-warning {{code will never be executed}} |
350 | else |
351 | calledFun(); |
352 | |
353 | if ((!1)) |
354 | calledFun(); // no-warning |
355 | else |
356 | calledFun(); |
357 | |
358 | if (!(1)) |
359 | calledFun(); // no-warning |
360 | else |
361 | calledFun(); |
362 | } |
363 | |
364 | void tautological_compare(bool x, int y) { |
365 | if (x > 10) // expected-note {{silence}} |
366 | calledFun(); // expected-warning {{will never be executed}} |
367 | if (10 < x) // expected-note {{silence}} |
368 | calledFun(); // expected-warning {{will never be executed}} |
369 | if (x == 10) // expected-note {{silence}} |
370 | calledFun(); // expected-warning {{will never be executed}} |
371 | |
372 | if (x < 10) // expected-note {{silence}} |
373 | calledFun(); |
374 | else |
375 | calledFun(); // expected-warning {{will never be executed}} |
376 | if (10 > x) // expected-note {{silence}} |
377 | calledFun(); |
378 | else |
379 | calledFun(); // expected-warning {{will never be executed}} |
380 | if (x != 10) // expected-note {{silence}} |
381 | calledFun(); |
382 | else |
383 | calledFun(); // expected-warning {{will never be executed}} |
384 | |
385 | if (y != 5 && y == 5) // expected-note {{silence}} |
386 | calledFun(); // expected-warning {{will never be executed}} |
387 | |
388 | if (y > 5 && y < 4) // expected-note {{silence}} |
389 | calledFun(); // expected-warning {{will never be executed}} |
390 | |
391 | if (y < 10 || y > 5) // expected-note {{silence}} |
392 | calledFun(); |
393 | else |
394 | calledFun(); // expected-warning {{will never be executed}} |
395 | |
396 | // TODO: Extend warning to the following code: |
397 | if (x < -1) |
398 | calledFun(); |
399 | if (x == -1) |
400 | calledFun(); |
401 | |
402 | if (x != -1) |
403 | calledFun(); |
404 | else |
405 | calledFun(); |
406 | if (-1 > x) |
407 | calledFun(); |
408 | else |
409 | calledFun(); |
410 | |
411 | if (y == -1 && y != -1) |
412 | calledFun(); |
413 | } |
414 | |