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