d_c99_bool_strict.c revision 1.3 1 1.3 rillig /* $NetBSD: d_c99_bool_strict.c,v 1.3 2021/01/11 00:28:28 rillig Exp $ */
2 1.1 rillig # 3 "d_c99_bool_strict.c"
3 1.1 rillig
4 1.1 rillig /*
5 1.1 rillig * Experimental feature: allow to treat _Bool as incompatible with all
6 1.1 rillig * scalar types. This means:
7 1.1 rillig *
8 1.1 rillig * SB001: Controlling expressions in 'if', 'while', 'for', '?:' must be of
9 1.1 rillig * type _Bool instead of scalar.
10 1.1 rillig *
11 1.1 rillig * SB002: The operators '!', '==', '!=', '<', '<=', '>=', '>', '&&', '||'
12 1.1 rillig * return _Bool instead of int.
13 1.1 rillig *
14 1.1 rillig * SB003: The operators '!', '&&', '||' take _Bool instead of scalar.
15 1.1 rillig *
16 1.1 rillig * SB004: The only operators that take _Bool are '!', '==', '!=',
17 1.1 rillig * '&', '^', '|', '&&', '||', '?', ':', '=', '&=', '^=', '|='.
18 1.1 rillig *
19 1.1 rillig * SB005: There is no implicit conversion from _Bool to any other type.
20 1.1 rillig *
21 1.1 rillig * SB006: A constant integer expression is compatible with type _Bool if
22 1.1 rillig * it is an integer constant with value 0 or 1, or if the result type of
23 1.1 rillig * its main operator is _Bool.
24 1.3 rillig *
25 1.3 rillig * SB007: Expressions like "flags & FLAG" are compatible with _Bool if
26 1.3 rillig * they appear in a context where they are immediately compared to zero.
27 1.3 rillig * Assigning to a _Bool variable does not count as such a context, to
28 1.3 rillig * allow programs to be compiled without silent changes on a compiler that
29 1.3 rillig * is lacking the special _Bool type.
30 1.3 rillig *
31 1.3 rillig * SB008: Bit fields in struct may be based on _Bool. These bit fields
32 1.3 rillig * typically have type _Bool:1 and can be converted to _Bool and back.
33 1.1 rillig */
34 1.1 rillig
35 1.2 rillig // Not yet implemented: /* lint1-extra-flags: -T */
36 1.1 rillig
37 1.1 rillig /*
38 1.1 rillig * The header <stdbool.h> defines the macros bool = _Bool, false = 0 and
39 1.1 rillig * true = 1. Therefore, constant expressions of integer type have to be
40 1.1 rillig * regarded as possible boolean constants if their value is either 0 or 1.
41 1.1 rillig * At this point of the translation, the preprocessor has already removed
42 1.1 rillig * the words "false" and "true" from the source code.
43 1.1 rillig */
44 1.1 rillig
45 1.1 rillig /*
46 1.1 rillig * Using a typedef for bool does not hurt the checks, they all use the
47 1.1 rillig * underlying basic type (see tspec_t), which is BOOL.
48 1.1 rillig */
49 1.1 rillig typedef _Bool bool;
50 1.1 rillig
51 1.1 rillig void
52 1.1 rillig SB001_controlling_expression(bool b, int i, double d, const void *p)
53 1.1 rillig {
54 1.1 rillig
55 1.1 rillig /* Fine due to SB006. */
56 1.1 rillig if (/*CONSTCOND*/0)
57 1.1 rillig return;
58 1.1 rillig
59 1.1 rillig /* Fine due to SB006. */
60 1.1 rillig if (/*CONSTCOND*/1)
61 1.1 rillig return;
62 1.1 rillig
63 1.1 rillig /* Not allowed: 2 is not a boolean expression. */
64 1.1 rillig if (/*CONSTCOND*/2)
65 1.1 rillig return;
66 1.1 rillig
67 1.1 rillig /* Not allowed: There is no implicit conversion from scalar to bool. */
68 1.1 rillig if (i)
69 1.1 rillig return;
70 1.1 rillig if (i != 0)
71 1.1 rillig return;
72 1.1 rillig
73 1.1 rillig /* Not allowed: There is no implicit conversion from scalar to bool. */
74 1.1 rillig if (d)
75 1.1 rillig return;
76 1.1 rillig if (d != 0.0)
77 1.1 rillig return;
78 1.1 rillig
79 1.1 rillig /* Not allowed: There is no implicit conversion from scalar to bool. */
80 1.1 rillig if (p)
81 1.1 rillig return;
82 1.1 rillig if (p != (void *)0)
83 1.1 rillig return;
84 1.1 rillig
85 1.1 rillig /* Using a bool expression is allowed. */
86 1.1 rillig if (b)
87 1.1 rillig return;
88 1.1 rillig }
89 1.1 rillig
90 1.1 rillig void
91 1.1 rillig SB002_operator_result(bool b)
92 1.1 rillig {
93 1.1 rillig b = b;
94 1.1 rillig char c = b;
95 1.1 rillig int i = b;
96 1.1 rillig double d = b;
97 1.1 rillig void *p = b;
98 1.1 rillig
99 1.1 rillig /* These assignments are all ok. */
100 1.1 rillig b = !b;
101 1.1 rillig b = i == i;
102 1.1 rillig b = i != i;
103 1.1 rillig b = i < i;
104 1.1 rillig b = i <= i;
105 1.1 rillig b = i >= i;
106 1.1 rillig b = i > i;
107 1.1 rillig b = b && b;
108 1.1 rillig b = b || b;
109 1.1 rillig
110 1.1 rillig /*
111 1.1 rillig * These assignments are not ok, they implicitly convert from bool
112 1.1 rillig * to int.
113 1.1 rillig */
114 1.1 rillig i = !b;
115 1.1 rillig i = i == i;
116 1.1 rillig i = i != i;
117 1.1 rillig i = i < i;
118 1.1 rillig i = i <= i;
119 1.1 rillig i = i >= i;
120 1.1 rillig i = i > i;
121 1.1 rillig i = b && b;
122 1.1 rillig i = b || b;
123 1.1 rillig }
124 1.1 rillig
125 1.1 rillig void
126 1.1 rillig SB003_operands(bool b, int i)
127 1.1 rillig {
128 1.1 rillig
129 1.1 rillig /* These assignments are ok. */
130 1.1 rillig b = !b;
131 1.1 rillig b = b && b;
132 1.1 rillig b = b || b;
133 1.1 rillig
134 1.1 rillig /* These assignments implicitly convert from scalar to bool. */
135 1.1 rillig b = !i;
136 1.1 rillig b = i && i;
137 1.1 rillig b = i || i;
138 1.1 rillig }
139 1.1 rillig
140 1.1 rillig void
141 1.1 rillig SB004_non_bool_operands(bool b, unsigned u)
142 1.1 rillig {
143 1.1 rillig b = !b; /* ok */
144 1.1 rillig b = ~b; /* not ok */
145 1.1 rillig ++b; /* not ok */
146 1.1 rillig --b; /* not ok */
147 1.1 rillig b++; /* not ok */
148 1.1 rillig b--; /* not ok */
149 1.1 rillig b = +b; /* not ok */
150 1.1 rillig b = -b; /* not ok */
151 1.1 rillig
152 1.1 rillig b = b * b; /* not ok */
153 1.1 rillig b = b / b; /* not ok */
154 1.1 rillig b = b % b; /* not ok */
155 1.1 rillig b = b + b; /* not ok */
156 1.1 rillig b = b - b; /* not ok */
157 1.1 rillig b = b << b; /* not ok */
158 1.1 rillig b = b >> b; /* not ok */
159 1.1 rillig
160 1.1 rillig b = b < b; /* not ok */
161 1.1 rillig b = b <= b; /* not ok */
162 1.1 rillig b = b > b; /* not ok */
163 1.1 rillig b = b >= b; /* not ok */
164 1.1 rillig b = b == b; /* ok */
165 1.1 rillig b = b != b; /* ok */
166 1.1 rillig
167 1.1 rillig b = b & b; /* ok */
168 1.1 rillig b = b ^ b; /* ok */
169 1.1 rillig b = b | b; /* ok */
170 1.1 rillig b = b && b; /* ok */
171 1.1 rillig b = b || b; /* ok */
172 1.1 rillig b = b ? b : b; /* ok */
173 1.1 rillig
174 1.1 rillig b = b; /* ok */
175 1.1 rillig b *= b; /* not ok */
176 1.1 rillig b /= b; /* not ok */
177 1.1 rillig b %= b; /* not ok */
178 1.1 rillig b += b; /* not ok */
179 1.1 rillig b -= b; /* not ok */
180 1.1 rillig b <<= b; /* not ok */
181 1.1 rillig b >>= b; /* not ok */
182 1.1 rillig b &= b; /* ok */
183 1.1 rillig b ^= b; /* ok */
184 1.1 rillig b |= b; /* ok */
185 1.1 rillig
186 1.1 rillig /* Operations with mixed types. */
187 1.1 rillig u = b * u; /* not ok */
188 1.1 rillig u = u * b; /* not ok */
189 1.1 rillig u = b / u; /* not ok */
190 1.1 rillig u = u / b; /* not ok */
191 1.1 rillig u = b % u; /* not ok */
192 1.1 rillig u = u % b; /* not ok */
193 1.1 rillig u = b + u; /* not ok */
194 1.1 rillig u = u + b; /* not ok */
195 1.1 rillig u = b - u; /* not ok */
196 1.1 rillig u = u - b; /* not ok */
197 1.1 rillig u = b << u; /* not ok */
198 1.1 rillig u = u << b; /* not ok */
199 1.1 rillig u = b >> u; /* not ok */
200 1.1 rillig u = u >> b; /* not ok */
201 1.1 rillig u = b ? u : u; /* ok */
202 1.1 rillig u = b ? b : u; /* not ok */
203 1.1 rillig u = b ? u : b; /* not ok */
204 1.1 rillig }
205 1.1 rillig
206 1.1 rillig void
207 1.1 rillig SB005_convert_from_bool_to_scalar(bool b)
208 1.1 rillig {
209 1.1 rillig int i;
210 1.1 rillig unsigned u;
211 1.1 rillig double d;
212 1.1 rillig void *p;
213 1.1 rillig
214 1.1 rillig i = b; /* not ok */
215 1.1 rillig u = b; /* not ok */
216 1.1 rillig d = b; /* not ok */
217 1.1 rillig p = b; /* not ok */
218 1.1 rillig }
219 1.1 rillig
220 1.1 rillig enum SB006_bool_constant_expression {
221 1.1 rillig /* Ok: 0 is a boolean constant expression. */
222 1.1 rillig INT0 = 0 ? 100 : 101,
223 1.1 rillig
224 1.1 rillig /* Ok: 1 is a boolean constant expression. */
225 1.1 rillig INT1 = 1 ? 100 : 101,
226 1.1 rillig
227 1.1 rillig /* Not ok: 2 is not a boolean constant (neither 0 nor 1). */
228 1.1 rillig INT2 = 2 ? 100 : 101,
229 1.1 rillig
230 1.1 rillig /*
231 1.1 rillig * Not ok: the intermediate expression "2 - 2" has return type
232 1.1 rillig * scalar, not bool. It is irrelevant that the final result
233 1.1 rillig * is 0, which would be a boolean constant.
234 1.1 rillig */
235 1.1 rillig ARITH = (2 - 2) ? 100 : 101,
236 1.1 rillig
237 1.1 rillig /*
238 1.1 rillig * Ok: The 13 and 12 are not boolean expressions, but they
239 1.1 rillig * are not in the calculation path that leads to the final
240 1.1 rillig * result. The important point is that the operator '>' has
241 1.1 rillig * return type bool.
242 1.1 rillig */
243 1.1 rillig Q1 = (13 > 12) ? 100 : 101,
244 1.1 rillig
245 1.1 rillig /*
246 1.1 rillig * Not ok: The 7 is irrelevant for the final result of the
247 1.1 rillig * expression, yet it turns the result type of the operator
248 1.1 rillig * '?:' to be int, not bool.
249 1.1 rillig */
250 1.1 rillig Q2 = (13 > 12 ? 1 : 7) ? 100 : 101,
251 1.1 rillig
252 1.1 rillig BINAND = 0 & 1, /* ok */
253 1.1 rillig
254 1.1 rillig BINXOR = 0 ^ 1, /* ok */
255 1.1 rillig
256 1.1 rillig BINOR = 0 | 1, /* ok */
257 1.1 rillig
258 1.1 rillig LOGOR = 0 || 1, /* ok */
259 1.1 rillig
260 1.1 rillig LOGAND = 0 && 1, /* ok */
261 1.1 rillig };
262 1.2 rillig
263 1.3 rillig /*
264 1.3 rillig * An efficient implementation technique for a collection of boolean flags
265 1.3 rillig * is an enum. The enum declaration groups the available constants, and as
266 1.3 rillig * of 2020, compilers such as GCC and Clang have basic support for detecting
267 1.3 rillig * type mismatches on enums.
268 1.3 rillig */
269 1.3 rillig
270 1.3 rillig enum Flags {
271 1.3 rillig FLAG0 = 1 << 0,
272 1.3 rillig FLAG1 = 1 << 1,
273 1.3 rillig FLAG28 = 1 << 28
274 1.2 rillig };
275 1.2 rillig
276 1.2 rillig /*
277 1.3 rillig * The usual way to query one of the flags is demonstrated below.
278 1.3 rillig */
279 1.3 rillig
280 1.3 rillig extern void println(const char *);
281 1.3 rillig
282 1.3 rillig void
283 1.3 rillig query_flag_from_enum_bit_set(enum Flags flags)
284 1.3 rillig {
285 1.3 rillig
286 1.3 rillig if (flags & FLAG0)
287 1.3 rillig println("FLAG0 is set");
288 1.3 rillig
289 1.3 rillig if ((flags & FLAG1) != 0)
290 1.3 rillig println("FLAG1 is set");
291 1.3 rillig
292 1.3 rillig if ((flags & (FLAG0 | FLAG1)) == (FLAG0 | FLAG1))
293 1.3 rillig println("FLAG0 and FLAG1 are both set");
294 1.3 rillig if (flags & FLAG0 && flags & FLAG1)
295 1.3 rillig println("FLAG0 and FLAG1 are both set");
296 1.3 rillig
297 1.3 rillig if ((flags & (FLAG0 | FLAG1)) != 0)
298 1.3 rillig println("At least one of FLAG0 and FLAG1 is set");
299 1.3 rillig
300 1.3 rillig if (flags & FLAG28)
301 1.3 rillig println("FLAG28 is set");
302 1.3 rillig }
303 1.3 rillig
304 1.3 rillig /*
305 1.3 rillig * In all the above conditions (or controlling expressions, as the C standard
306 1.3 rillig * calls them), the result of the operator '&' is compared against 0. This
307 1.3 rillig * makes this pattern work, no matter whether the bits are in the low-value
308 1.3 rillig * range or in the high-value range (such as FLAG28, which has the value
309 1.3 rillig * 1073741824, which is more than what fits into an unsigned char). Even
310 1.3 rillig * if an enum could be extended to larger types than int, this pattern
311 1.3 rillig * would work.
312 1.3 rillig */
313 1.3 rillig
314 1.3 rillig /*
315 1.3 rillig * There is a crucial difference between a _Bool variable and an ordinary
316 1.3 rillig * integer variable though. C99 6.3.1.2 defines a conversion from an
317 1.3 rillig * arbitrary scalar type to _Bool as (value != 0 ? 1 : 0). This means that
318 1.3 rillig * even if _Bool is implemented as an 8-bit unsigned integer, assigning 256
319 1.3 rillig * to it would still result in the value 1 being stored. Storing 256 in an
320 1.3 rillig * ordinary 8-bit unsigned integer would result in the value 0 being stored.
321 1.3 rillig * See the test d_c99_bool.c for more details.
322 1.2 rillig *
323 1.3 rillig * Because of this, expressions like (flags & FLAG28) are only allowed in
324 1.3 rillig * bool context if they are guaranteed not to be truncated, even if the
325 1.3 rillig * result were to be stored in a plain unsigned integer.
326 1.2 rillig */
327 1.3 rillig
328 1.3 rillig void
329 1.3 rillig SB007_allow_flag_test_on_bit_set_enums(enum Flags flags)
330 1.3 rillig {
331 1.3 rillig bool b;
332 1.3 rillig
333 1.3 rillig /*
334 1.3 rillig * FLAG0 has the value 1 and can therefore be stored in a bool
335 1.3 rillig * variable without truncation. Nevertheless this special case
336 1.3 rillig * is not allowed because it would be too confusing if FLAG0 would
337 1.3 rillig * work and all the other flags wouldn't.
338 1.3 rillig */
339 1.3 rillig b = flags & FLAG0;
340 1.3 rillig
341 1.3 rillig /*
342 1.3 rillig * Assuming that FLAG1 is set in flags, a _Bool variable stores this
343 1.3 rillig * as 1, as defined by C99 6.3.1.2. An unsigned char variable would
344 1.3 rillig * store it as 2, as that is the integer value of FLAG1. Since FLAG1
345 1.3 rillig * fits in an unsigned char, no truncation takes place.
346 1.3 rillig */
347 1.3 rillig b = flags & FLAG1;
348 1.3 rillig
349 1.3 rillig /*
350 1.3 rillig * In a _Bool variable, FLAG28 is stored as 1, as above. In an
351 1.3 rillig * unsigned char, the stored value would be 0 since bit 28 is out of
352 1.3 rillig * range for an unsigned char, which usually has 8 significant bits.
353 1.3 rillig */
354 1.3 rillig b = flags & FLAG28;
355 1.3 rillig }
356 1.3 rillig
357 1.3 rillig /* A bool bit field is compatible with bool. Other bit fields are not. */
358 1.3 rillig
359 1.3 rillig struct flags {
360 1.3 rillig bool bool_flag: 1;
361 1.3 rillig unsigned uint_flag: 1;
362 1.3 rillig };
363 1.3 rillig
364 1.3 rillig void
365 1.3 rillig SB008_flags_from_bit_fields(const struct flags *flags)
366 1.2 rillig {
367 1.3 rillig bool b;
368 1.3 rillig
369 1.3 rillig b = flags->bool_flag; /* ok */
370 1.3 rillig b = flags->uint_flag; /* not ok */
371 1.3 rillig }
372 1.3 rillig
373 1.3 rillig /* Test implicit conversion when returning a value from a function. */
374 1.3 rillig
375 1.3 rillig bool
376 1.3 rillig returning_bool(bool b, int i, const char *p)
377 1.3 rillig {
378 1.3 rillig if (i > 0)
379 1.3 rillig return b; /* ok */
380 1.3 rillig if (i < 0)
381 1.3 rillig return i; /* not ok */
382 1.3 rillig return p; /* not ok */
383 1.3 rillig }
384 1.3 rillig
385 1.3 rillig char
386 1.3 rillig returning_char(bool b, int i, const char *p)
387 1.3 rillig {
388 1.3 rillig if (i > 0)
389 1.3 rillig return b; /* not ok */
390 1.3 rillig if (i < 0)
391 1.3 rillig return i; /* not ok, but not related to bool */
392 1.3 rillig return p; /* not ok */
393 1.3 rillig }
394 1.3 rillig
395 1.3 rillig /* Test passing arguments to a function. */
396 1.3 rillig
397 1.3 rillig extern void taking_arguments(bool, int, const char *, ...);
398 1.3 rillig
399 1.3 rillig void
400 1.3 rillig passing_arguments(bool b, int i, const char *p)
401 1.3 rillig {
402 1.3 rillig /* No conversion necessary. */
403 1.3 rillig taking_arguments(b, i, p);
404 1.3 rillig
405 1.3 rillig /* Implicitly converting bool to other scalar types. */
406 1.3 rillig taking_arguments(b, b, b);
407 1.3 rillig
408 1.3 rillig /* Implicitly converting int to bool (arg #1). */
409 1.3 rillig taking_arguments(i, i, i);
410 1.3 rillig
411 1.3 rillig /* Implicitly converting pointer to bool (arg #1). */
412 1.3 rillig taking_arguments(p, p, p);
413 1.3 rillig
414 1.3 rillig /* Passing bool as vararg. */
415 1.3 rillig taking_arguments(b, i, p, b, i, p);
416 1.2 rillig }
417