xref: /netbsd-src/tests/usr.bin/xlint/lint1/msg_193.c (revision 7d62b00eb9ad855ffcd7da46b41e23feb5476fac)
1 /*	$NetBSD: msg_193.c,v 1.20 2023/02/21 19:47:21 rillig Exp $	*/
2 # 3 "msg_193.c"
3 
4 // Test for message: statement not reached [193]
5 
6 /*
7  * Test the reachability of statements in a function.
8  *
9  *	if
10  *	if-else
11  *	if-else-if-else
12  *	for
13  *	while
14  *	do-while
15  *	switch
16  *	break
17  *	continue
18  *	goto
19  *	return
20  *
21  *	constant expression
22  *	system-dependent constant expression
23  */
24 
25 extern void reachable(void);
26 extern void unreachable(void);
27 extern _Bool maybe(void);
28 
29 
30 void
31 test_statement(void)
32 {
33 	reachable();
34 	reachable();
35 }
36 
37 void
38 test_compound_statement(void)
39 {
40 	reachable();
41 	{
42 		reachable();
43 		reachable();
44 	}
45 	reachable();
46 }
47 
48 void
49 test_if_statement(void)
50 {
51 	if (1)
52 		reachable();
53 	reachable();
54 	if (0)
55 		unreachable();		/* expect+0: ... [193] */
56 	reachable();
57 }
58 
59 void
60 test_if_compound_statement(void)
61 {
62 	if (1) {
63 		reachable();
64 	}
65 	if (1) {
66 		{
67 			{
68 				reachable();
69 			}
70 		}
71 	}
72 
73 	if (0) {
74 		unreachable();		/* expect+0: ... [193] */
75 	}
76 	if (0) {
77 		{
78 			{
79 				unreachable();	/* expect+0: ... [193] */
80 			}
81 		}
82 	}
83 }
84 
85 void
86 test_if_without_else(void)
87 {
88 	if (1)
89 		reachable();
90 	reachable();
91 
92 	if (0)
93 		unreachable();		/* expect+0: ... [193] */
94 	reachable();
95 }
96 
97 void
98 test_if_with_else(void)
99 {
100 	if (1)
101 		reachable();
102 	else
103 		unreachable();		/* expect+0: ... [193] */
104 	reachable();
105 
106 	if (0)
107 		unreachable();		/* expect+0: ... [193] */
108 	else
109 		reachable();
110 	reachable();
111 }
112 
113 void
114 test_if_else_if_else(void)
115 {
116 	if (1)
117 		reachable();
118 	else if (1)			/* expect+0: ... [193] */
119 		unreachable();
120 	else
121 		unreachable();		/* expect+0: ... [193] */
122 
123 	if (0)
124 		unreachable();		/* expect+0: ... [193] */
125 	else if (1)
126 		reachable();
127 	else
128 		unreachable();		/* expect+0: ... [193] */
129 
130 	if (0)
131 		unreachable();		/* expect+0: ... [193] */
132 	else if (0)
133 		unreachable();		/* expect+0: ... [193] */
134 	else
135 		reachable();
136 }
137 
138 void
139 test_if_return(void)
140 {
141 	if (1)
142 		return;
143 	unreachable();			/* expect+0: ... [193] */
144 }
145 
146 void
147 test_if_else_return(void)
148 {
149 	if (1)
150 		reachable();
151 	else
152 		return;			/* expect+0: ... [193] */
153 	reachable();
154 }
155 
156 void
157 test_for_forever(void)
158 {
159 	for (;;)
160 		reachable();
161 	unreachable();			/* expect+0: ... [193] */
162 }
163 
164 void
165 test_for_true(void)
166 {
167 	for (; 1;)
168 		reachable();
169 	unreachable();			/* expect+0: ... [193] */
170 }
171 
172 void
173 test_for_false(void)
174 {
175 	for (; 0;)
176 		unreachable();		/* expect+0: ... [193] */
177 	reachable();
178 }
179 
180 void
181 test_for_break(void)
182 {
183 	for (;;) {
184 		reachable();
185 		break;
186 		unreachable();		/* expect+0: ... [193] */
187 	}
188 	reachable();
189 }
190 
191 void
192 test_for_if_break(void)
193 {
194 	for (;;) {
195 		reachable();
196 		if (0) {
197 			unreachable();	/* expect+0: ... [193] */
198 			break;
199 			unreachable();	/* expect+0: ... [193] */
200 		}
201 		if (1) {
202 			reachable();
203 			break;
204 			unreachable();	/* expect+0: ... [193] */
205 		}
206 		unreachable();		/* expect+0: ... [193] */
207 	}
208 	reachable();
209 }
210 
211 void
212 test_for_continue(void)
213 {
214 	for (;;) {
215 		reachable();
216 		continue;
217 		unreachable();		/* expect+0: ... [193] */
218 	}
219 	unreachable();			/* expect+0: ... [193] */
220 }
221 
222 void
223 test_for_if_continue(void)
224 {
225 	for (;;) {
226 		reachable();
227 		if (0) {
228 			unreachable();	/* expect+0: ... [193] */
229 			continue;
230 			unreachable();	/* expect+0: ... [193] */
231 		}
232 		if (1) {
233 			reachable();
234 			continue;
235 			unreachable();	/* expect+0: ... [193] */
236 		}
237 		unreachable();		/* expect+0: ... [193] */
238 	}
239 	unreachable();			/* expect+0: ... [193] */
240 }
241 
242 void
243 test_for_return(void)
244 {
245 	for (;;) {
246 		reachable();
247 		return;
248 		unreachable();		/* expect+0: ... [193] */
249 	}
250 	unreachable();			/* expect+0: ... [193] */
251 }
252 
253 void
254 test_for_if_return(void)
255 {
256 	for (;;) {
257 		reachable();
258 		if (0) {
259 			unreachable();	/* expect+0: ... [193] */
260 			return;
261 			unreachable();	/* expect+0: ... [193] */
262 		}
263 		if (1) {
264 			reachable();
265 			return;
266 			unreachable();	/* expect+0: ... [193] */
267 		}
268 		unreachable();		/* expect+0: ... [193] */
269 	}
270 	unreachable();			/* expect+0: ... [193] */
271 }
272 
273 void
274 test_while_true(void)
275 {
276 	while (1)
277 		reachable();
278 	unreachable();			/* expect+0: ... [193] */
279 }
280 
281 void
282 test_while_false(void)
283 {
284 	while (0)
285 		unreachable();		/* expect+0: ... [193] */
286 	reachable();
287 }
288 
289 void
290 test_while_break(void)
291 {
292 	while (1) {
293 		reachable();
294 		break;
295 		unreachable();		/* expect+0: ... [193] */
296 	}
297 	reachable();
298 }
299 
300 void
301 test_while_if_break(void)
302 {
303 	while (1) {
304 		reachable();
305 		if (0) {
306 			unreachable();	/* expect+0: ... [193] */
307 			break;
308 			unreachable();	/* expect+0: ... [193] */
309 		}
310 		if (1) {
311 			reachable();
312 			break;
313 			unreachable();	/* expect+0: ... [193] */
314 		}
315 		unreachable();		/* expect+0: ... [193] */
316 	}
317 	reachable();
318 }
319 
320 void
321 test_while_continue(void)
322 {
323 	while (1) {
324 		reachable();
325 		continue;
326 		unreachable();		/* expect+0: ... [193] */
327 	}
328 	unreachable();			/* expect+0: ... [193] */
329 }
330 
331 void
332 test_while_if_continue(void)
333 {
334 	while (1) {
335 		reachable();
336 		if (0) {
337 			unreachable();	/* expect+0: ... [193] */
338 			continue;
339 			unreachable();	/* expect+0: ... [193] */
340 		}
341 		if (1) {
342 			reachable();
343 			continue;
344 			unreachable();	/* expect+0: ... [193] */
345 		}
346 		unreachable();		/* expect+0: ... [193] */
347 	}
348 	unreachable();			/* expect+0: ... [193] */
349 }
350 
351 void
352 test_while_return(void)
353 {
354 	while (1) {
355 		reachable();
356 		return;
357 		unreachable();		/* expect+0: ... [193] */
358 	}
359 	unreachable();			/* expect+0: ... [193] */
360 }
361 
362 void
363 test_while_if_return(void)
364 {
365 	while (1) {
366 		reachable();
367 		if (0) {
368 			unreachable();	/* expect+0: ... [193] */
369 			return;
370 			unreachable();	/* expect+0: ... [193] */
371 		}
372 		if (1) {
373 			reachable();
374 			return;
375 			unreachable();	/* expect+0: ... [193] */
376 		}
377 		unreachable();		/* expect+0: ... [193] */
378 	}
379 	unreachable();			/* expect+0: ... [193] */
380 }
381 
382 void
383 test_do_while_true(void)
384 {
385 	do {
386 		reachable();
387 	} while (1);
388 	unreachable();			/* expect+0: ... [193] */
389 }
390 
391 void
392 test_do_while_false(void)
393 {
394 	do {
395 		reachable();
396 	} while (0);
397 	reachable();
398 }
399 
400 void
401 test_do_while_break(void)
402 {
403 	do {
404 		reachable();
405 		break;
406 		unreachable();		/* expect+0: ... [193] */
407 	} while (1);
408 	reachable();
409 }
410 
411 void
412 test_do_while_if_break(void)
413 {
414 	do {
415 		reachable();
416 		if (0) {
417 			unreachable();	/* expect+0: ... [193] */
418 			break;
419 			unreachable();	/* expect+0: ... [193] */
420 		}
421 		if (1) {
422 			reachable();
423 			break;
424 			unreachable();	/* expect+0: ... [193] */
425 		}
426 		unreachable();		/* expect+0: ... [193] */
427 	} while (1);
428 	reachable();
429 }
430 
431 void
432 test_do_while_continue(void)
433 {
434 	do {
435 		reachable();
436 		continue;
437 		unreachable();		/* expect+0: ... [193] */
438 	} while (1);
439 	unreachable();			/* expect+0: ... [193] */
440 }
441 
442 void
443 test_do_while_if_continue(void)
444 {
445 	do {
446 		reachable();
447 		if (0) {
448 			unreachable();	/* expect+0: ... [193] */
449 			continue;
450 			unreachable();	/* expect+0: ... [193] */
451 		}
452 		if (1) {
453 			reachable();
454 			continue;
455 			unreachable();	/* expect+0: ... [193] */
456 		}
457 		unreachable();		/* expect+0: ... [193] */
458 	} while (1);
459 	unreachable();			/* expect+0: ... [193] */
460 }
461 
462 void
463 test_do_while_return(void)
464 {
465 	do {
466 		reachable();
467 		return;
468 		unreachable();		/* expect+0: ... [193] */
469 	} while (1);
470 	unreachable();			/* expect+0: ... [193] */
471 }
472 
473 void
474 test_do_while_if_return(void)
475 {
476 	do {
477 		reachable();
478 		if (0) {
479 			unreachable();	/* expect+0: ... [193] */
480 			return;
481 			unreachable();	/* expect+0: ... [193] */
482 		}
483 		if (1) {
484 			reachable();
485 			return;
486 			unreachable();	/* expect+0: ... [193] */
487 		}
488 		unreachable();		/* expect+0: ... [193] */
489 	} while (1);
490 	unreachable();			/* expect+0: ... [193] */
491 }
492 
493 void
494 test_if_nested(void)
495 {
496 	if (0) {
497 		if (1)			/* expect+0: ... [193] */
498 			unreachable();
499 		else
500 			unreachable();	/* expect+0: ... [193] *//* XXX: redundant */
501 
502 		if (0)
503 			unreachable();	/* expect+0: ... [193] *//* XXX: redundant */
504 		else
505 			unreachable();
506 
507 		unreachable();
508 	}
509 	reachable();
510 
511 	if (1) {
512 		if (1)
513 			reachable();
514 		else
515 			unreachable();	/* expect+0: ... [193] */
516 
517 		if (0)
518 			unreachable();	/* expect+0: ... [193] */
519 		else
520 			reachable();
521 
522 		reachable();
523 	}
524 	reachable();
525 }
526 
527 void
528 test_if_maybe(void)
529 {
530 	if (maybe()) {
531 		if (0)
532 			unreachable();	/* expect+0: ... [193] */
533 		else
534 			reachable();
535 		reachable();
536 	}
537 	reachable();
538 
539 	if (0) {
540 		if (maybe())		/* expect+0: ... [193] */
541 			unreachable();
542 		else
543 			unreachable();
544 		unreachable();
545 	}
546 	reachable();
547 
548 	if (1) {
549 		if (maybe())
550 			reachable();
551 		else
552 			reachable();
553 		reachable();
554 	}
555 	reachable();
556 }
557 
558 /*
559  * To compute the reachability graph of this little monster, lint would have
560  * to keep all statements and their relations from the whole function in
561  * memory.  It doesn't do that.  Therefore it does not warn about any
562  * unreachable statements in this function.
563  */
564 void
565 test_goto_numbers_alphabetically(void)
566 {
567 	goto one;
568 eight:
569 	goto nine;
570 five:
571 	return;
572 four:
573 	goto five;
574 nine:
575 	goto ten;
576 one:
577 	goto two;
578 seven:
579 	goto eight;
580 six:
581 	/* expect-1: warning: label 'six' unused in function 'test_goto_numbers_alphabetically' [232] */
582 	goto seven;
583 ten:
584 	return;
585 three:
586 	goto four;
587 two:
588 	goto three;
589 }
590 
591 void
592 test_while_goto(void)
593 {
594 	while (1) {
595 		goto out;
596 		break;		/* lint only warns with the -b option */
597 	}
598 	unreachable();		/* expect+0: ... [193] */
599 out:
600 	reachable();
601 }
602 
603 void
604 test_unreachable_label(void)
605 {
606 	if (0)
607 		goto unreachable;	/* expect+0: ... [193] */
608 	goto reachable;
609 
610 	/* named_label assumes that any label is reachable. */
611 unreachable:
612 	unreachable();
613 reachable:
614 	reachable();
615 }
616 
617 /* TODO: switch */
618 
619 /* TODO: system-dependent constant expression (see tn_system_dependent) */
620 
621 void suppressed(void);
622 
623 void
624 lint_annotation_NOTREACHED(void)
625 {
626 	if (0) {
627 		/* expect+1: warning: statement not reached [193] */
628 		unreachable();
629 	}
630 
631 	if (0) {
632 		/* NOTREACHED */
633 		suppressed();
634 	}
635 
636 	if (0)
637 		/* NOTREACHED */
638 		suppressed();
639 
640 	if (1) {
641 		reachable();
642 	}
643 
644 	if (1) {
645 		/* NOTREACHED */
646 		suppressed();
647 	}
648 
649 	/*
650 	 * Since the condition in the 'if' statement is constant, lint knows
651 	 * that the branch is unconditionally taken.  The annotation comment
652 	 * marks that branch as not reached, which means that any following
653 	 * statement cannot be reached as well.
654 	 */
655 	/* expect+1: warning: statement not reached [193] */
656 	if (1)
657 		/* NOTREACHED */
658 		suppressed();
659 }
660 
661 /*
662  * Since at least 2002 and before cgram.y 1.379 from 2022-01-16, lint did not
663  * detect a double semicolon.  See cgram.y, expression_statement, T_SEMI.
664  */
665 int
666 test_null_statement(void)
667 {
668 	/*
669 	 * The following 2 semicolons are superfluous but lint doesn't warn
670 	 * about them.  Probably it should.  A null statement as part of a
671 	 * block-list has no use.
672 	 */
673 	;;
674 
675 	/*
676 	 * If assertions are disabled with -DNDEBUG and __lint__ is defined,
677 	 * NetBSD's <assert.h> defines assert(x) to nothing, leaving only
678 	 * the trailing semicolon.  If there are several assertions next to
679 	 * each other, without any whitespace in between (very unusual), the
680 	 * GCC preprocessor generates ";;" for them, which makes them
681 	 * indistinguishable from the literal ";;" from the typo above.
682 	 *
683 	 * (echo '#include <assert.h>'; echo 'assert(0);assert(1);') \
684 	 * | gcc -DNDEBUG -E - -D__lint__
685 	 *
686 	 * To actually see the difference, lint would need to look at the
687 	 * code before preprocessing and compare it with the preprocessed
688 	 * code, which would be a lot of work.
689 	 *
690 	 * Apart from the above edge case, detecting extra semicolons would
691 	 * be possible, but lint would have to look at the whitespace between
692 	 * the tokens, and this is something that it doesn't do at all, as of
693 	 * 2022-01-16.
694 	 */
695 
696 	/*
697 	 * A stand-alone null statement, on the other hand, has its purpose.
698 	 * Without it, the 'for' loop would not be complete.  The NetBSD
699 	 * style is to use 'continue;' instead of a simple ';'.
700 	 */
701 	for (int i = 0; i < 10; i++)
702 		;
703 
704 	/* expect+1: warning: statement not reached [193] */
705 	return 0;;
706 }
707 
708 /*
709  * Before func.c 1.149 from 2023-02-21, lint crashed due to a null pointer
710  * dereference.
711  */
712 void
713 invalid_case_expression(void)
714 {
715 	switch (4) {
716 	/* expect+1: error: operand of '~' has invalid type 'double' [108] */
717 	case ~0.0:
718 		;
719 	}
720 }
721