d_c99_bool_strict.c revision 1.25 1 /* $NetBSD: d_c99_bool_strict.c,v 1.25 2021/03/21 14:12:46 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 */
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 accept_bool(0); /* expect: 334 */
128 accept_bool(1); /* expect: 334 */
129 accept_bool(2); /* expect: 334 */
130 }
131
132 enum strict_bool_constant_expressions {
133 /* Ok: __lint_false is a boolean constant expression. */
134 FALSE = __lint_false ? 100 : 101, /* expect: 161 */
135
136 /* Ok: __lint_true is a boolean constant expression. */
137 TRUE = __lint_true ? 100 : 101, /* expect: 161 */
138
139 /* Not ok: an integer is not a boolean constant expression. */
140 INT0 = 0 ? 100 : 101, /* expect: 331 */
141
142 /* Not ok: an integer is not a boolean constant expression. */
143 INT1 = 1 ? 100 : 101, /* expect: 331 */
144
145 /* Not ok: 2 is not a boolean constant. */
146 INT2 = 2 ? 100 : 101, /* expect: 331 */
147
148 /* Not ok: compound integer expressions are not bool. */
149 ARITH = (2 - 2) ? 100 : 101, /* expect: 331 */
150
151 /*
152 * Without strict bool mode, these two variants of an expression can
153 * occur when a preprocessor macro is either defined to 1 or left
154 * empty, as in lint1/ops.def.
155 *
156 * TODO: figure out an elegant way to achieve the same effect in
157 * strict bool mode.
158 */
159 BINARY_PLUS = (1 + 0) ? 100 : 101, /* expect: 331 */
160 UNARY_PLUS = (+0) ? 100 : 101, /* expect: 331 */
161
162 /* The main operator '>' has return type bool. */
163 Q1 = (13 > 12) ? 100 : 101, /* expect: 161 */
164
165 /*
166 * The parenthesized expression has type int and thus cannot be
167 * used as the controlling expression in the '?:' operator.
168 */
169 Q2 = (13 > 12 ? 1 : 7) ? 100 : 101, /* expect: 161, 331 */
170
171 BINAND_BOOL = __lint_false & __lint_true, /* expect: 55 */
172 BINAND_INT = 0 & 1,
173
174 BINXOR_BOOL = __lint_false ^ __lint_true, /* expect: 55 */
175 BINXOR_INT = 0 ^ 1,
176
177 BINOR_BOOL = __lint_false | __lint_true, /* expect: 55 */
178 BINOR_INT = 0 | 1,
179
180 LOGOR_BOOL = __lint_false || __lint_true, /* expect: 161, 55 */
181 LOGOR_INT = 0 || 1, /* expect: 331, 332 */
182
183 LOGAND_BOOL = __lint_false && __lint_true, /* expect: 161, 55 */
184 LOGAND_INT = 0 && 1, /* expect: 331, 332 */
185 };
186
187 /*
188 * strict-bool-bit-fields
189 */
190
191 void
192 strict_bool_bit_fields(void)
193 {
194 struct flags {
195 bool bool_flag: 1;
196 unsigned uint_flag: 1;
197 };
198
199 struct flags flags = { __lint_false, 0 };
200 struct flags *flags_ptr = &flags;
201 bool b;
202
203 b = flags.bool_flag;
204 b = flags.uint_flag; /* expect: 107 */
205 flags.bool_flag = b;
206 flags.uint_flag = b; /* expect: 107 */
207
208 b = flags_ptr->bool_flag;
209 b = flags_ptr->uint_flag; /* expect: 107 */
210 flags_ptr->bool_flag = b;
211 flags_ptr->uint_flag = b; /* expect: 107 */
212 }
213
214 void
215 strict_bool_bit_fields_operand_conversion(void)
216 {
217 struct s {
218 bool ordinary;
219 bool bit_field: 1;
220 };
221
222 struct s s = { 0 > 0 };
223
224 s.ordinary = s.ordinary | s.ordinary;
225 s.bit_field = s.bit_field | s.bit_field;
226 }
227
228 /*
229 * strict-bool-conversion
230 */
231
232 bool
233 strict_bool_conversion_return_false(void)
234 {
235 return __lint_false;
236 }
237
238 bool
239 strict_bool_conversion_return_true(void)
240 {
241 return __lint_true;
242 }
243
244 bool
245 strict_bool_conversion_return_bool(bool b)
246 {
247 return b;
248 }
249
250 bool
251 strict_bool_conversion_return_0(void)
252 {
253 return 0; /* expect: 211 */
254 }
255
256 bool
257 strict_bool_conversion_return_1(void)
258 {
259 return 1; /* expect: 211 */
260 }
261
262 bool
263 strict_bool_conversion_return_2(void)
264 {
265 return 2; /* expect: 211 */
266 }
267
268 bool
269 strict_bool_conversion_return_pointer(const void *p) /* expect: 231 */
270 {
271 return p; /* expect: 211 */
272 }
273
274 char
275 strict_bool_conversion_return_false_as_char(void)
276 {
277 return __lint_false; /* expect: 211 */
278 }
279
280 char
281 strict_bool_conversion_return_true_as_char(void)
282 {
283 return __lint_true; /* expect: 211 */
284 }
285
286
287 void
288 strict_bool_conversion_function_argument(void)
289 {
290 accept_bool(__lint_false);
291 accept_bool(__lint_true);
292 }
293
294 void
295 strict_bool_conversion_function_argument_pass(bool b, int i, const char *p)
296 {
297 /* No conversion necessary. */
298 take_arguments(b, i, p);
299
300 /* Implicitly converting bool to other scalar types. */
301 take_arguments(b, b, b); /* expect: 334, 334 */
302
303 /* Implicitly converting int to bool (arg #1). */
304 take_arguments(i, i, i); /* expect: 334, 154 */
305
306 /* Implicitly converting pointer to bool (arg #1). */
307 take_arguments(p, p, p); /* expect: 334, 154 */
308
309 /* Passing bool as vararg. */
310 take_arguments(b, i, p, b, i, p); /* TODO: expect: arg#4 */
311
312 /* Passing a bool constant. */
313 take_arguments(__lint_false, i, p);
314
315 /* Passing a bool constant. */
316 take_arguments(__lint_true, i, p);
317
318 /* Trying to pass integer constants. */
319 take_arguments(0, i, p); /* expect: 334 */
320 take_arguments(1, i, p); /* expect: 334 */
321 take_arguments(2, i, p); /* expect: 334 */
322 }
323
324 void
325 strict_bool_conversion_between_bool_and_int(void)
326 {
327 bool b;
328 int i;
329
330 b = 0; /* expect: 107 */
331 b = __lint_false;
332 b = 1; /* expect: 107 */
333 b = __lint_true;
334
335 i = 0;
336 i = __lint_false; /* expect: 107 */
337 i = 1;
338 i = __lint_true; /* expect: 107 */
339
340 i = b; /* expect: 107 */
341 b = i; /* expect: 107 */
342 }
343
344 void
345 strict_bool_conversion_from_bool_to_scalar(bool b) /* expect: 231 */
346 {
347 int i;
348 unsigned u;
349 double d;
350 void *p;
351
352 i = b; /* expect: 107 */
353 u = b; /* expect: 107 */
354 d = b; /* expect: 107 */
355 p = b; /* expect: 107 */
356 }
357
358 /*
359 * strict-bool-controlling-expression:
360 * Controlling expressions in 'if', 'while', 'for', '?:' must be of
361 * type bool.
362 */
363
364 void
365 strict_bool_controlling_expression(bool b, int i, double d, const void *p)
366 {
367 if (__lint_false) /* expect: 161 */
368 do_nothing();
369
370 if (__lint_true) /* expect: 161 */
371 do_nothing();
372
373 if (b)
374 do_nothing();
375
376 if (0) /* expect: 333 */
377 do_nothing();
378
379 if (1) /* expect: 333 */
380 do_nothing();
381
382 if (2) /* expect: 333 */
383 do_nothing();
384
385 /* Not allowed: There is no implicit conversion from scalar to bool. */
386 if (i) /* expect: 333 */
387 do_nothing();
388 if (i != 0)
389 do_nothing();
390
391 /* Not allowed: There is no implicit conversion from scalar to bool. */
392 if (d) /* expect: 333 */
393 do_nothing();
394 if (d != 0.0)
395 do_nothing();
396
397 /* Not allowed: There is no implicit conversion from scalar to bool. */
398 if (p) /* expect: 333 */
399 do_nothing();
400 if (p != (void *)0)
401 do_nothing();
402 }
403
404 /*
405 * strict-bool-operand-unary:
406 * Operator bool? scalar?
407 * ! yes -
408 * & yes yes
409 * The other unary operators do not accept bool operands.
410 */
411
412 void
413 strict_bool_operand_unary_not(void)
414 {
415 bool b = __lint_false;
416
417 b = !b;
418 b = !!!b;
419 b = !__lint_false; /* expect: 161, 239 */
420 b = !__lint_true; /* expect: 161, 239 */
421
422 int i = 0;
423
424 i = !i; /* expect: 330 */
425 i = !!!i; /* expect: 330 */
426 i = !0; /* expect: 330 */
427 i = !1; /* expect: 330 */
428 }
429
430 void
431 strict_bool_operand_unary_address(void)
432 {
433 bool b = __lint_false;
434
435 /* Taking the address of a bool lvalue. */
436 bool *bp;
437 bp = &b;
438 *bp = b;
439 b = *bp;
440 }
441
442 /*
443 * strict-bool-operand-binary:
444 * Operator left: bool? other? right: bool? other?
445 * . - yes yes yes
446 * -> - yes yes yes
447 * <=, <, >=, > - yes - yes
448 * ==, != yes yes yes yes
449 * & yes yes yes yes
450 * ^ yes yes yes yes
451 * | yes yes yes yes
452 * && yes - yes -
453 * || yes - yes -
454 * ? yes - yes yes
455 * : yes yes yes yes
456 * = yes yes yes yes
457 * &=, ^=, |= yes yes yes yes
458 * , yes yes yes yes
459 * The other binary operators do not accept bool operands.
460 */
461
462 /*
463 * Ensure that bool members can be accessed as usual.
464 */
465 void
466 strict_bool_operand_binary_dot_arrow(void)
467 {
468 struct bool_struct {
469 bool b;
470 };
471
472 /* Initialize and assign using boolean constants. */
473 bool b = __lint_false;
474 b = __lint_true;
475
476 /* Access a struct member using the '.' operator. */
477 struct bool_struct bs = { __lint_true };
478 b = bs.b;
479 bs.b = b;
480 bs.b = 0; /* expect: 107 */
481
482 /* Access a struct member using the '->' operator. */
483 struct bool_struct *bsp = &bs;
484 b = bsp->b;
485 bsp->b = b;
486 bsp->b = 0; /* expect: 107 */
487 }
488
489 int
490 strict_bool_operand_binary(bool b, int i)
491 {
492
493 /* The right-hand sides of these assignments are ok. */
494 b = !b;
495 b = b && b;
496 b = b || b;
497
498 /*
499 * The right-hand sides of these assignments implicitly convert from
500 * scalar to bool.
501 */
502 b = !i; /* expect: 330 */
503 b = i && i; /* expect: 331, 332 */
504 b = i || i; /* expect: 331, 332 */
505
506 b = b && 0; /* expect: 332 */
507 b = 0 && b; /* expect: 331 */
508 b = b || 0; /* expect: 332 */
509 b = 0 || b; /* expect: 331 */
510
511 return i;
512 }
513
514 void
515 strict_bool_operand_binary_all(bool b, unsigned u)
516 {
517 b = !b;
518 b = ~b; /* expect: 335 */
519 ++b; /* expect: 335 */
520 --b; /* expect: 335 */
521 b++; /* expect: 335 */
522 b--; /* expect: 335 */
523 b = +b; /* expect: 335 */
524 b = -b; /* expect: 335 */
525
526 b = b * b; /* expect: 336, 337 */
527 b = b / b; /* expect: 336, 337 */
528 b = b % b; /* expect: 336, 337 */
529 b = b + b; /* expect: 336, 337 */
530 b = b - b; /* expect: 336, 337 */
531 b = b << b; /* expect: 336, 337 */
532 b = b >> b; /* expect: 336, 337 */
533
534 b = b < b; /* expect: 336, 337 */
535 b = b <= b; /* expect: 336, 337 */
536 b = b > b; /* expect: 336, 337 */
537 b = b >= b; /* expect: 336, 337 */
538 b = b == b;
539 b = b != b;
540
541 b = b & b;
542 b = b ^ b;
543 b = b | b;
544 b = b && b;
545 b = b || b;
546 b = b ? b : b;
547
548 b = b;
549 b *= b; /* expect: 336, 337 */
550 b /= b; /* expect: 336, 337 */
551 b %= b; /* expect: 336, 337 */
552 b += b; /* expect: 336, 337 */
553 b -= b; /* expect: 336, 337 */
554 b <<= b; /* expect: 336, 337 */
555 b >>= b; /* expect: 336, 337 */
556 b &= b;
557 b ^= b;
558 b |= b;
559
560 /* Operations with mixed types. */
561 u = b * u; /* expect: 336 */
562 u = u * b; /* expect: 337 */
563 u = b / u; /* expect: 336 */
564 u = u / b; /* expect: 337 */
565 u = b % u; /* expect: 336 */
566 u = u % b; /* expect: 337 */
567 u = b + u; /* expect: 336 */
568 u = u + b; /* expect: 337 */
569 u = b - u; /* expect: 336 */
570 u = u - b; /* expect: 337 */
571 u = b << u; /* expect: 336 */
572 u = u << b; /* expect: 337 */
573 u = b >> u; /* expect: 336 */
574 u = u >> b; /* expect: 337 */
575 u = b ? u : u;
576 u = b ? b : u; /* expect: 107 */
577 u = b ? u : b; /* expect: 107 */
578 }
579
580 bool
581 strict_bool_operand_binary_comma(bool b, int i)
582 {
583 b = (b, !b); /* expect: 129 */
584 i = (i, i + 1); /* expect: 129 */
585 return b;
586 }
587
588 /*
589 * strict-bool-operator-result:
590 * The result type of the operators '!', '<', '<=', '>', '>=',
591 * '==', '!=', '&&', '||' is _Bool instead of int.
592 */
593
594 void
595 strict_bool_operator_result(bool b)
596 {
597 char c = b; /* expect: 107 */
598 int i = b; /* expect: 107 */
599 double d = b; /* expect: 107 */
600 void *p = b; /* expect: 107 */
601
602 /* The right-hand sides of these assignments are all ok. */
603 b = !b;
604 b = i == i;
605 b = i != i;
606 b = i < i;
607 b = i <= i;
608 b = i >= i;
609 b = i > i;
610 b = b && b;
611 b = b || b;
612
613 /*
614 * The right-hand sides of these assignments are not ok, they
615 * implicitly convert from bool to int.
616 */
617 i = !b; /* expect: 107 */
618 i = i == i; /* expect: 107 */
619 i = i != i; /* expect: 107 */
620 i = i < i; /* expect: 107 */
621 i = i <= i; /* expect: 107 */
622 i = i >= i; /* expect: 107 */
623 i = i > i; /* expect: 107 */
624 i = b && b; /* expect: 107 */
625 i = b || b; /* expect: 107 */
626 }
627
628
629 /*
630 * strict-bool-bitwise-and:
631 * Expressions of the form "flags & FLAG" are compatible with _Bool if
632 * the left operand has enum type, the right operand is an integer
633 * constant and the resulting value is used in a context where it is
634 * implicitly and immediately compared to zero.
635 *
636 * Note: Examples for such contexts are controlling expressions or the
637 * operands of the operators '!', '&&', '||'.
638 *
639 * Note: Counterexamples for contexts are assignments to a bool variable.
640 *
641 * Note: These rules ensure that conforming code can be compiled without
642 * change in behavior using old compilers that implement bool as an
643 * ordinary integer type, without the special rule C99 6.3.1.2.
644 */
645
646 enum Flags {
647 FLAG0 = 1 << 0,
648 FLAG1 = 1 << 1,
649 FLAG28 = 1 << 28
650 };
651
652 void
653 strict_bool_bitwise_and_enum(enum Flags flags) /* expect: 231 */
654 {
655 bool b;
656
657 /*
658 * FLAG0 has the value 1 and thus can be stored in a bool variable
659 * without truncation. Nevertheless this special case is not allowed
660 * because it would be too confusing if FLAG0 would work and all the
661 * other flags wouldn't.
662 */
663 b = flags & FLAG0; /* expect: 107 */
664
665 /*
666 * Assuming that FLAG1 is set in flags, a _Bool variable stores this
667 * as 1, as defined by C99 6.3.1.2. A uint8_t variable would store
668 * it as 2, as that is the integer value of FLAG1. Since FLAG1 fits
669 * in a uint8_t, no truncation takes place.
670 */
671 b = flags & FLAG1; /* expect: 107 */
672
673 /*
674 * In a _Bool variable, FLAG28 is stored as 1, since it is unequal to
675 * zero. In a uint8_t, the stored value would be 0 since bit 28 is
676 * out of range for a uint8_t and thus gets truncated.
677 */
678 b = flags & FLAG28; /* expect: 107 */
679 }
680
681 /*
682 * Demonstrate idiomatic code to query flags from an enum bit set.
683 *
684 * In all the controlling expressions in this function, the result of the
685 * operator '&' is compared against 0. This makes this pattern work, no
686 * matter whether the bits are in the low-value range or in the high-value
687 * range (such as FLAG28, which has the value 1073741824, which is more than
688 * what would fit into an unsigned char). Even if an enum could be extended
689 * to larger types than int, this pattern would work.
690 */
691 void
692 query_flag_from_enum_bit_set(enum Flags flags)
693 {
694 if (flags & FLAG0)
695 println("FLAG0 is set");
696
697 if ((flags & FLAG1) != 0)
698 println("FLAG1 is set");
699
700 if ((flags & (FLAG0 | FLAG1)) == (FLAG0 | FLAG1))
701 println("FLAG0 and FLAG1 are both set");
702
703 if (flags & FLAG0 && flags & FLAG1)
704 println("FLAG0 and FLAG1 are both set");
705
706 if ((flags & (FLAG0 | FLAG1)) != 0)
707 println("At least one of FLAG0 and FLAG1 is set");
708
709 if (flags & FLAG28)
710 println("FLAG28 is set");
711 }
712
713
714 void
715 strict_bool_operator_eq_bool_int(void)
716 {
717 (void)(strict_bool_conversion_return_false() == 0); /* expect: 107 */
718 }
719
720 void
721 strict_bool_assign_bit_field_then_compare(void)
722 {
723 struct s {
724 bool flag: 1;
725 };
726
727 struct s s = { __lint_false };
728
729 (void)((s.flag = s.flag) != __lint_false); /* expect: 129 */
730 }
731
732 void
733 bool_as_array_index(bool cond)
734 {
735 static const char *repr[] = { "no", "yes" };
736 /*
737 * The '+' in the error message reveals that lint internally
738 * translates 'arr[ind]' to '*(arr + ind)' in an early stage of
739 * parsing.
740 */
741 println(repr[cond]); /* expect: 337 */
742 println(cond ? "yes" : "no");
743 }
744
745 void
746 do_while_false(void)
747 {
748 do {
749
750 } while (__lint_false);
751 }
752
753 void
754 do_while_true(void)
755 {
756 do {
757
758 } while (__lint_true); /* expect: 161 */
759 }
760
761 void
762 initialization(void)
763 {
764 struct {
765 _Bool b;
766 } var[] = {
767 { __lint_false },
768 { __lint_true },
769 { 0 }, /* expect: 107 */
770 { 1 }, /* expect: 107 */
771 };
772 }
773