d_c99_bool_strict.c revision 1.33 1 /* $NetBSD: d_c99_bool_strict.c,v 1.33 2021/11/16 18:27:04 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 (/*CONSTCOND*/0) /* expect: 333 */
377 do_nothing(); /* expect: statement not reached [193] */
378
379 if (/*CONSTCOND*/1) /* expect: 333 */
380 do_nothing();
381
382 if (/*CONSTCOND*/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
780 /*
781 * For expressions that originate from a system header, the strict type rules
782 * are relaxed a bit, to allow for expressions like 'flags & FLAG', even
783 * though they are not strictly boolean.
784 *
785 * This shouldn't apply to function call expressions though since one of the
786 * goals of strict bool mode is to normalize all expressions like 'strcmp' to
787 * be 'strcmp(a, b) == 0' instead of '!strcmp(a, b)'.
788 */
789 # 1 "stdio.h" 1 3 4
790 typedef struct stdio_file {
791 int fd;
792 } FILE;
793 int ferror(FILE *);
794 FILE stdio_files[3];
795 FILE *stdio_stdout;
796 # 797 "d_c99_bool_strict.c" 2
797 # 1 "string.h" 1 3 4
798 int strcmp(const char *, const char *);
799 # 800 "d_c99_bool_strict.c" 2
800
801 void
802 controlling_expression(FILE *f, const char *a, const char *b)
803 {
804 /* expect+1: error: controlling expression must be bool, not 'int' [333] */
805 if (ferror(f))
806 return;
807 /* expect+1: error: controlling expression must be bool, not 'int' [333] */
808 if (strcmp(a, b))
809 return;
810 /* expect+1: error: operand of '!' must be bool, not 'int' [330] */
811 if (!ferror(f))
812 return;
813 /* expect+1: error: operand of '!' must be bool, not 'int' [330] */
814 if (!strcmp(a, b))
815 return;
816
817 /*
818 * No warning below since the expression 'stdio_stdin' comes from a
819 * system header (typically via a macro), and this property is passed
820 * up to the expression 'ferror(stdio_stdin)'.
821 *
822 * That is wrong though since the above rule would allow a plain
823 * 'strcmp' without a following '== 0', as long as one of its
824 * arguments comes from a system header.
825 *
826 * Seen in bin/echo/echo.c, function main, call to ferror.
827 */
828 /*
829 * TODO: In a function call expression, tn->tn_relaxed should only be
830 * derived from the function itself, not from its arguments.
831 */
832 /* TODO: Warn about type mismatch [333]. */
833 if (ferror(
834 # 835 "d_c99_bool_strict.c" 3 4
835 &stdio_files[1]
836 # 837 "d_c99_bool_strict.c"
837 ))
838 return;
839
840 /*
841 * Before cgram.y 1.369 from 2021-11-16, at the end of parsing the
842 * name 'stdio_stdout', the parser already looked ahead to the next
843 * token, to see whether it was the '(' of a function call. At that
844 * point, the parser was no longer in a system header, therefore
845 * 'stdio_stdout' was not tn_relaxed, and this information was pushed
846 * down to the whole function call expression (which was another bug
847 * at that time).
848 */
849 if (ferror(
850 # 851 "d_c99_bool_strict.c" 3 4
851 stdio_stdout
852 # 853 "d_c99_bool_strict.c"
853 ))
854 return;
855
856 /*
857 * In this variant, there is a token ')' after the name
858 * 'stdio_stdout', which has the effect that at the end of parsing
859 * the name, the parser is still in the system header, thus setting
860 * tn_relaxed to true.
861 */
862 if (ferror(
863 # 864 "d_c99_bool_strict.c" 3 4
864 (stdio_stdout)
865 # 866 "d_c99_bool_strict.c"
866 ))
867 return;
868
869 /*
870 * Before cgram.y 1.369 from 2021-11-16, the comment following
871 * 'stdio_stdout' did not prevent the search for '('. At the point
872 * where build_name calls expr_zalloc_tnode, the parser was already
873 * in the main file again, thus treating 'stdio_stdout' as not coming
874 * from a system header.
875 */
876 if (ferror(
877 # 878 "d_c99_bool_strict.c" 3 4
878 stdio_stdout /* comment */
879 # 880 "d_c99_bool_strict.c"
880 ))
881 return;
882 }
883