1 /* $NetBSD: d_c99_bool_strict.c,v 1.40 2023/03/28 14:44:34 rillig Exp $ */ 2 # 3 "d_c99_bool_strict.c" 3 4 /* 5 * The option -T treats _Bool as incompatible with all other scalar types. 6 * This is implemented by the following rules: 7 * 8 * strict-bool-typedef: 9 * The type _Bool is compatible with any typedef of _Bool. 10 * 11 * Note: Since <stdbool.h> defines bool as textual alias of _Bool, 12 * having another typedef for bool is unusual. 13 * 14 * strict-bool-constant: 15 * There are 2 bool constants named false and true. 16 * No other constants are compatible with type _Bool. 17 * 18 * Note: Internally these constants are named __lint_false and 19 * __lint_true. 20 * 21 * strict-bool-bit-field: 22 * A struct or union member that is a bit field with underlying type 23 * bool is compatible with plain bool. 24 * 25 * strict-bool-conversion: 26 * There is no implicit conversion between _Bool and any other type. 27 * 28 * strict-bool-controlling-expression: 29 * Controlling expressions in 'if', 'while', 'for', '?:' must be of 30 * type bool. 31 * 32 * strict-bool-operand-unary: 33 * Operator bool? scalar? 34 * ! yes - 35 * & yes yes 36 * The other unary operators do not accept bool operands. 37 * 38 * strict-bool-operand-binary: 39 * Operator left: bool? other? right: bool? other? 40 * . - yes yes yes 41 * -> - yes yes yes 42 * <=, <, >=, > - yes - yes 43 * ==, != yes yes yes yes 44 * & yes yes yes yes 45 * ^ yes yes yes yes 46 * | yes yes yes yes 47 * && yes - yes - 48 * || yes - yes - 49 * ? yes - yes yes 50 * : yes yes yes yes 51 * = yes yes yes yes 52 * &=, ^=, |= yes yes yes yes 53 * , yes yes yes yes 54 * The other binary operators do not accept bool operands. 55 * 56 * strict-bool-operator-result: 57 * The result type of the operators '!', '<', '<=', '>', '>=', 58 * '==', '!=', '&&', '||' is _Bool instead of int. 59 * 60 * strict-bool-bitwise-and: 61 * Expressions of the form "flags & FLAG" are compatible with _Bool if 62 * the left operand has enum type, the right operand is an integer 63 * constant and the resulting value is used in a context where it is 64 * implicitly and immediately compared to zero. 65 * 66 * Note: An efficient implementation technique for a collection of bool 67 * flags is an enum. The enum declaration groups the available 68 * constants, and as of 2020, compilers such as GCC and Clang have basic 69 * support for detecting type mismatches on enums. 70 * 71 * Note: Examples for such contexts are controlling expressions or the 72 * operands of the operators '!', '&&', '||'. 73 * 74 * Note: Counterexamples for contexts are assignments to a bool variable. 75 * 76 * Note: These rules ensure that conforming code can be compiled without 77 * change in behavior using old compilers that implement bool as an 78 * ordinary integer type, without the special rule C99 6.3.1.2. 79 * 80 * Note: There is a crucial difference between a _Bool variable and an 81 * ordinary integer variable. C99 6.3.1.2 defines a conversion from an 82 * arbitrary scalar value to _Bool as equivalent to (value != 0 ? 1 : 0). 83 * This means that even if _Bool is implemented as an 8-bit unsigned 84 * integer, assigning 256 to it would still result in the value 1 being 85 * stored. Storing 256 in an ordinary 8-bit unsigned integer would 86 * result in the value 0 being stored. See the test d_c99_bool.c for 87 * more details. 88 */ 89 90 /* 91 * The header <stdbool.h> defines the macros bool = _Bool, false = 0 and 92 * true = 1. Without further hacks, this would mean that constant expressions 93 * of integer type have to be regarded as possible boolean constants if their 94 * value is either 0 or 1. 95 * 96 * This would not help in migrating old code to use bool consistently. 97 * Therefore lint provides its own <stdbool.h> header that expands false to 98 * __lint_false and true to __lint_true, two predefined constant expressions. 99 */ 100 101 /* lint1-extra-flags: -hT -X 351 */ 102 103 /* 104 * strict-bool-typedef 105 */ 106 107 /* 108 * Using a typedef for bool does not hurt the checks, they all use the 109 * underlying basic type (see tspec_t), which is BOOL. 110 */ 111 typedef _Bool bool; 112 113 extern void accept_bool(bool); 114 extern void println(const char *); 115 extern void take_arguments(bool, int, const char *, ...); 116 extern void do_nothing(void); 117 118 /* 119 * strict-bool-constant 120 */ 121 122 void 123 strict_bool_constant(void) 124 { 125 accept_bool(__lint_false); 126 accept_bool(__lint_true); 127 /* expect+1: error: argument #1 expects '_Bool', gets passed 'int' [334] */ 128 accept_bool(0); 129 /* expect+1: error: argument #1 expects '_Bool', gets passed 'int' [334] */ 130 accept_bool(1); 131 /* expect+1: error: argument #1 expects '_Bool', gets passed 'int' [334] */ 132 accept_bool(2); 133 } 134 135 enum strict_bool_constant_expressions { 136 /* Ok: __lint_false is a boolean constant expression. */ 137 /* expect+1: warning: constant in conditional context [161] */ 138 FALSE = __lint_false ? 100 : 101, 139 140 /* Ok: __lint_true is a boolean constant expression. */ 141 /* expect+1: warning: constant in conditional context [161] */ 142 TRUE = __lint_true ? 100 : 101, 143 144 /* Not ok: an integer is not a boolean constant expression. */ 145 /* expect+1: error: left operand of '?' must be bool, not 'int' [331] */ 146 INT0 = 0 ? 100 : 101, 147 148 /* Not ok: an integer is not a boolean constant expression. */ 149 /* expect+1: error: left operand of '?' must be bool, not 'int' [331] */ 150 INT1 = 1 ? 100 : 101, 151 152 /* Not ok: 2 is not a boolean constant. */ 153 /* expect+1: error: left operand of '?' must be bool, not 'int' [331] */ 154 INT2 = 2 ? 100 : 101, 155 156 /* Not ok: compound integer expressions are not bool. */ 157 /* expect+1: error: left operand of '?' must be bool, not 'int' [331] */ 158 ARITH = (2 - 2) ? 100 : 101, 159 160 /* 161 * Without strict bool mode, these two variants of an expression can 162 * occur when a preprocessor macro is either defined to 1 or left 163 * empty (since C99), as in lint1/ops.def. 164 * 165 * In strict bool mode, the resulting expression can be compared 166 * against 0 to achieve the same effect (so +0 != 0 or 1 + 0 != 0). 167 */ 168 /* expect+1: error: left operand of '?' must be bool, not 'int' [331] */ 169 BINARY_PLUS = (1 + 0) ? 100 : 101, 170 /* expect+1: error: left operand of '?' must be bool, not 'int' [331] */ 171 UNARY_PLUS = (+0) ? 100 : 101, 172 173 /* The main operator '>' has return type bool. */ 174 /* expect+1: warning: constant in conditional context [161] */ 175 Q1 = (13 > 12) ? 100 : 101, 176 177 /* 178 * The parenthesized expression has type int and thus cannot be 179 * used as the controlling expression in the '?:' operator. 180 */ 181 /* expect+2: warning: constant in conditional context [161] */ 182 /* expect+1: error: left operand of '?' must be bool, not 'int' [331] */ 183 Q2 = (13 > 12 ? 1 : 7) ? 100 : 101, 184 185 /* expect+1: error: integral constant expression expected [55] */ 186 BINAND_BOOL = __lint_false & __lint_true, 187 BINAND_INT = 0 & 1, 188 189 /* expect+1: error: integral constant expression expected [55] */ 190 BINXOR_BOOL = __lint_false ^ __lint_true, 191 BINXOR_INT = 0 ^ 1, 192 193 /* expect+1: error: integral constant expression expected [55] */ 194 BINOR_BOOL = __lint_false | __lint_true, 195 BINOR_INT = 0 | 1, 196 197 /* expect+2: warning: constant in conditional context [161] */ 198 /* expect+1: error: integral constant expression expected [55] */ 199 LOGOR_BOOL = __lint_false || __lint_true, 200 /* expect+2: error: left operand of '||' must be bool, not 'int' [331] */ 201 /* expect+1: error: right operand of '||' must be bool, not 'int' [332] */ 202 LOGOR_INT = 0 || 1, 203 204 /* expect+2: warning: constant in conditional context [161] */ 205 /* expect+1: error: integral constant expression expected [55] */ 206 LOGAND_BOOL = __lint_false && __lint_true, 207 /* expect+2: error: left operand of '&&' must be bool, not 'int' [331] */ 208 /* expect+1: error: right operand of '&&' must be bool, not 'int' [332] */ 209 LOGAND_INT = 0 && 1, 210 }; 211 212 /* 213 * strict-bool-bit-fields 214 */ 215 216 void 217 strict_bool_bit_fields(void) 218 { 219 struct flags { 220 bool bool_flag: 1; 221 unsigned uint_flag: 1; 222 }; 223 224 struct flags flags = { __lint_false, 0 }; 225 struct flags *flags_ptr = &flags; 226 bool b; 227 228 b = flags.bool_flag; 229 /* expect+1: error: operands of '=' have incompatible types '_Bool' and 'unsigned int' [107] */ 230 b = flags.uint_flag; 231 flags.bool_flag = b; 232 /* expect+1: error: operands of '=' have incompatible types 'unsigned int' and '_Bool' [107] */ 233 flags.uint_flag = b; 234 235 b = flags_ptr->bool_flag; 236 /* expect+1: error: operands of '=' have incompatible types '_Bool' and 'unsigned int' [107] */ 237 b = flags_ptr->uint_flag; 238 flags_ptr->bool_flag = b; 239 /* expect+1: error: operands of '=' have incompatible types 'unsigned int' and '_Bool' [107] */ 240 flags_ptr->uint_flag = b; 241 } 242 243 void 244 strict_bool_bit_fields_operand_conversion(void) 245 { 246 struct s { 247 bool ordinary; 248 bool bit_field: 1; 249 }; 250 251 struct s s = { 0 > 0 }; 252 253 s.ordinary = s.ordinary | s.ordinary; 254 s.bit_field = s.bit_field | s.bit_field; 255 } 256 257 /* 258 * strict-bool-conversion 259 */ 260 261 bool 262 strict_bool_conversion_return_false(void) 263 { 264 return __lint_false; 265 } 266 267 bool 268 strict_bool_conversion_return_true(void) 269 { 270 return __lint_true; 271 } 272 273 bool 274 strict_bool_conversion_return_bool(bool b) 275 { 276 return b; 277 } 278 279 bool 280 strict_bool_conversion_return_0(void) 281 { 282 /* expect+1: error: function has return type '_Bool' but returns 'int' [211] */ 283 return 0; 284 } 285 286 bool 287 strict_bool_conversion_return_1(void) 288 { 289 /* expect+1: error: function has return type '_Bool' but returns 'int' [211] */ 290 return 1; 291 } 292 293 bool 294 strict_bool_conversion_return_2(void) 295 { 296 /* expect+1: error: function has return type '_Bool' but returns 'int' [211] */ 297 return 2; 298 } 299 300 /* expect+2: warning: argument 'p' unused in function 'strict_bool_conversion_return_pointer' [231] */ 301 bool 302 strict_bool_conversion_return_pointer(const void *p) 303 { 304 /* expect+1: error: function has return type '_Bool' but returns 'pointer' [211] */ 305 return p; 306 } 307 308 char 309 strict_bool_conversion_return_false_as_char(void) 310 { 311 /* expect+1: error: function has return type 'char' but returns '_Bool' [211] */ 312 return __lint_false; 313 } 314 315 char 316 strict_bool_conversion_return_true_as_char(void) 317 { 318 /* expect+1: error: function has return type 'char' but returns '_Bool' [211] */ 319 return __lint_true; 320 } 321 322 323 void 324 strict_bool_conversion_function_argument(void) 325 { 326 accept_bool(__lint_false); 327 accept_bool(__lint_true); 328 } 329 330 void 331 strict_bool_conversion_function_argument_pass(bool b, int i, const char *p) 332 { 333 /* No conversion necessary. */ 334 take_arguments(b, i, p); 335 336 /* Implicitly converting bool to other scalar types. */ 337 /* expect+2: error: argument #2 expects 'int', gets passed '_Bool' [334] */ 338 /* expect+1: error: argument #3 expects 'pointer', gets passed '_Bool' [334] */ 339 take_arguments(b, b, b); 340 341 /* Implicitly converting int to bool (arg #1). */ 342 /* expect+2: error: argument #1 expects '_Bool', gets passed 'int' [334] */ 343 /* expect+1: warning: illegal combination of pointer 'pointer to const char' and integer 'int', arg #3 [154] */ 344 take_arguments(i, i, i); 345 346 /* Implicitly converting pointer to bool (arg #1). */ 347 /* expect+2: error: argument #1 expects '_Bool', gets passed 'pointer' [334] */ 348 /* expect+1: warning: illegal combination of integer 'int' and pointer 'pointer to const char', arg #2 [154] */ 349 take_arguments(p, p, p); 350 351 /* Passing bool as vararg. */ 352 /* TODO: maybe expect+1: arg#4 should not be bool but scalar */ 353 take_arguments(b, i, p, b, i, p); 354 355 /* Passing a bool constant. */ 356 take_arguments(__lint_false, i, p); 357 358 /* Passing a bool constant. */ 359 take_arguments(__lint_true, i, p); 360 361 /* Trying to pass integer constants. */ 362 /* expect+1: error: argument #1 expects '_Bool', gets passed 'int' [334] */ 363 take_arguments(0, i, p); 364 /* expect+1: error: argument #1 expects '_Bool', gets passed 'int' [334] */ 365 take_arguments(1, i, p); 366 /* expect+1: error: argument #1 expects '_Bool', gets passed 'int' [334] */ 367 take_arguments(2, i, p); 368 } 369 370 void 371 strict_bool_conversion_between_bool_and_int(void) 372 { 373 bool b; 374 int i; 375 376 /* expect+1: error: operands of '=' have incompatible types '_Bool' and 'int' [107] */ 377 b = 0; 378 b = __lint_false; 379 /* expect+1: error: operands of '=' have incompatible types '_Bool' and 'int' [107] */ 380 b = 1; 381 b = __lint_true; 382 383 i = 0; 384 /* expect+1: error: operands of '=' have incompatible types 'int' and '_Bool' [107] */ 385 i = __lint_false; 386 i = 1; 387 /* expect+1: error: operands of '=' have incompatible types 'int' and '_Bool' [107] */ 388 i = __lint_true; 389 390 /* expect+1: error: operands of '=' have incompatible types 'int' and '_Bool' [107] */ 391 i = b; 392 /* expect+1: error: operands of '=' have incompatible types '_Bool' and 'int' [107] */ 393 b = i; 394 } 395 396 /* expect+2: warning: argument 'b' unused in function 'strict_bool_conversion_from_bool_to_scalar' [231] */ 397 void 398 strict_bool_conversion_from_bool_to_scalar(bool b) 399 { 400 int i; 401 unsigned u; 402 double d; 403 void *p; 404 405 /* expect+1: error: operands of '=' have incompatible types 'int' and '_Bool' [107] */ 406 i = b; 407 /* expect+1: error: operands of '=' have incompatible types 'unsigned int' and '_Bool' [107] */ 408 u = b; 409 /* expect+1: error: operands of '=' have incompatible types 'double' and '_Bool' [107] */ 410 d = b; 411 /* expect+1: error: operands of '=' have incompatible types 'pointer' and '_Bool' [107] */ 412 p = b; 413 } 414 415 /* 416 * strict-bool-controlling-expression: 417 * Controlling expressions in 'if', 'while', 'for', '?:' must be of 418 * type bool. 419 */ 420 421 void 422 strict_bool_controlling_expression(bool b, int i, double d, const void *p) 423 { 424 /* expect+1: warning: constant in conditional context [161] */ 425 if (__lint_false) 426 do_nothing(); 427 /* expect-1: warning: statement not reached [193] */ 428 429 /* expect+1: warning: constant in conditional context [161] */ 430 if (__lint_true) 431 do_nothing(); 432 433 if (b) 434 do_nothing(); 435 436 /* expect+1: error: controlling expression must be bool, not 'int' [333] */ 437 if (/*CONSTCOND*/0) 438 do_nothing(); 439 /* expect-1: warning: statement not reached [193] */ 440 441 /* expect+1: error: controlling expression must be bool, not 'int' [333] */ 442 if (/*CONSTCOND*/1) 443 do_nothing(); 444 445 /* expect+1: error: controlling expression must be bool, not 'int' [333] */ 446 if (/*CONSTCOND*/2) 447 do_nothing(); 448 449 /* Not allowed: There is no implicit conversion from scalar to bool. */ 450 /* expect+1: error: controlling expression must be bool, not 'int' [333] */ 451 if (i) 452 do_nothing(); 453 if (i != 0) 454 do_nothing(); 455 456 /* Not allowed: There is no implicit conversion from scalar to bool. */ 457 /* expect+1: error: controlling expression must be bool, not 'double' [333] */ 458 if (d) 459 do_nothing(); 460 if (d != 0.0) 461 do_nothing(); 462 463 /* Not allowed: There is no implicit conversion from scalar to bool. */ 464 /* expect+1: error: controlling expression must be bool, not 'pointer' [333] */ 465 if (p) 466 do_nothing(); 467 if (p != (void *)0) 468 do_nothing(); 469 } 470 471 /* 472 * strict-bool-operand-unary: 473 * Operator bool? scalar? 474 * ! yes - 475 * & yes yes 476 * The other unary operators do not accept bool operands. 477 */ 478 479 void 480 strict_bool_operand_unary_not(void) 481 { 482 bool b = __lint_false; 483 484 b = !b; 485 b = !!!b; 486 /* expect+2: warning: constant in conditional context [161] */ 487 /* expect+1: warning: constant argument to '!' [239] */ 488 b = !__lint_false; 489 /* expect+2: warning: constant in conditional context [161] */ 490 /* expect+1: warning: constant argument to '!' [239] */ 491 b = !__lint_true; 492 493 int i = 0; 494 495 /* expect+1: error: operand of '!' must be bool, not 'int' [330] */ 496 i = !i; 497 /* expect+1: error: operand of '!' must be bool, not 'int' [330] */ 498 i = !!!i; 499 /* expect+1: error: operand of '!' must be bool, not 'int' [330] */ 500 i = !0; 501 /* expect+1: error: operand of '!' must be bool, not 'int' [330] */ 502 i = !1; 503 } 504 505 void 506 strict_bool_operand_unary_address(void) 507 { 508 bool b = __lint_false; 509 510 /* Taking the address of a bool lvalue. */ 511 bool *bp; 512 bp = &b; 513 *bp = b; 514 b = *bp; 515 } 516 517 /* see strict_bool_operand_unary_all below for the other unary operators. */ 518 519 /* 520 * strict-bool-operand-binary: 521 * Operator left: bool? other? right: bool? other? 522 * . - yes yes yes 523 * -> - yes yes yes 524 * <=, <, >=, > - yes - yes 525 * ==, != yes yes yes yes 526 * & yes yes yes yes 527 * ^ yes yes yes yes 528 * | yes yes yes yes 529 * && yes - yes - 530 * || yes - yes - 531 * ? yes - yes yes 532 * : yes yes yes yes 533 * = yes yes yes yes 534 * &=, ^=, |= yes yes yes yes 535 * , yes yes yes yes 536 * The other binary operators do not accept bool operands. 537 */ 538 539 /* 540 * Ensure that bool members can be accessed as usual. 541 */ 542 void 543 strict_bool_operand_binary_dot_arrow(void) 544 { 545 struct bool_struct { 546 bool b; 547 }; 548 549 /* Initialize and assign using boolean constants. */ 550 bool b = __lint_false; 551 b = __lint_true; 552 553 /* Access a struct member using the '.' operator. */ 554 struct bool_struct bs = { __lint_true }; 555 b = bs.b; 556 bs.b = b; 557 /* expect+1: error: operands of '=' have incompatible types '_Bool' and 'int' [107] */ 558 bs.b = 0; 559 560 /* Access a struct member using the '->' operator. */ 561 struct bool_struct *bsp = &bs; 562 b = bsp->b; 563 bsp->b = b; 564 /* expect+1: error: operands of '=' have incompatible types '_Bool' and 'int' [107] */ 565 bsp->b = 0; 566 } 567 568 int 569 strict_bool_operand_binary(bool b, int i) 570 { 571 572 /* The right-hand sides of these assignments are ok. */ 573 b = !b; 574 b = b && b; 575 b = b || b; 576 577 /* 578 * The right-hand sides of these assignments implicitly convert from 579 * scalar to bool. 580 */ 581 /* expect+1: error: operand of '!' must be bool, not 'int' [330] */ 582 b = !i; 583 /* expect+2: error: left operand of '&&' must be bool, not 'int' [331] */ 584 /* expect+1: error: right operand of '&&' must be bool, not 'int' [332] */ 585 b = i && i; 586 /* expect+2: error: left operand of '||' must be bool, not 'int' [331] */ 587 /* expect+1: error: right operand of '||' must be bool, not 'int' [332] */ 588 b = i || i; 589 590 /* expect+1: error: right operand of '&&' must be bool, not 'int' [332] */ 591 b = b && 0; 592 /* expect+1: error: left operand of '&&' must be bool, not 'int' [331] */ 593 b = 0 && b; 594 /* expect+1: error: right operand of '||' must be bool, not 'int' [332] */ 595 b = b || 0; 596 /* expect+1: error: left operand of '||' must be bool, not 'int' [331] */ 597 b = 0 || b; 598 599 return i; 600 } 601 602 void 603 strict_bool_operand_unary_all(bool b) 604 { 605 b = !b; 606 /* expect+1: error: operand of '~' must not be bool [335] */ 607 b = ~b; 608 /* expect+1: error: operand of '++x' must not be bool [335] */ 609 ++b; 610 /* expect+1: error: operand of '--x' must not be bool [335] */ 611 --b; 612 /* expect+1: error: operand of 'x++' must not be bool [335] */ 613 b++; 614 /* expect+1: error: operand of 'x--' must not be bool [335] */ 615 b--; 616 /* expect+1: error: operand of '+' must not be bool [335] */ 617 b = +b; 618 /* expect+1: error: operand of '-' must not be bool [335] */ 619 b = -b; 620 } 621 622 void 623 strict_bool_operand_binary_all(bool b, unsigned u) 624 { 625 /* expect+2: error: left operand of '*' must not be bool [336] */ 626 /* expect+1: error: right operand of '*' must not be bool [337] */ 627 b = b * b; 628 /* expect+2: error: left operand of '/' must not be bool [336] */ 629 /* expect+1: error: right operand of '/' must not be bool [337] */ 630 b = b / b; 631 /* expect+2: error: left operand of '%' must not be bool [336] */ 632 /* expect+1: error: right operand of '%' must not be bool [337] */ 633 b = b % b; 634 /* expect+2: error: left operand of '+' must not be bool [336] */ 635 /* expect+1: error: right operand of '+' must not be bool [337] */ 636 b = b + b; 637 /* expect+2: error: left operand of '-' must not be bool [336] */ 638 /* expect+1: error: right operand of '-' must not be bool [337] */ 639 b = b - b; 640 /* expect+2: error: left operand of '<<' must not be bool [336] */ 641 /* expect+1: error: right operand of '<<' must not be bool [337] */ 642 b = b << b; 643 /* expect+2: error: left operand of '>>' must not be bool [336] */ 644 /* expect+1: error: right operand of '>>' must not be bool [337] */ 645 b = b >> b; 646 647 /* expect+2: error: left operand of '<' must not be bool [336] */ 648 /* expect+1: error: right operand of '<' must not be bool [337] */ 649 b = b < b; 650 /* expect+2: error: left operand of '<=' must not be bool [336] */ 651 /* expect+1: error: right operand of '<=' must not be bool [337] */ 652 b = b <= b; 653 /* expect+2: error: left operand of '>' must not be bool [336] */ 654 /* expect+1: error: right operand of '>' must not be bool [337] */ 655 b = b > b; 656 /* expect+2: error: left operand of '>=' must not be bool [336] */ 657 /* expect+1: error: right operand of '>=' must not be bool [337] */ 658 b = b >= b; 659 b = b == b; 660 b = b != b; 661 662 b = b & b; 663 b = b ^ b; 664 b = b | b; 665 b = b && b; 666 b = b || b; 667 b = b ? b : b; 668 669 b = b; 670 /* expect+2: error: left operand of '*=' must not be bool [336] */ 671 /* expect+1: error: right operand of '*=' must not be bool [337] */ 672 b *= b; 673 /* expect+2: error: left operand of '/=' must not be bool [336] */ 674 /* expect+1: error: right operand of '/=' must not be bool [337] */ 675 b /= b; 676 /* expect+2: error: left operand of '%=' must not be bool [336] */ 677 /* expect+1: error: right operand of '%=' must not be bool [337] */ 678 b %= b; 679 /* expect+2: error: left operand of '+=' must not be bool [336] */ 680 /* expect+1: error: right operand of '+=' must not be bool [337] */ 681 b += b; 682 /* expect+2: error: left operand of '-=' must not be bool [336] */ 683 /* expect+1: error: right operand of '-=' must not be bool [337] */ 684 b -= b; 685 /* expect+2: error: left operand of '<<=' must not be bool [336] */ 686 /* expect+1: error: right operand of '<<=' must not be bool [337] */ 687 b <<= b; 688 /* expect+2: error: left operand of '>>=' must not be bool [336] */ 689 /* expect+1: error: right operand of '>>=' must not be bool [337] */ 690 b >>= b; 691 b &= b; 692 b ^= b; 693 b |= b; 694 695 /* Operations with mixed types. */ 696 /* expect+1: error: left operand of '*' must not be bool [336] */ 697 u = b * u; 698 /* expect+1: error: right operand of '*' must not be bool [337] */ 699 u = u * b; 700 /* expect+1: error: left operand of '/' must not be bool [336] */ 701 u = b / u; 702 /* expect+1: error: right operand of '/' must not be bool [337] */ 703 u = u / b; 704 /* expect+1: error: left operand of '%' must not be bool [336] */ 705 u = b % u; 706 /* expect+1: error: right operand of '%' must not be bool [337] */ 707 u = u % b; 708 /* expect+1: error: left operand of '+' must not be bool [336] */ 709 u = b + u; 710 /* expect+1: error: right operand of '+' must not be bool [337] */ 711 u = u + b; 712 /* expect+1: error: left operand of '-' must not be bool [336] */ 713 u = b - u; 714 /* expect+1: error: right operand of '-' must not be bool [337] */ 715 u = u - b; 716 /* expect+1: error: left operand of '<<' must not be bool [336] */ 717 u = b << u; 718 /* expect+1: error: right operand of '<<' must not be bool [337] */ 719 u = u << b; 720 /* expect+1: error: left operand of '>>' must not be bool [336] */ 721 u = b >> u; 722 /* expect+1: error: right operand of '>>' must not be bool [337] */ 723 u = u >> b; 724 u = b ? u : u; 725 /* expect+1: error: operands of ':' have incompatible types '_Bool' and 'unsigned int' [107] */ 726 u = b ? b : u; 727 /* expect+1: error: operands of ':' have incompatible types 'unsigned int' and '_Bool' [107] */ 728 u = b ? u : b; 729 } 730 731 bool 732 strict_bool_operand_binary_comma(bool b, int i) 733 { 734 /* expect+1: warning: expression has null effect [129] */ 735 b = (b, !b); 736 /* expect+1: warning: expression has null effect [129] */ 737 i = (i, i + 1); 738 return b; 739 } 740 741 /* 742 * strict-bool-operator-result: 743 * The result type of the operators '!', '<', '<=', '>', '>=', 744 * '==', '!=', '&&', '||' is _Bool instead of int. 745 */ 746 747 void 748 strict_bool_operator_result(bool b) 749 { 750 /* expect+1: error: operands of 'init' have incompatible types 'char' and '_Bool' [107] */ 751 char c = b; 752 /* expect+1: error: operands of 'init' have incompatible types 'int' and '_Bool' [107] */ 753 int i = b; 754 /* expect+1: error: operands of 'init' have incompatible types 'double' and '_Bool' [107] */ 755 double d = b; 756 /* expect+1: error: operands of 'init' have incompatible types 'pointer' and '_Bool' [107] */ 757 void *p = b; 758 759 /* The right-hand sides of these assignments are all ok. */ 760 b = !b; 761 b = i == i; 762 b = i != i; 763 b = i < i; 764 b = i <= i; 765 b = i >= i; 766 b = i > i; 767 b = b && b; 768 b = b || b; 769 770 /* 771 * The right-hand sides of these assignments are not ok, they 772 * implicitly convert from bool to int. 773 */ 774 /* expect+1: error: operands of '=' have incompatible types 'int' and '_Bool' [107] */ 775 i = !b; 776 /* expect+1: error: operands of '=' have incompatible types 'int' and '_Bool' [107] */ 777 i = i == i; 778 /* expect+1: error: operands of '=' have incompatible types 'int' and '_Bool' [107] */ 779 i = i != i; 780 /* expect+1: error: operands of '=' have incompatible types 'int' and '_Bool' [107] */ 781 i = i < i; 782 /* expect+1: error: operands of '=' have incompatible types 'int' and '_Bool' [107] */ 783 i = i <= i; 784 /* expect+1: error: operands of '=' have incompatible types 'int' and '_Bool' [107] */ 785 i = i >= i; 786 /* expect+1: error: operands of '=' have incompatible types 'int' and '_Bool' [107] */ 787 i = i > i; 788 /* expect+1: error: operands of '=' have incompatible types 'int' and '_Bool' [107] */ 789 i = b && b; 790 /* expect+1: error: operands of '=' have incompatible types 'int' and '_Bool' [107] */ 791 i = b || b; 792 } 793 794 795 /* 796 * strict-bool-bitwise-and: 797 * Expressions of the form "flags & FLAG" are compatible with _Bool if 798 * the left operand has enum type, the right operand is an integer 799 * constant and the resulting value is used in a context where it is 800 * implicitly and immediately compared to zero. 801 * 802 * Note: Examples for such contexts are controlling expressions or the 803 * operands of the operators '!', '&&', '||'. 804 * 805 * Note: Counterexamples for contexts are assignments to a bool variable. 806 * 807 * Note: These rules ensure that conforming code can be compiled without 808 * change in behavior using old compilers that implement bool as an 809 * ordinary integer type, without the special rule C99 6.3.1.2. 810 */ 811 812 enum Flags { 813 FLAG0 = 1 << 0, 814 FLAG1 = 1 << 1, 815 FLAG28 = 1 << 28 816 }; 817 818 /* expect+2: warning: argument 'flags' unused in function 'strict_bool_bitwise_and_enum' [231] */ 819 void 820 strict_bool_bitwise_and_enum(enum Flags flags) 821 { 822 bool b; 823 824 /* 825 * FLAG0 has the value 1 and thus can be stored in a bool variable 826 * without truncation. Nevertheless this special case is not allowed 827 * because it would be too confusing if FLAG0 would work and all the 828 * other flags wouldn't. 829 */ 830 /* expect+1: error: operands of '=' have incompatible types '_Bool' and 'int' [107] */ 831 b = flags & FLAG0; 832 833 /* 834 * Assuming that FLAG1 is set in flags, a _Bool variable stores this 835 * as 1, as defined by C99 6.3.1.2. A uint8_t variable would store 836 * it as 2, as that is the integer value of FLAG1. Since FLAG1 fits 837 * in a uint8_t, no truncation takes place. 838 */ 839 /* expect+1: error: operands of '=' have incompatible types '_Bool' and 'int' [107] */ 840 b = flags & FLAG1; 841 842 /* 843 * In a _Bool variable, FLAG28 is stored as 1, since it is unequal to 844 * zero. In a uint8_t, the stored value would be 0 since bit 28 is 845 * out of range for a uint8_t and thus gets truncated. 846 */ 847 /* expect+1: error: operands of '=' have incompatible types '_Bool' and 'int' [107] */ 848 b = flags & FLAG28; 849 } 850 851 /* 852 * Demonstrate idiomatic code to query flags from an enum bit set. 853 * 854 * In all the controlling expressions in this function, the result of the 855 * operator '&' is compared against 0. This makes this pattern work, no 856 * matter whether the bits are in the low-value range or in the high-value 857 * range (such as FLAG28, which has the value 1073741824, which is more than 858 * what would fit into an unsigned char). Even if an enum could be extended 859 * to larger types than int, this pattern would work. 860 */ 861 void 862 query_flag_from_enum_bit_set(enum Flags flags) 863 { 864 if (flags & FLAG0) 865 println("FLAG0 is set"); 866 867 if ((flags & FLAG1) != 0) 868 println("FLAG1 is set"); 869 870 if ((flags & (FLAG0 | FLAG1)) == (FLAG0 | FLAG1)) 871 println("FLAG0 and FLAG1 are both set"); 872 873 if (flags & FLAG0 && flags & FLAG1) 874 println("FLAG0 and FLAG1 are both set"); 875 876 if ((flags & (FLAG0 | FLAG1)) != 0) 877 println("At least one of FLAG0 and FLAG1 is set"); 878 879 if (flags & FLAG28) 880 println("FLAG28 is set"); 881 } 882 883 884 void 885 strict_bool_operator_eq_bool_int(void) 886 { 887 /* expect+1: error: operands of '==' have incompatible types '_Bool' and 'int' [107] */ 888 (void)(strict_bool_conversion_return_false() == 0); 889 } 890 891 void 892 strict_bool_assign_bit_field_then_compare(void) 893 { 894 struct s { 895 bool flag: 1; 896 }; 897 898 struct s s = { __lint_false }; 899 900 /* expect+1: warning: expression has null effect [129] */ 901 (void)((s.flag = s.flag) != __lint_false); 902 } 903 904 void 905 bool_as_array_index(bool cond) 906 { 907 static const char *repr[] = { "no", "yes" }; 908 /* 909 * The '+' in the error message reveals that lint internally 910 * translates 'arr[ind]' to '*(arr + ind)' in an early stage of 911 * parsing. 912 */ 913 /* expect+1: error: right operand of '+' must not be bool [337] */ 914 println(repr[cond]); 915 println(cond ? "yes" : "no"); 916 } 917 918 void 919 do_while_false(void) 920 { 921 do { 922 923 } while (__lint_false); 924 } 925 926 void 927 do_while_true(void) 928 { 929 do { 930 931 } while (__lint_true); 932 /* expect-1: warning: constant in conditional context [161] */ 933 } 934 935 void 936 initialization(void) 937 { 938 struct { 939 _Bool b; 940 } var[] = { 941 { __lint_false }, 942 { __lint_true }, 943 /* expect+1: error: operands of 'init' have incompatible types '_Bool' and 'int' [107] */ 944 { 0 }, 945 /* expect+1: error: operands of 'init' have incompatible types '_Bool' and 'int' [107] */ 946 { 1 }, 947 }; 948 } 949 950 /* 951 * For expressions that originate from a system header, the strict type rules 952 * are relaxed a bit, to allow for expressions like 'flags & FLAG', even 953 * though they are not strictly boolean. 954 * 955 * This shouldn't apply to function call expressions though since one of the 956 * goals of strict bool mode is to normalize all expressions calling 'strcmp' 957 * to be of the form 'strcmp(a, b) == 0' instead of '!strcmp(a, b)'. 958 */ 959 # 1 "stdio.h" 1 3 4 960 typedef struct stdio_file { 961 int fd; 962 } FILE; 963 int ferror(FILE *); 964 FILE stdio_files[3]; 965 FILE *stdio_stdout; 966 # 967 "d_c99_bool_strict.c" 2 967 # 1 "string.h" 1 3 4 968 int strcmp(const char *, const char *); 969 # 970 "d_c99_bool_strict.c" 2 970 971 void 972 controlling_expression(FILE *f, const char *a, const char *b) 973 { 974 /* expect+1: error: controlling expression must be bool, not 'int' [333] */ 975 if (ferror(f)) 976 return; 977 /* expect+1: error: controlling expression must be bool, not 'int' [333] */ 978 if (strcmp(a, b)) 979 return; 980 /* expect+1: error: operand of '!' must be bool, not 'int' [330] */ 981 if (!ferror(f)) 982 return; 983 /* expect+1: error: operand of '!' must be bool, not 'int' [330] */ 984 if (!strcmp(a, b)) 985 return; 986 987 /* 988 * Before tree.c 1.395 from 2021-11-16, the expression below didn't 989 * produce a warning since the expression 'stdio_files' came from a 990 * system header (via a macro), and this property was passed up to 991 * the expression 'ferror(stdio_files[1])'. 992 * 993 * That was wrong though since the type of a function call expression 994 * only depends on the function itself but not its arguments types. 995 * The old rule had allowed a raw condition 'strcmp(a, b)' without 996 * the comparison '!= 0', as long as one of its arguments came from a 997 * system header. 998 * 999 * Seen in bin/echo/echo.c, function main, call to ferror. 1000 */ 1001 /* expect+5: error: controlling expression must be bool, not 'int' [333] */ 1002 if (ferror( 1003 # 1004 "d_c99_bool_strict.c" 3 4 1004 &stdio_files[1] 1005 # 1006 "d_c99_bool_strict.c" 1006 )) 1007 return; 1008 1009 /* 1010 * Before cgram.y 1.369 from 2021-11-16, at the end of parsing the 1011 * name 'stdio_stdout', the parser already looked ahead to the next 1012 * token, to see whether it was the '(' of a function call. 1013 * 1014 * At that point, the parser was no longer in a system header, 1015 * therefore 'stdio_stdout' had tn_sys == false, and this information 1016 * was pushed down to the whole function call expression (which was 1017 * another bug that got fixed in tree.c 1.395 from 2021-11-16). 1018 */ 1019 /* expect+5: error: controlling expression must be bool, not 'int' [333] */ 1020 if (ferror( 1021 # 1022 "d_c99_bool_strict.c" 3 4 1022 stdio_stdout 1023 # 1024 "d_c99_bool_strict.c" 1024 )) 1025 return; 1026 1027 /* 1028 * In this variant of the pattern, there is a token ')' after the 1029 * name 'stdio_stdout', which even before tree.c 1.395 from 1030 * 2021-11-16 had the effect that at the end of parsing the name, the 1031 * parser was still in the system header, thus setting tn_sys (or 1032 * rather tn_relaxed at that time) to true. 1033 */ 1034 /* expect+5: error: controlling expression must be bool, not 'int' [333] */ 1035 if (ferror( 1036 # 1037 "d_c99_bool_strict.c" 3 4 1037 (stdio_stdout) 1038 # 1039 "d_c99_bool_strict.c" 1039 )) 1040 return; 1041 1042 /* 1043 * Before cgram.y 1.369 from 2021-11-16, the comment following 1044 * 'stdio_stdout' did not prevent the search for '('. At the point 1045 * where build_name called expr_alloc_tnode, the parser was already 1046 * in the main file again, thus treating 'stdio_stdout' as not coming 1047 * from a system header. 1048 * 1049 * This has been fixed in tree.c 1.395 from 2021-11-16. Before that, 1050 * an expression had come from a system header if its operands came 1051 * from a system header, but that was only close to the truth. In a 1052 * case where both operands come from a system header but the 1053 * operator comes from the main translation unit, the main 1054 * translation unit still has control over the whole expression. So 1055 * the correct approach is to focus on the operator, not the 1056 * operands. There are a few corner cases where the operator is 1057 * invisible (for implicit conversions) or synthetic (for translating 1058 * 'arr[index]' to '*(arr + index)', but these are handled as well. 1059 */ 1060 /* expect+5: error: controlling expression must be bool, not 'int' [333] */ 1061 if (ferror( 1062 # 1063 "d_c99_bool_strict.c" 3 4 1063 stdio_stdout /* comment */ 1064 # 1065 "d_c99_bool_strict.c" 1065 )) 1066 return; 1067 } 1068