d_c99_bool_strict.c revision 1.7 1 /* $NetBSD: d_c99_bool_strict.c,v 1.7 2021/01/15 23:15:28 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 means:
7 *
8 * SB001: Controlling expressions in 'if', 'while', 'for', '?:' must be of
9 * type _Bool instead of scalar.
10 *
11 * SB002: The operators '!', '==', '!=', '<', '<=', '>=', '>', '&&', '||'
12 * return _Bool instead of int.
13 *
14 * SB003: The operators '!', '&&', '||' take _Bool instead of scalar.
15 *
16 * SB004: The only operators that take _Bool are '!', '==', '!=',
17 * '&', '^', '|', '&&', '||', '?', ':', '=', '&=', '^=', '|='.
18 *
19 * SB005: There is no implicit conversion from _Bool to any other type.
20 *
21 * SB006: An expression is compatible with type _Bool if its main operator
22 * returns type _Bool, or if the expression is an integer constant expression
23 * with value 0 or 1.
24 *
25 * SB007: Expressions like "flags & FLAG" are compatible with _Bool if
26 * they appear in a context where they are immediately compared to zero.
27 * Assigning to a _Bool variable does not count as such a context, to
28 * allow programs to be compiled without silent changes on a compiler that
29 * is lacking the special _Bool type.
30 *
31 * SB008: Bit fields in struct may be based on _Bool. These bit fields
32 * typically have type _Bool:1 and can be converted to _Bool and back.
33 */
34
35 /* lint1-extra-flags: -T */
36
37 /*
38 * The header <stdbool.h> defines the macros bool = _Bool, false = 0 and
39 * true = 1. Therefore, constant expressions of integer type have to be
40 * regarded as possible boolean constants if their value is either 0 or 1.
41 * At this point of the translation, the preprocessor has already removed
42 * the words "false" and "true" from the source code.
43 */
44
45 /*
46 * Using a typedef for bool does not hurt the checks, they all use the
47 * underlying basic type (see tspec_t), which is BOOL.
48 */
49 typedef _Bool bool;
50
51 void
52 SB001_controlling_expression(bool b, int i, double d, const void *p)
53 {
54
55 /* Fine due to SB006. */
56 if (/*CONSTCOND*/0)
57 return;
58
59 /* Fine due to SB006. */
60 if (/*CONSTCOND*/1)
61 return;
62
63 /* Not allowed: 2 is not a boolean expression. */
64 if (/*CONSTCOND*/2) /* expect: 333 */
65 return;
66
67 /* Not allowed: There is no implicit conversion from scalar to bool. */
68 if (i) /* expect: 333 */
69 return;
70 if (i != 0)
71 return;
72
73 /* Not allowed: There is no implicit conversion from scalar to bool. */
74 if (d) /* expect: 333 */
75 return;
76 if (d != 0.0)
77 return;
78
79 /* Not allowed: There is no implicit conversion from scalar to bool. */
80 if (p) /* expect: 333 */
81 return;
82 if (p != (void *)0)
83 return;
84
85 /* Using a bool expression is allowed. */
86 if (b)
87 return;
88 }
89
90 void
91 SB002_operator_result_type(bool b)
92 {
93 b = b;
94 char c = b; /* expect: 107 */
95 int i = b; /* expect: 107 */
96 double d = b; /* expect: 107 */
97 void *p = b; /* expect: 107 */
98
99 /* The right-hand sides of these assignments are all ok. */
100 b = !b;
101 b = i == i;
102 b = i != i;
103 b = i < i;
104 b = i <= i;
105 b = i >= i;
106 b = i > i;
107 b = b && b;
108 b = b || b;
109
110 /*
111 * The right-hand sides of these assignments are not ok, they
112 * implicitly convert from bool to int.
113 */
114 i = !b; /* expect: 107 */
115 i = i == i; /* expect: 107 */
116 i = i != i; /* expect: 107 */
117 i = i < i; /* expect: 107 */
118 i = i <= i; /* expect: 107 */
119 i = i >= i; /* expect: 107 */
120 i = i > i; /* expect: 107 */
121 i = b && b; /* expect: 107 */
122 i = b || b; /* expect: 107 */
123 }
124
125 int
126 SB003_operands(bool b, int i)
127 {
128
129 /* The right-hand sides of these assignments are ok. */
130 b = !b;
131 b = b && b;
132 b = b || b;
133
134 /*
135 * The right-hand sides of these assignments implicitly convert from
136 * scalar to bool.
137 */
138 b = !i; /* expect: 330 */
139 b = i && i; /* expect: 331, 332 */
140 b = i || i; /* expect: 331, 332 */
141
142 b = b && 0;
143 b = 0 && b;
144 b = b || 0;
145 b = 0 || b;
146
147 return i;
148 }
149
150 /*ARGSUSED*/
151 void
152 SB004_operators_and_bool_operands(bool b, unsigned u)
153 {
154 b = !b; /* ok */
155 b = ~b; /* expect: 335 */
156 ++b; /* expect: 335 */
157 --b; /* expect: 335 */
158 b++; /* expect: 335 */
159 b--; /* expect: 335 */
160 b = +b; /* expect: 335 */
161 b = -b; /* expect: 335 */
162
163 b = b * b; /* expect: 336, 337 */
164 b = b / b; /* expect: 336, 337 */
165 b = b % b; /* expect: 336, 337 */
166 b = b + b; /* expect: 336, 337 */
167 b = b - b; /* expect: 336, 337 */
168 b = b << b; /* expect: 336, 337 */
169 b = b >> b; /* expect: 336, 337 */
170
171 b = b < b; /* expect: 336, 337 */
172 b = b <= b; /* expect: 336, 337 */
173 b = b > b; /* expect: 336, 337 */
174 b = b >= b; /* expect: 336, 337 */
175 b = b == b; /* ok */
176 b = b != b; /* ok */
177
178 b = b & b; /* ok */
179 b = b ^ b; /* ok */
180 b = b | b; /* ok */
181 b = b && b; /* ok */
182 b = b || b; /* ok */
183 b = b ? b : b; /* ok */
184
185 b = b; /* ok */
186 b *= b; /* expect: 336, 337 */
187 b /= b; /* expect: 336, 337 */
188 b %= b; /* expect: 336, 337 */
189 b += b; /* expect: 336, 337 */
190 b -= b; /* expect: 336, 337 */
191 b <<= b; /* expect: 336, 337 */
192 b >>= b; /* expect: 336, 337 */
193 b &= b; /* ok */
194 b ^= b; /* ok */
195 b |= b; /* ok */
196
197 /* Operations with mixed types. */
198 u = b * u; /* expect: 336 */
199 u = u * b; /* expect: 337 */
200 u = b / u; /* expect: 336 */
201 u = u / b; /* expect: 337 */
202 u = b % u; /* expect: 336 */
203 u = u % b; /* expect: 337 */
204 u = b + u; /* expect: 336 */
205 u = u + b; /* expect: 337 */
206 u = b - u; /* expect: 336 */
207 u = u - b; /* expect: 337 */
208 u = b << u; /* expect: 336 */
209 u = u << b; /* expect: 337 */
210 u = b >> u; /* expect: 336 */
211 u = u >> b; /* expect: 337 */
212 u = b ? u : u; /* ok */
213 u = b ? b : u; /* expect: 107 */
214 u = b ? u : b; /* expect: 107 */
215 }
216
217 /*ARGSUSED*/
218 void
219 SB005_convert_from_bool_to_scalar(bool b)
220 {
221 int i;
222 unsigned u;
223 double d;
224 void *p;
225
226 i = b; /* expect: 107 */
227 u = b; /* expect: 107 */
228 d = b; /* expect: 107 */
229 p = b; /* expect: 107 */
230 }
231
232 enum SB006_bool_constant_expression {
233 /* Ok: 0 is a boolean constant expression. */
234 INT0 = 0 ? 100 : 101,
235
236 /* Ok: 1 is a boolean constant expression. */
237 INT1 = 1 ? 100 : 101,
238
239 /* Not ok: 2 is not a boolean constant (neither 0 nor 1). */
240 INT2 = 2 ? 100 : 101, /* expect: 331 */
241
242 /*
243 * The intermediate expression "2" has type int, which is not
244 * compatible with _Bool. The expression "2 - 2" is an integer
245 * constant expression with value 0 and is thus a bool constant
246 * expression. This particular case probably does not occur in
247 * practice.
248 */
249 ARITH = (2 - 2) ? 100 : 101,
250
251 /*
252 * These two variants of an expression can occur when a preprocessor
253 * macro is either defined to 1 or left empty, as in lint1/ops.def.
254 */
255 BINARY_PLUS = (1 + 0) ? 100 : 101,
256 UNARY_PLUS = (+0) ? 100 : 101,
257
258 /* The main operator '>' has return type bool. */
259 Q1 = (13 > 12) ? 100 : 101,
260
261 /*
262 * The 7 is part of the integer constant expression, but it is
263 * irrelevant for the final result. The expression in parentheses
264 * is an integer constant expression with value 1 and thus is a
265 * bool constant expression.
266 */
267 Q2 = (13 > 12 ? 1 : 7) ? 100 : 101,
268
269 BINAND = 0 & 1, /* ok */
270
271 BINXOR = 0 ^ 1, /* ok */
272
273 BINOR = 0 | 1, /* ok */
274
275 LOGOR = 0 || 1, /* ok */
276
277 LOGAND = 0 && 1, /* ok */
278 };
279
280 /*
281 * An efficient implementation technique for a collection of boolean flags
282 * is an enum. The enum declaration groups the available constants, and as
283 * of 2020, compilers such as GCC and Clang have basic support for detecting
284 * type mismatches on enums.
285 */
286
287 enum Flags {
288 FLAG0 = 1 << 0,
289 FLAG1 = 1 << 1,
290 FLAG28 = 1 << 28
291 };
292
293 /*
294 * The usual way to query one of the flags is demonstrated below.
295 */
296
297 extern void
298 println(const char *);
299
300 void
301 query_flag_from_enum_bit_set(enum Flags flags)
302 {
303
304 if (flags & FLAG0)
305 println("FLAG0 is set");
306
307 if ((flags & FLAG1) != 0)
308 println("FLAG1 is set");
309
310 if ((flags & (FLAG0 | FLAG1)) == (FLAG0 | FLAG1))
311 println("FLAG0 and FLAG1 are both set");
312
313 if (flags & FLAG0 && flags & FLAG1)
314 println("FLAG0 and FLAG1 are both set");
315
316 if ((flags & (FLAG0 | FLAG1)) != 0)
317 println("At least one of FLAG0 and FLAG1 is set");
318
319 if (flags & FLAG28)
320 println("FLAG28 is set");
321 }
322
323 /*
324 * In all the above conditions (or controlling expressions, as the C standard
325 * calls them), the result of the operator '&' is compared against 0. This
326 * makes this pattern work, no matter whether the bits are in the low-value
327 * range or in the high-value range (such as FLAG28, which has the value
328 * 1073741824, which is more than what would fit into an unsigned char).
329 * Even if an enum could be extended to larger types than int, this pattern
330 * would work.
331 */
332
333 /*
334 * There is a crucial difference between a _Bool variable and an ordinary
335 * integer variable. C99 6.3.1.2 defines a conversion from an arbitrary
336 * scalar value to _Bool as equivalent to (value != 0 ? 1 : 0). This means
337 * that even if _Bool is implemented as an 8-bit unsigned integer, assigning
338 * 256 to it would still result in the value 1 being stored. Storing 256 in
339 * an ordinary 8-bit unsigned integer would result in the value 0 being
340 * stored. See the test d_c99_bool.c for more details.
341 *
342 * Because of this, expressions like (flags & FLAG28) are only allowed in
343 * bool context if they are guaranteed not to be truncated, even if the
344 * result were to be stored in a plain unsigned integer.
345 */
346
347 /*ARGSUSED*/
348 void
349 SB007_allow_flag_test_on_bit_set_enums(enum Flags flags)
350 {
351 bool b;
352
353 /*
354 * FLAG0 has the value 1 and thus can be stored in a bool variable
355 * without truncation. Nevertheless this special case is not allowed
356 * because it would be too confusing if FLAG0 would work and all the
357 * other flags wouldn't.
358 */
359 b = flags & FLAG0; /* expect: 107 */
360
361 /*
362 * Assuming that FLAG1 is set in flags, a _Bool variable stores this
363 * as 1, as defined by C99 6.3.1.2. A uint8_t variable would store
364 * it as 2, as that is the integer value of FLAG1. Since FLAG1 fits
365 * in a uint8_t, no truncation takes place.
366 */
367 b = flags & FLAG1; /* expect: 107 */
368
369 /*
370 * In a _Bool variable, FLAG28 is stored as 1, since it is unequal to
371 * zero. In a uint8_t, the stored value would be 0 since bit 28 is
372 * out of range for a uint8_t and thus gets truncated.
373 */
374 b = flags & FLAG28; /* expect: 107 */
375 }
376
377 /* A bool bit field is compatible with bool. Other bit fields are not. */
378
379 struct flags {
380 bool bool_flag: 1;
381 unsigned uint_flag: 1;
382 };
383
384 /*ARGSUSED*/
385 void
386 SB008_bit_fields(const struct flags *flags)
387 {
388 bool b;
389
390 b = flags->bool_flag; /* ok */
391 b = flags->uint_flag; /* expect: 107 */
392 flags->bool_flag = b;
393 flags->uint_flag = b; /* expect: 107 */
394 }
395
396 /* Test implicit conversion when returning a value from a function. */
397
398 /*ARGSUSED*/
399 bool
400 returning_bool(bool b, int i, const char *p)
401 {
402 if (i > 0)
403 return b; /* ok */
404 if (i < 0)
405 return i; /* expect: 211 */
406 return p; /* expect: 211 */
407 }
408
409 /*ARGSUSED*/
410 char
411 returning_char(bool b, int i, const char *p)
412 {
413 if (i > 0)
414 return b; /* expect: 211 */
415 if (i < 0)
416 return i; /* XXX: narrowing conversion */
417 return p; /* expect: 183 */
418 }
419
420 bool
421 return_constant_false(void)
422 {
423 return 0;
424 }
425
426 bool
427 return_constant_true(void)
428 {
429 return 1;
430 }
431
432 bool
433 return_invalid_integer(void)
434 {
435 return 2; /* expect: 211 */
436 }
437
438 /* Test passing arguments to a function. */
439
440 extern void
441 taking_arguments(bool, int, const char *, ...);
442
443 void
444 passing_arguments(bool b, int i, const char *p)
445 {
446 /* No conversion necessary. */
447 taking_arguments(b, i, p);
448
449 /* Implicitly converting bool to other scalar types. */
450 taking_arguments(b, b, b); /* expect: 334, 334 */
451
452 /* Implicitly converting int to bool (arg #1). */
453 taking_arguments(i, i, i); /* expect: 334, 154 */
454
455 /* Implicitly converting pointer to bool (arg #1). */
456 taking_arguments(p, p, p); /* expect: 334, 154 */
457
458 /* Passing bool as vararg. */
459 taking_arguments(b, i, p, b, i, p); /* expect: arg#4 */ // TODO
460
461 /* Passing a bool constant. */
462 taking_arguments(0, i, p);
463
464 /* Passing a bool constant. */
465 taking_arguments(1, i, p);
466
467 /* Trying to pass an invalid integer. */
468 taking_arguments(2, i, p); /* expect: 334 */
469 }
470
471 /*
472 * This is just normal access to a bool member of a struct, to ensure that
473 * these produce no errors.
474 */
475 void
476 struct_access_operators(void)
477 {
478 struct bool_struct {
479 bool b;
480 };
481
482 /* Initialize and assign using boolean constants. */
483 bool b = 0;
484 b = 1;
485
486 /* Access a struct member using the '.' operator. */
487 struct bool_struct bs = { 1 };
488 b = bs.b;
489 bs.b = b;
490 bs.b = 0;
491
492 /* Access a struct member using the '->' operator. */
493 struct bool_struct *bsp = &bs;
494 b = bsp->b;
495 bsp->b = b;
496 bsp->b = 0;
497
498 /* Taking the address of a bool lvalue. */
499 bool *bp;
500 bp = &b;
501 *bp = b;
502 b = *bp;
503 }
504
505 /*
506 * Comparing a _Bool expression to 0 or 1 is redundant. It may come from
507 * an earlier version of the code, before it got migrated to using _Bool.
508 * Usually, bool expressions are used directly as control expressions or
509 * as argument to the boolean operators such as '!', '&&', '||'.
510 *
511 * Since lint steps in after the C preprocessor, it has no chance of seeing
512 * the original source code, which may well have been "b == false" instead
513 * of "b == 0".
514 */
515 bool
516 compare_var_with_constant(bool b)
517 {
518 bool t1 = b == 0;
519 bool t2 = t1 != 0;
520 bool t3 = t2 == 1;
521 bool t4 = t3 != 1;
522 return t4 ^ t3;
523 }
524
525 bool
526 SB003_operand_comma(bool b, int i)
527 {
528 b = (b, !b);
529 i = (i, i + 1);
530 return b;
531 }
532
533 void
534 bit_field_as_operator_argument(void)
535 {
536 struct s {
537 bool ordinary;
538 bool bit_field: 1;
539 };
540
541 struct s s = { 0 };
542
543 s.ordinary = s.ordinary | s.ordinary;
544 s.bit_field = s.bit_field | s.bit_field; /* FIXME *//* expect: 107 */
545 }
546