1 /* $NetBSD: msg_193.c,v 1.22 2024/11/13 04:32:49 rillig Exp $ */ 2 # 3 "msg_193.c" 3 4 // Test for message: '%s' 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 27 extern void reachable(void); 28 extern void unreachable(void); 29 extern _Bool maybe(void); 30 31 32 void 33 test_statement(void) 34 { 35 reachable(); 36 reachable(); 37 } 38 39 void 40 test_compound_statement(void) 41 { 42 reachable(); 43 { 44 reachable(); 45 reachable(); 46 } 47 reachable(); 48 } 49 50 void 51 test_if_statement(void) 52 { 53 if (1) 54 reachable(); 55 reachable(); 56 if (0) 57 unreachable(); /* expect+0: ... [193] */ 58 reachable(); 59 } 60 61 void 62 test_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 87 void 88 test_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 99 void 100 test_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 115 void 116 test_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 140 void 141 test_if_return(void) 142 { 143 if (1) 144 return; 145 unreachable(); /* expect+0: ... [193] */ 146 } 147 148 void 149 test_if_else_return(void) 150 { 151 if (1) 152 reachable(); 153 else 154 return; /* expect+0: ... [193] */ 155 reachable(); 156 } 157 158 void 159 test_for_forever(void) 160 { 161 for (;;) 162 reachable(); 163 unreachable(); /* expect+0: ... [193] */ 164 } 165 166 void 167 test_for_true(void) 168 { 169 for (; 1;) 170 reachable(); 171 unreachable(); /* expect+0: ... [193] */ 172 } 173 174 void 175 test_for_false(void) 176 { 177 for (; 0;) 178 unreachable(); /* expect+0: ... [193] */ 179 reachable(); 180 } 181 182 void 183 test_for_break(void) 184 { 185 for (;;) { 186 reachable(); 187 break; 188 unreachable(); /* expect+0: ... [193] */ 189 } 190 reachable(); 191 } 192 193 void 194 test_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 213 void 214 test_for_continue(void) 215 { 216 for (;;) { 217 reachable(); 218 continue; 219 unreachable(); /* expect+0: ... [193] */ 220 } 221 unreachable(); /* expect+0: ... [193] */ 222 } 223 224 void 225 test_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 244 void 245 test_for_return(void) 246 { 247 for (;;) { 248 reachable(); 249 return; 250 unreachable(); /* expect+0: ... [193] */ 251 } 252 unreachable(); /* expect+0: ... [193] */ 253 } 254 255 void 256 test_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 275 void 276 test_while_true(void) 277 { 278 while (1) 279 reachable(); 280 unreachable(); /* expect+0: ... [193] */ 281 } 282 283 void 284 test_while_false(void) 285 { 286 while (0) 287 unreachable(); /* expect+0: ... [193] */ 288 reachable(); 289 } 290 291 void 292 test_while_break(void) 293 { 294 while (1) { 295 reachable(); 296 break; 297 unreachable(); /* expect+0: ... [193] */ 298 } 299 reachable(); 300 } 301 302 void 303 test_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 322 void 323 test_while_continue(void) 324 { 325 while (1) { 326 reachable(); 327 continue; 328 unreachable(); /* expect+0: ... [193] */ 329 } 330 unreachable(); /* expect+0: ... [193] */ 331 } 332 333 void 334 test_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 353 void 354 test_while_return(void) 355 { 356 while (1) { 357 reachable(); 358 return; 359 unreachable(); /* expect+0: ... [193] */ 360 } 361 unreachable(); /* expect+0: ... [193] */ 362 } 363 364 void 365 test_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 384 void 385 test_do_while_true(void) 386 { 387 do { 388 reachable(); 389 } while (1); 390 unreachable(); /* expect+0: ... [193] */ 391 } 392 393 void 394 test_do_while_false(void) 395 { 396 do { 397 reachable(); 398 } while (0); 399 reachable(); 400 } 401 402 void 403 test_do_while_break(void) 404 { 405 do { 406 reachable(); 407 break; 408 unreachable(); /* expect+0: ... [193] */ 409 } while (1); 410 reachable(); 411 } 412 413 void 414 test_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 433 void 434 test_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 444 void 445 test_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 464 void 465 test_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 475 void 476 test_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 495 void 496 test_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 529 void 530 test_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 */ 566 void 567 test_goto_numbers_alphabetically(void) 568 { 569 goto one; 570 eight: 571 goto nine; 572 five: 573 return; 574 four: 575 goto five; 576 nine: 577 goto ten; 578 one: 579 goto two; 580 seven: 581 goto eight; 582 six: 583 /* expect-1: warning: label 'six' unused in function 'test_goto_numbers_alphabetically' [232] */ 584 goto seven; 585 ten: 586 return; 587 three: 588 goto four; 589 two: 590 goto three; 591 } 592 593 void 594 test_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] */ 601 out: 602 reachable(); 603 } 604 605 void 606 test_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. */ 613 unreachable: 614 unreachable(); 615 reachable: 616 reachable(); 617 } 618 619 /* TODO: switch */ 620 621 /* TODO: system-dependent constant expression (see tn_system_dependent) */ 622 623 void suppressed(void); 624 625 void 626 lint_annotation_NOTREACHED(void) 627 { 628 if (0) { 629 /* expect+1: warning: 'call' 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: 'if' 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 */ 667 int 668 test_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: 'empty' 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 */ 714 void 715 invalid_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