d_c99_bool_strict.c revision 1.29 1 /* $NetBSD: d_c99_bool_strict.c,v 1.29 2021/07/02 18:52:20 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 (since C99), as in lint1/ops.def.
155 *
156 * In strict bool mode, the resulting expression can be compared
157 * against 0 to achieve the same effect (so +0 != 0 or 1 + 0 != 0).
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 *//* expect: 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 *//* expect: 55 */
181 LOGOR_INT = 0 || 1, /* expect: 331 *//* expect: 332 */
182
183 LOGAND_BOOL = __lint_false && __lint_true, /* expect: 161 *//* expect: 55 */
184 LOGAND_INT = 0 && 1, /* expect: 331 *//* expect: 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 *//* expect: 334 */
302
303 /* Implicitly converting int to bool (arg #1). */
304 take_arguments(i, i, i); /* expect: 334 *//* expect: 154 */
305
306 /* Implicitly converting pointer to bool (arg #1). */
307 take_arguments(p, p, p); /* expect: 334 *//* expect: 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(); /* expect: statement not reached */
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 *//* expect: 239 */
420 b = !__lint_true; /* expect: 161 *//* expect: 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 /* see strict_bool_operand_unary_all below for the other unary operators. */
443
444 /*
445 * strict-bool-operand-binary:
446 * Operator left: bool? other? right: bool? other?
447 * . - yes yes yes
448 * -> - yes yes yes
449 * <=, <, >=, > - yes - yes
450 * ==, != yes yes yes yes
451 * & yes yes yes yes
452 * ^ yes yes yes yes
453 * | yes yes yes yes
454 * && yes - yes -
455 * || yes - yes -
456 * ? yes - yes yes
457 * : yes yes yes yes
458 * = yes yes yes yes
459 * &=, ^=, |= yes yes yes yes
460 * , yes yes yes yes
461 * The other binary operators do not accept bool operands.
462 */
463
464 /*
465 * Ensure that bool members can be accessed as usual.
466 */
467 void
468 strict_bool_operand_binary_dot_arrow(void)
469 {
470 struct bool_struct {
471 bool b;
472 };
473
474 /* Initialize and assign using boolean constants. */
475 bool b = __lint_false;
476 b = __lint_true;
477
478 /* Access a struct member using the '.' operator. */
479 struct bool_struct bs = { __lint_true };
480 b = bs.b;
481 bs.b = b;
482 bs.b = 0; /* expect: 107 */
483
484 /* Access a struct member using the '->' operator. */
485 struct bool_struct *bsp = &bs;
486 b = bsp->b;
487 bsp->b = b;
488 bsp->b = 0; /* expect: 107 */
489 }
490
491 int
492 strict_bool_operand_binary(bool b, int i)
493 {
494
495 /* The right-hand sides of these assignments are ok. */
496 b = !b;
497 b = b && b;
498 b = b || b;
499
500 /*
501 * The right-hand sides of these assignments implicitly convert from
502 * scalar to bool.
503 */
504 b = !i; /* expect: 330 */
505 b = i && i; /* expect: 331 *//* expect: 332 */
506 b = i || i; /* expect: 331 *//* expect: 332 */
507
508 b = b && 0; /* expect: 332 */
509 b = 0 && b; /* expect: 331 */
510 b = b || 0; /* expect: 332 */
511 b = 0 || b; /* expect: 331 */
512
513 return i;
514 }
515
516 void
517 strict_bool_operand_unary_all(bool b)
518 {
519 b = !b;
520 b = ~b; /* expect: 335 */
521 ++b; /* expect: 335 */
522 --b; /* expect: 335 */
523 b++; /* expect: 335 */
524 b--; /* expect: 335 */
525 b = +b; /* expect: 335 */
526 b = -b; /* expect: 335 */
527 }
528
529 void
530 strict_bool_operand_binary_all(bool b, unsigned u)
531 {
532 b = b * b; /* expect: 336 *//* expect: 337 */
533 b = b / b; /* expect: 336 *//* expect: 337 */
534 b = b % b; /* expect: 336 *//* expect: 337 */
535 b = b + b; /* expect: 336 *//* expect: 337 */
536 b = b - b; /* expect: 336 *//* expect: 337 */
537 b = b << b; /* expect: 336 *//* expect: 337 */
538 b = b >> b; /* expect: 336 *//* expect: 337 */
539
540 b = b < b; /* expect: 336 *//* expect: 337 */
541 b = b <= b; /* expect: 336 *//* expect: 337 */
542 b = b > b; /* expect: 336 *//* expect: 337 */
543 b = b >= b; /* expect: 336 *//* expect: 337 */
544 b = b == b;
545 b = b != b;
546
547 b = b & b;
548 b = b ^ b;
549 b = b | b;
550 b = b && b;
551 b = b || b;
552 b = b ? b : b;
553
554 b = b;
555 b *= b; /* expect: 336 *//* expect: 337 */
556 b /= b; /* expect: 336 *//* expect: 337 */
557 b %= b; /* expect: 336 *//* expect: 337 */
558 b += b; /* expect: 336 *//* expect: 337 */
559 b -= b; /* expect: 336 *//* expect: 337 */
560 b <<= b; /* expect: 336 *//* expect: 337 */
561 b >>= b; /* expect: 336 *//* expect: 337 */
562 b &= b;
563 b ^= b;
564 b |= b;
565
566 /* Operations with mixed types. */
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; /* expect: 336 */
576 u = u - b; /* expect: 337 */
577 u = b << u; /* expect: 336 */
578 u = u << b; /* expect: 337 */
579 u = b >> u; /* expect: 336 */
580 u = u >> b; /* expect: 337 */
581 u = b ? u : u;
582 u = b ? b : u; /* expect: 107 */
583 u = b ? u : b; /* expect: 107 */
584 }
585
586 bool
587 strict_bool_operand_binary_comma(bool b, int i)
588 {
589 b = (b, !b); /* expect: 129 */
590 i = (i, i + 1); /* expect: 129 */
591 return b;
592 }
593
594 /*
595 * strict-bool-operator-result:
596 * The result type of the operators '!', '<', '<=', '>', '>=',
597 * '==', '!=', '&&', '||' is _Bool instead of int.
598 */
599
600 void
601 strict_bool_operator_result(bool b)
602 {
603 char c = b; /* expect: 107 */
604 int i = b; /* expect: 107 */
605 double d = b; /* expect: 107 */
606 void *p = b; /* expect: 107 */
607
608 /* The right-hand sides of these assignments are all ok. */
609 b = !b;
610 b = i == i;
611 b = i != i;
612 b = i < i;
613 b = i <= i;
614 b = i >= i;
615 b = i > i;
616 b = b && b;
617 b = b || b;
618
619 /*
620 * The right-hand sides of these assignments are not ok, they
621 * implicitly convert from bool to int.
622 */
623 i = !b; /* expect: 107 */
624 i = i == i; /* expect: 107 */
625 i = i != i; /* expect: 107 */
626 i = i < i; /* expect: 107 */
627 i = i <= i; /* expect: 107 */
628 i = i >= i; /* expect: 107 */
629 i = i > i; /* expect: 107 */
630 i = b && b; /* expect: 107 */
631 i = b || b; /* expect: 107 */
632 }
633
634
635 /*
636 * strict-bool-bitwise-and:
637 * Expressions of the form "flags & FLAG" are compatible with _Bool if
638 * the left operand has enum type, the right operand is an integer
639 * constant and the resulting value is used in a context where it is
640 * implicitly and immediately compared to zero.
641 *
642 * Note: Examples for such contexts are controlling expressions or the
643 * operands of the operators '!', '&&', '||'.
644 *
645 * Note: Counterexamples for contexts are assignments to a bool variable.
646 *
647 * Note: These rules ensure that conforming code can be compiled without
648 * change in behavior using old compilers that implement bool as an
649 * ordinary integer type, without the special rule C99 6.3.1.2.
650 */
651
652 enum Flags {
653 FLAG0 = 1 << 0,
654 FLAG1 = 1 << 1,
655 FLAG28 = 1 << 28
656 };
657
658 void
659 strict_bool_bitwise_and_enum(enum Flags flags) /* expect: 231 */
660 {
661 bool b;
662
663 /*
664 * FLAG0 has the value 1 and thus can be stored in a bool variable
665 * without truncation. Nevertheless this special case is not allowed
666 * because it would be too confusing if FLAG0 would work and all the
667 * other flags wouldn't.
668 */
669 b = flags & FLAG0; /* expect: 107 */
670
671 /*
672 * Assuming that FLAG1 is set in flags, a _Bool variable stores this
673 * as 1, as defined by C99 6.3.1.2. A uint8_t variable would store
674 * it as 2, as that is the integer value of FLAG1. Since FLAG1 fits
675 * in a uint8_t, no truncation takes place.
676 */
677 b = flags & FLAG1; /* expect: 107 */
678
679 /*
680 * In a _Bool variable, FLAG28 is stored as 1, since it is unequal to
681 * zero. In a uint8_t, the stored value would be 0 since bit 28 is
682 * out of range for a uint8_t and thus gets truncated.
683 */
684 b = flags & FLAG28; /* expect: 107 */
685 }
686
687 /*
688 * Demonstrate idiomatic code to query flags from an enum bit set.
689 *
690 * In all the controlling expressions in this function, the result of the
691 * operator '&' is compared against 0. This makes this pattern work, no
692 * matter whether the bits are in the low-value range or in the high-value
693 * range (such as FLAG28, which has the value 1073741824, which is more than
694 * what would fit into an unsigned char). Even if an enum could be extended
695 * to larger types than int, this pattern would work.
696 */
697 void
698 query_flag_from_enum_bit_set(enum Flags flags)
699 {
700 if (flags & FLAG0)
701 println("FLAG0 is set");
702
703 if ((flags & FLAG1) != 0)
704 println("FLAG1 is set");
705
706 if ((flags & (FLAG0 | FLAG1)) == (FLAG0 | FLAG1))
707 println("FLAG0 and FLAG1 are both set");
708
709 if (flags & FLAG0 && flags & FLAG1)
710 println("FLAG0 and FLAG1 are both set");
711
712 if ((flags & (FLAG0 | FLAG1)) != 0)
713 println("At least one of FLAG0 and FLAG1 is set");
714
715 if (flags & FLAG28)
716 println("FLAG28 is set");
717 }
718
719
720 void
721 strict_bool_operator_eq_bool_int(void)
722 {
723 (void)(strict_bool_conversion_return_false() == 0); /* expect: 107 */
724 }
725
726 void
727 strict_bool_assign_bit_field_then_compare(void)
728 {
729 struct s {
730 bool flag: 1;
731 };
732
733 struct s s = { __lint_false };
734
735 (void)((s.flag = s.flag) != __lint_false); /* expect: 129 */
736 }
737
738 void
739 bool_as_array_index(bool cond)
740 {
741 static const char *repr[] = { "no", "yes" };
742 /*
743 * The '+' in the error message reveals that lint internally
744 * translates 'arr[ind]' to '*(arr + ind)' in an early stage of
745 * parsing.
746 */
747 println(repr[cond]); /* expect: 337 */
748 println(cond ? "yes" : "no");
749 }
750
751 void
752 do_while_false(void)
753 {
754 do {
755
756 } while (__lint_false);
757 }
758
759 void
760 do_while_true(void)
761 {
762 do {
763
764 } while (__lint_true); /* expect: 161 */
765 }
766
767 void
768 initialization(void)
769 {
770 struct {
771 _Bool b;
772 } var[] = {
773 { __lint_false },
774 { __lint_true },
775 { 0 }, /* expect: 107 */
776 { 1 }, /* expect: 107 */
777 };
778 }
779