d_c99_bool_strict.c revision 1.13 1 /* $NetBSD: d_c99_bool_strict.c,v 1.13 2021/01/17 11:32:06 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 no
35 * The other binary operators do not accept bool operands.
36 *
37 * strict-bool-operand-binary:
38 * Operator left: bool? other? right: bool? other?
39 * . - yes yes yes
40 * -> - yes yes yes
41 * <=, <, >=, > - yes - yes
42 * ==, != yes yes yes yes
43 * & yes yes yes yes
44 * ^ yes yes yes yes
45 * | yes yes yes yes
46 * && yes - yes -
47 * || yes - yes -
48 * ? yes - yes yes
49 * : yes yes yes yes
50 * = yes yes yes yes
51 * &=, ^=, |= yes yes yes yes
52 * , yes yes yes yes
53 * The other binary operators do not accept bool operands.
54 *
55 * strict-bool-operator-result:
56 * The result type of the operators '!', '<', '<=', '>', '>=',
57 * '==', '!=', '&&', '||' is _Bool instead of int.
58 *
59 * strict-bool-bitwise-and:
60 * Expressions of the form "flags & FLAG" are compatible with _Bool if
61 * the left operand has enum type, the right operand is an integer
62 * constant and the resulting value is used in a context where it is
63 * implicitly and immediately compared to zero.
64 *
65 * Note: An efficient implementation technique for a collection of bool
66 * flags is an enum. The enum declaration groups the available
67 * constants, and as of 2020, compilers such as GCC and Clang have basic
68 * support for detecting type mismatches on enums.
69 *
70 * Note: Examples for such contexts are controlling expressions or the
71 * operands of the operators '!', '&&', '||'.
72 *
73 * Note: Counterexamples for contexts are assignments to a bool variable.
74 *
75 * Note: These rules ensure that conforming code can be compiled without
76 * change in behavior using old compilers that implement bool as an
77 * ordinary integer type, without the special rule C99 6.3.1.2.
78 *
79 * Note: There is a crucial difference between a _Bool variable and an
80 * ordinary integer variable. C99 6.3.1.2 defines a conversion from an
81 * arbitrary scalar value to _Bool as equivalent to (value != 0 ? 1 : 0).
82 * This means that even if _Bool is implemented as an 8-bit unsigned
83 * integer, assigning 256 to it would still result in the value 1 being
84 * stored. Storing 256 in an ordinary 8-bit unsigned integer would
85 * result in the value 0 being stored. See the test d_c99_bool.c for
86 * more details.
87 */
88
89 /*
90 * The header <stdbool.h> defines the macros bool = _Bool, false = 0 and
91 * true = 1. Without further hacks, this would mean that constant expressions
92 * of integer type have to be regarded as possible boolean constants if their
93 * value is either 0 or 1.
94 *
95 * This would not help in migrating old code to use bool consistently.
96 * Therefore lint provides its own <stdbool.h> header that expands false to
97 * __lint_false and true to __lint_true, two predefined constant expressions.
98 */
99
100 /* lint1-extra-flags: -T */
101
102 /*
103 * strict-bool-typedef
104 */
105
106 /*
107 * Using a typedef for bool does not hurt the checks, they all use the
108 * underlying basic type (see tspec_t), which is BOOL.
109 */
110 typedef _Bool bool;
111
112 extern void accept_bool(bool);
113 extern void println(const char *);
114 extern void take_arguments(bool, int, const char *, ...);
115 extern void do_nothing(void);
116
117 /*
118 * strict-bool-constant
119 */
120
121 void
122 strict_bool_constant(void)
123 {
124 accept_bool(__lint_false);
125 accept_bool(__lint_true);
126 accept_bool(0); /* expect: 334 */
127 accept_bool(1); /* expect: 334 */
128 accept_bool(2); /* expect: 334 */
129 }
130
131 enum strict_bool_constant_expressions {
132 /* Ok: __lint_false is a boolean constant expression. */
133 FALSE = __lint_false ? 100 : 101,
134
135 /* Ok: __lint_true is a boolean constant expression. */
136 TRUE = __lint_true ? 100 : 101,
137
138 /* Not ok: an integer is not a boolean constant expression. */
139 INT0 = 0 ? 100 : 101, /* expect: 331 */
140
141 /* Not ok: an integer is not a boolean constant expression. */
142 INT1 = 1 ? 100 : 101, /* expect: 331 */
143
144 /* Not ok: 2 is not a boolean constant. */
145 INT2 = 2 ? 100 : 101, /* expect: 331 */
146
147 /* Not ok: compound integer expressions are not bool. */
148 ARITH = (2 - 2) ? 100 : 101, /* expect: 331 */
149
150 /*
151 * Without strict bool mode, these two variants of an expression can
152 * occur when a preprocessor macro is either defined to 1 or left
153 * empty, as in lint1/ops.def.
154 *
155 * TODO: figure out an elegant way to achieve the same effect in
156 * strict bool mode.
157 */
158 BINARY_PLUS = (1 + 0) ? 100 : 101, /* expect: 331 */
159 UNARY_PLUS = (+0) ? 100 : 101, /* expect: 331 */
160
161 /* The main operator '>' has return type bool. */
162 Q1 = (13 > 12) ? 100 : 101,
163
164 /*
165 * The parenthesized expression has type int and thus cannot be
166 * used as the controlling expression in the '?:' operator.
167 */
168 Q2 = (13 > 12 ? 1 : 7) ? 100 : 101, /* expect: 331 */
169
170 BINAND_BOOL = __lint_false & __lint_true,
171 BINAND_INT = 0 & 1,
172
173 BINXOR_BOOL = __lint_false ^ __lint_true,
174 BINXOR_INT = 0 ^ 1,
175
176 BINOR_BOOL = __lint_false | __lint_true,
177 BINOR_INT = 0 | 1,
178
179 LOGOR_BOOL = __lint_false || __lint_true,
180 LOGOR_INT = 0 || 1, /* expect: 331, 332 */
181
182 LOGAND_BOOL = __lint_false && __lint_true,
183 LOGAND_INT = 0 && 1, /* expect: 331, 332 */
184 };
185
186 /*
187 * strict-bool-bit-fields
188 */
189
190 void
191 strict_bool_bit_fields(void)
192 {
193 struct flags {
194 bool bool_flag: 1;
195 unsigned uint_flag: 1;
196 };
197
198 struct flags flags = { __lint_false, 0 };
199 struct flags *flags_ptr = &flags;
200 bool b;
201
202 b = flags.bool_flag;
203 b = flags.uint_flag; /* expect: 107 */
204 flags.bool_flag = b;
205 flags.uint_flag = b; /* expect: 107 */
206
207 b = flags_ptr->bool_flag;
208 b = flags_ptr->uint_flag; /* expect: 107 */
209 flags_ptr->bool_flag = b;
210 flags_ptr->uint_flag = b; /* expect: 107 */
211 }
212
213 void
214 strict_bool_bit_fields_operand_conversion(void)
215 {
216 struct s {
217 bool ordinary;
218 bool bit_field: 1;
219 };
220
221 struct s s = { 0 };
222
223 s.ordinary = s.ordinary | s.ordinary;
224 s.bit_field = s.bit_field | s.bit_field; /* FIXME *//* expect: 107 */
225 }
226
227 /*
228 * strict-bool-conversion
229 */
230
231 bool
232 strict_bool_conversion_return_false(void)
233 {
234 return __lint_false;
235 }
236
237 bool
238 strict_bool_conversion_return_true(void)
239 {
240 return __lint_true;
241 }
242
243 bool
244 strict_bool_conversion_return_bool(bool b)
245 {
246 return b;
247 }
248
249 bool
250 strict_bool_conversion_return_0(void)
251 {
252 return 0; /* expect: 211 */
253 }
254
255 bool
256 strict_bool_conversion_return_1(void)
257 {
258 return 1; /* expect: 211 */
259 }
260
261 bool
262 strict_bool_conversion_return_2(void)
263 {
264 return 2; /* expect: 211 */
265 }
266
267 bool
268 strict_bool_conversion_return_pointer(const void *p) /* expect: 231 */
269 {
270 return p; /* expect: 211 */
271 }
272
273 char
274 strict_bool_conversion_return_false_as_char(void)
275 {
276 return __lint_false; /* expect: 211 */
277 }
278
279 char
280 strict_bool_conversion_return_true_as_char(void)
281 {
282 return __lint_true; /* expect: 211 */
283 }
284
285
286 void
287 strict_bool_conversion_function_argument(void)
288 {
289 accept_bool(__lint_false);
290 accept_bool(__lint_true);
291 }
292
293 void
294 strict_bool_conversion_function_argument_pass(bool b, int i, const char *p)
295 {
296 /* No conversion necessary. */
297 take_arguments(b, i, p);
298
299 /* Implicitly converting bool to other scalar types. */
300 take_arguments(b, b, b); /* expect: 334, 334 */
301
302 /* Implicitly converting int to bool (arg #1). */
303 take_arguments(i, i, i); /* expect: 334, 154 */
304
305 /* Implicitly converting pointer to bool (arg #1). */
306 take_arguments(p, p, p); /* expect: 334, 154 */
307
308 /* Passing bool as vararg. */
309 take_arguments(b, i, p, b, i, p); /* expect: arg#4 */ // TODO
310
311 /* Passing a bool constant. */
312 take_arguments(__lint_false, i, p);
313
314 /* Passing a bool constant. */
315 take_arguments(__lint_true, i, p);
316
317 /* Trying to pass integer constants. */
318 take_arguments(0, i, p); /* expect: 334 */
319 take_arguments(1, i, p); /* expect: 334 */
320 take_arguments(2, i, p); /* expect: 334 */
321 }
322
323 void
324 strict_bool_conversion_between_bool_and_int(void)
325 {
326 bool b;
327 int i;
328
329 b = 0; /* expect: 107 */
330 b = __lint_false;
331 b = 1; /* expect: 107 */
332 b = __lint_true;
333
334 i = 0;
335 i = __lint_false; /* expect: 107 */
336 i = 1;
337 i = __lint_true; /* expect: 107 */
338
339 i = b; /* expect: 107 */
340 b = i; /* expect: 107 */
341 }
342
343 void
344 strict_bool_conversion_from_bool_to_scalar(bool b) /* expect: 231 */
345 {
346 int i;
347 unsigned u;
348 double d;
349 void *p;
350
351 i = b; /* expect: 107 */
352 u = b; /* expect: 107 */
353 d = b; /* expect: 107 */
354 p = b; /* expect: 107 */
355 }
356
357 /*
358 * strict-bool-controlling-expression:
359 * Controlling expressions in 'if', 'while', 'for', '?:' must be of
360 * type bool.
361 */
362
363 void
364 strict_bool_controlling_expression(bool b, int i, double d, const void *p)
365 {
366 if (__lint_false)
367 do_nothing();
368
369 if (__lint_true)
370 do_nothing();
371
372 if (b)
373 do_nothing();
374
375 if (0) /* expect: 333 */
376 do_nothing();
377
378 if (1) /* expect: 333 */
379 do_nothing();
380
381 if (2) /* expect: 333 */
382 do_nothing();
383
384 /* Not allowed: There is no implicit conversion from scalar to bool. */
385 if (i) /* expect: 333 */
386 do_nothing();
387 if (i != 0)
388 do_nothing();
389
390 /* Not allowed: There is no implicit conversion from scalar to bool. */
391 if (d) /* expect: 333 */
392 do_nothing();
393 if (d != 0.0)
394 do_nothing();
395
396 /* Not allowed: There is no implicit conversion from scalar to bool. */
397 if (p) /* expect: 333 */
398 do_nothing();
399 if (p != (void *)0)
400 do_nothing();
401 }
402
403 /*
404 * strict-bool-operand-unary:
405 * Operator bool? scalar?
406 * ! yes -
407 * & yes yes
408 * The other binary operators do not accept bool operands.
409 */
410
411 void
412 strict_bool_operand_unary_not(void)
413 {
414 bool b = __lint_false;
415
416 b = !b;
417 b = !!!b;
418 b = !__lint_false;
419 b = !__lint_true;
420
421 int i = 0;
422
423 i = !i; /* expect: 330 */
424 i = !!!i; /* expect: 330 */
425 i = !0; /* expect: 330 */
426 i = !1; /* expect: 330 */
427 }
428
429 void
430 strict_bool_operand_unary_address(void)
431 {
432 bool b = __lint_false;
433
434 /* Taking the address of a bool lvalue. */
435 bool *bp;
436 bp = &b;
437 *bp = b;
438 b = *bp;
439 }
440
441 /*
442 * strict-bool-operand-binary:
443 * Operator left: bool? other? right: bool? other?
444 * . - yes yes yes
445 * -> - yes yes yes
446 * <=, <, >=, > - yes - yes
447 * ==, != yes yes yes yes
448 * & yes yes yes yes
449 * ^ yes yes yes yes
450 * | yes yes yes yes
451 * && yes - yes -
452 * || yes - yes -
453 * ? yes - yes yes
454 * : yes yes yes yes
455 * = yes yes yes yes
456 * &=, ^=, |= yes yes yes yes
457 * , yes yes yes yes
458 * The other binary operators do not accept bool operands.
459 */
460
461 /*
462 * Ensure that bool members can be accessed as usual.
463 */
464 void
465 strict_bool_operand_binary_dot_arrow(void)
466 {
467 struct bool_struct {
468 bool b;
469 };
470
471 /* Initialize and assign using boolean constants. */
472 bool b = __lint_false;
473 b = __lint_true;
474
475 /* Access a struct member using the '.' operator. */
476 struct bool_struct bs = { __lint_true };
477 b = bs.b;
478 bs.b = b;
479 bs.b = 0; /* expect: 107 */
480
481 /* Access a struct member using the '->' operator. */
482 struct bool_struct *bsp = &bs;
483 b = bsp->b;
484 bsp->b = b;
485 bsp->b = 0; /* expect: 107 */
486 }
487
488 int
489 strict_bool_operand_binary(bool b, int i)
490 {
491
492 /* The right-hand sides of these assignments are ok. */
493 b = !b;
494 b = b && b;
495 b = b || b;
496
497 /*
498 * The right-hand sides of these assignments implicitly convert from
499 * scalar to bool.
500 */
501 b = !i; /* expect: 330 */
502 b = i && i; /* expect: 331, 332 */
503 b = i || i; /* expect: 331, 332 */
504
505 b = b && 0; /* expect: 332 */
506 b = 0 && b; /* expect: 331 */
507 b = b || 0; /* expect: 332 */
508 b = 0 || b; /* expect: 331 */
509
510 return i;
511 }
512
513 void
514 strict_bool_operand_binary_all(bool b, unsigned u)
515 {
516 b = !b;
517 b = ~b; /* expect: 335 */
518 ++b; /* expect: 335 */
519 --b; /* expect: 335 */
520 b++; /* expect: 335 */
521 b--; /* expect: 335 */
522 b = +b; /* expect: 335 */
523 b = -b; /* expect: 335 */
524
525 b = b * b; /* expect: 336, 337 */
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
533 b = b < b; /* expect: 336, 337 */
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;
538 b = b != b;
539
540 b = b & b;
541 b = b ^ b;
542 b = b | b;
543 b = b && b;
544 b = b || b;
545 b = b ? b : b;
546
547 b = b;
548 b *= b; /* expect: 336, 337 */
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;
556 b ^= b;
557 b |= b;
558
559 /* Operations with mixed types. */
560 u = b * u; /* expect: 336 */
561 u = u * b; /* expect: 337 */
562 u = b / u; /* expect: 336 */
563 u = u / b; /* expect: 337 */
564 u = b % u; /* expect: 336 */
565 u = u % b; /* expect: 337 */
566 u = b + u; /* expect: 336 */
567 u = u + b; /* expect: 337 */
568 u = b - u; /* expect: 336 */
569 u = u - b; /* expect: 337 */
570 u = b << u; /* expect: 336 */
571 u = u << b; /* expect: 337 */
572 u = b >> u; /* expect: 336 */
573 u = u >> b; /* expect: 337 */
574 u = b ? u : u;
575 u = b ? b : u; /* expect: 107 */
576 u = b ? u : b; /* expect: 107 */
577 }
578
579 bool
580 strict_bool_operand_binary_comma(bool b, int i)
581 {
582 b = (b, !b);
583 i = (i, i + 1);
584 return b;
585 }
586
587 /*
588 * strict-bool-operator-result:
589 * The result type of the operators '!', '<', '<=', '>', '>=',
590 * '==', '!=', '&&', '||' is _Bool instead of int.
591 */
592
593 void
594 strict_bool_operator_result(bool b)
595 {
596 char c = b; /* expect: 107 */
597 int i = b; /* expect: 107 */
598 double d = b; /* expect: 107 */
599 void *p = b; /* expect: 107 */
600
601 /* The right-hand sides of these assignments are all ok. */
602 b = !b;
603 b = i == i;
604 b = i != i;
605 b = i < i;
606 b = i <= i;
607 b = i >= i;
608 b = i > i;
609 b = b && b;
610 b = b || b;
611
612 /*
613 * The right-hand sides of these assignments are not ok, they
614 * implicitly convert from bool to int.
615 */
616 i = !b; /* expect: 107 */
617 i = i == i; /* 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 = b && b; /* expect: 107 */
624 i = b || b; /* expect: 107 */
625 }
626
627
628 /*
629 * strict-bool-bitwise-and:
630 * Expressions of the form "flags & FLAG" are compatible with _Bool if
631 * the left operand has enum type, the right operand is an integer
632 * constant and the resulting value is used in a context where it is
633 * implicitly and immediately compared to zero.
634 *
635 * Note: Examples for such contexts are controlling expressions or the
636 * operands of the operators '!', '&&', '||'.
637 *
638 * Note: Counterexamples for contexts are assignments to a bool variable.
639 *
640 * Note: These rules ensure that conforming code can be compiled without
641 * change in behavior using old compilers that implement bool as an
642 * ordinary integer type, without the special rule C99 6.3.1.2.
643 */
644
645 enum Flags {
646 FLAG0 = 1 << 0,
647 FLAG1 = 1 << 1,
648 FLAG28 = 1 << 28
649 };
650
651 void
652 strict_bool_bitwise_and_enum(enum Flags flags) /* expect: 231 */
653 {
654 bool b;
655
656 /*
657 * FLAG0 has the value 1 and thus can be stored in a bool variable
658 * without truncation. Nevertheless this special case is not allowed
659 * because it would be too confusing if FLAG0 would work and all the
660 * other flags wouldn't.
661 */
662 b = flags & FLAG0; /* expect: 107 */
663
664 /*
665 * Assuming that FLAG1 is set in flags, a _Bool variable stores this
666 * as 1, as defined by C99 6.3.1.2. A uint8_t variable would store
667 * it as 2, as that is the integer value of FLAG1. Since FLAG1 fits
668 * in a uint8_t, no truncation takes place.
669 */
670 b = flags & FLAG1; /* expect: 107 */
671
672 /*
673 * In a _Bool variable, FLAG28 is stored as 1, since it is unequal to
674 * zero. In a uint8_t, the stored value would be 0 since bit 28 is
675 * out of range for a uint8_t and thus gets truncated.
676 */
677 b = flags & FLAG28; /* expect: 107 */
678 }
679
680 /*
681 * Demonstrate idiomatic code to query flags from an enum bit set.
682 *
683 * In all the controlling expressions in this function, the result of the
684 * operator '&' is compared against 0. This makes this pattern work, no
685 * matter whether the bits are in the low-value range or in the high-value
686 * range (such as FLAG28, which has the value 1073741824, which is more than
687 * what would fit into an unsigned char). Even if an enum could be extended
688 * to larger types than int, this pattern would work.
689 */
690 void
691 query_flag_from_enum_bit_set(enum Flags flags)
692 {
693 if (flags & FLAG0)
694 println("FLAG0 is set");
695
696 if ((flags & FLAG1) != 0)
697 println("FLAG1 is set");
698
699 if ((flags & (FLAG0 | FLAG1)) == (FLAG0 | FLAG1))
700 println("FLAG0 and FLAG1 are both set");
701
702 if (flags & FLAG0 && flags & FLAG1)
703 println("FLAG0 and FLAG1 are both set");
704
705 if ((flags & (FLAG0 | FLAG1)) != 0)
706 println("At least one of FLAG0 and FLAG1 is set");
707
708 if (flags & FLAG28)
709 println("FLAG28 is set");
710 }
711
712
713 void
714 strict_bool_operator_eq_bool_int(void)
715 {
716 (void)(strict_bool_conversion_return_false() == 0); /* expect: 107 */
717 }
718
719 void
720 strict_bool_assign_bit_field_then_compare(void)
721 {
722 struct s {
723 bool flag: 1;
724 };
725
726 struct s s = { __lint_false };
727
728 /* FIXME: The __lint_false is converted irreversibly to an INT. */
729 (void)((s.flag = s.flag) != __lint_false); /* expect: 107 */
730 }
731