d_c99_bool_strict.c revision 1.2 1 1.2 rillig /* $NetBSD: d_c99_bool_strict.c,v 1.2 2021/01/10 21:45:50 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.1 rillig */
25 1.1 rillig
26 1.2 rillig // Not yet implemented: /* lint1-extra-flags: -T */
27 1.1 rillig
28 1.1 rillig /*
29 1.1 rillig * The header <stdbool.h> defines the macros bool = _Bool, false = 0 and
30 1.1 rillig * true = 1. Therefore, constant expressions of integer type have to be
31 1.1 rillig * regarded as possible boolean constants if their value is either 0 or 1.
32 1.1 rillig * At this point of the translation, the preprocessor has already removed
33 1.1 rillig * the words "false" and "true" from the source code.
34 1.1 rillig */
35 1.1 rillig
36 1.1 rillig /*
37 1.1 rillig * Using a typedef for bool does not hurt the checks, they all use the
38 1.1 rillig * underlying basic type (see tspec_t), which is BOOL.
39 1.1 rillig */
40 1.1 rillig typedef _Bool bool;
41 1.1 rillig
42 1.1 rillig void
43 1.1 rillig SB001_controlling_expression(bool b, int i, double d, const void *p)
44 1.1 rillig {
45 1.1 rillig
46 1.1 rillig /* Fine due to SB006. */
47 1.1 rillig if (/*CONSTCOND*/0)
48 1.1 rillig return;
49 1.1 rillig
50 1.1 rillig /* Fine due to SB006. */
51 1.1 rillig if (/*CONSTCOND*/1)
52 1.1 rillig return;
53 1.1 rillig
54 1.1 rillig /* Not allowed: 2 is not a boolean expression. */
55 1.1 rillig if (/*CONSTCOND*/2)
56 1.1 rillig return;
57 1.1 rillig
58 1.1 rillig /* Not allowed: There is no implicit conversion from scalar to bool. */
59 1.1 rillig if (i)
60 1.1 rillig return;
61 1.1 rillig if (i != 0)
62 1.1 rillig return;
63 1.1 rillig
64 1.1 rillig /* Not allowed: There is no implicit conversion from scalar to bool. */
65 1.1 rillig if (d)
66 1.1 rillig return;
67 1.1 rillig if (d != 0.0)
68 1.1 rillig return;
69 1.1 rillig
70 1.1 rillig /* Not allowed: There is no implicit conversion from scalar to bool. */
71 1.1 rillig if (p)
72 1.1 rillig return;
73 1.1 rillig if (p != (void *)0)
74 1.1 rillig return;
75 1.1 rillig
76 1.1 rillig /* Using a bool expression is allowed. */
77 1.1 rillig if (b)
78 1.1 rillig return;
79 1.1 rillig }
80 1.1 rillig
81 1.1 rillig void
82 1.1 rillig SB002_operator_result(bool b)
83 1.1 rillig {
84 1.1 rillig b = b;
85 1.1 rillig char c = b;
86 1.1 rillig int i = b;
87 1.1 rillig double d = b;
88 1.1 rillig void *p = b;
89 1.1 rillig
90 1.1 rillig /* These assignments are all ok. */
91 1.1 rillig b = !b;
92 1.1 rillig b = i == i;
93 1.1 rillig b = i != i;
94 1.1 rillig b = i < i;
95 1.1 rillig b = i <= i;
96 1.1 rillig b = i >= i;
97 1.1 rillig b = i > i;
98 1.1 rillig b = b && b;
99 1.1 rillig b = b || b;
100 1.1 rillig
101 1.1 rillig /*
102 1.1 rillig * These assignments are not ok, they implicitly convert from bool
103 1.1 rillig * to int.
104 1.1 rillig */
105 1.1 rillig i = !b;
106 1.1 rillig i = i == i;
107 1.1 rillig i = i != i;
108 1.1 rillig i = i < i;
109 1.1 rillig i = i <= i;
110 1.1 rillig i = i >= i;
111 1.1 rillig i = i > i;
112 1.1 rillig i = b && b;
113 1.1 rillig i = b || b;
114 1.1 rillig }
115 1.1 rillig
116 1.1 rillig void
117 1.1 rillig SB003_operands(bool b, int i)
118 1.1 rillig {
119 1.1 rillig
120 1.1 rillig /* These assignments are ok. */
121 1.1 rillig b = !b;
122 1.1 rillig b = b && b;
123 1.1 rillig b = b || b;
124 1.1 rillig
125 1.1 rillig /* These assignments implicitly convert from scalar to bool. */
126 1.1 rillig b = !i;
127 1.1 rillig b = i && i;
128 1.1 rillig b = i || i;
129 1.1 rillig }
130 1.1 rillig
131 1.1 rillig void
132 1.1 rillig SB004_non_bool_operands(bool b, unsigned u)
133 1.1 rillig {
134 1.1 rillig b = !b; /* ok */
135 1.1 rillig b = ~b; /* not ok */
136 1.1 rillig ++b; /* not ok */
137 1.1 rillig --b; /* not ok */
138 1.1 rillig b++; /* not ok */
139 1.1 rillig b--; /* not ok */
140 1.1 rillig b = +b; /* not ok */
141 1.1 rillig b = -b; /* not ok */
142 1.1 rillig
143 1.1 rillig b = b * b; /* not ok */
144 1.1 rillig b = b / b; /* not ok */
145 1.1 rillig b = b % b; /* not ok */
146 1.1 rillig b = b + b; /* not ok */
147 1.1 rillig b = b - b; /* not ok */
148 1.1 rillig b = b << b; /* not ok */
149 1.1 rillig b = b >> b; /* not ok */
150 1.1 rillig
151 1.1 rillig b = b < b; /* not ok */
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; /* ok */
156 1.1 rillig b = b != b; /* ok */
157 1.1 rillig
158 1.1 rillig b = b & b; /* ok */
159 1.1 rillig b = b ^ b; /* ok */
160 1.1 rillig b = b | b; /* ok */
161 1.1 rillig b = b && b; /* ok */
162 1.1 rillig b = b || b; /* ok */
163 1.1 rillig b = b ? b : b; /* ok */
164 1.1 rillig
165 1.1 rillig b = b; /* ok */
166 1.1 rillig b *= b; /* not ok */
167 1.1 rillig b /= b; /* not ok */
168 1.1 rillig b %= b; /* not ok */
169 1.1 rillig b += b; /* not ok */
170 1.1 rillig b -= b; /* not ok */
171 1.1 rillig b <<= b; /* not ok */
172 1.1 rillig b >>= b; /* not ok */
173 1.1 rillig b &= b; /* ok */
174 1.1 rillig b ^= b; /* ok */
175 1.1 rillig b |= b; /* ok */
176 1.1 rillig
177 1.1 rillig /* Operations with mixed types. */
178 1.1 rillig u = b * u; /* not ok */
179 1.1 rillig u = u * b; /* not ok */
180 1.1 rillig u = b / u; /* not ok */
181 1.1 rillig u = u / b; /* not ok */
182 1.1 rillig u = b % u; /* not ok */
183 1.1 rillig u = u % b; /* not ok */
184 1.1 rillig u = b + u; /* not ok */
185 1.1 rillig u = u + b; /* not ok */
186 1.1 rillig u = b - u; /* not ok */
187 1.1 rillig u = u - b; /* not ok */
188 1.1 rillig u = b << u; /* not ok */
189 1.1 rillig u = u << b; /* not ok */
190 1.1 rillig u = b >> u; /* not ok */
191 1.1 rillig u = u >> b; /* not ok */
192 1.1 rillig u = b ? u : u; /* ok */
193 1.1 rillig u = b ? b : u; /* not ok */
194 1.1 rillig u = b ? u : b; /* not ok */
195 1.1 rillig }
196 1.1 rillig
197 1.1 rillig void
198 1.1 rillig SB005_convert_from_bool_to_scalar(bool b)
199 1.1 rillig {
200 1.1 rillig int i;
201 1.1 rillig unsigned u;
202 1.1 rillig double d;
203 1.1 rillig void *p;
204 1.1 rillig
205 1.1 rillig i = b; /* not ok */
206 1.1 rillig u = b; /* not ok */
207 1.1 rillig d = b; /* not ok */
208 1.1 rillig p = b; /* not ok */
209 1.1 rillig }
210 1.1 rillig
211 1.1 rillig enum SB006_bool_constant_expression {
212 1.1 rillig /* Ok: 0 is a boolean constant expression. */
213 1.1 rillig INT0 = 0 ? 100 : 101,
214 1.1 rillig
215 1.1 rillig /* Ok: 1 is a boolean constant expression. */
216 1.1 rillig INT1 = 1 ? 100 : 101,
217 1.1 rillig
218 1.1 rillig /* Not ok: 2 is not a boolean constant (neither 0 nor 1). */
219 1.1 rillig INT2 = 2 ? 100 : 101,
220 1.1 rillig
221 1.1 rillig /*
222 1.1 rillig * Not ok: the intermediate expression "2 - 2" has return type
223 1.1 rillig * scalar, not bool. It is irrelevant that the final result
224 1.1 rillig * is 0, which would be a boolean constant.
225 1.1 rillig */
226 1.1 rillig ARITH = (2 - 2) ? 100 : 101,
227 1.1 rillig
228 1.1 rillig /*
229 1.1 rillig * Ok: The 13 and 12 are not boolean expressions, but they
230 1.1 rillig * are not in the calculation path that leads to the final
231 1.1 rillig * result. The important point is that the operator '>' has
232 1.1 rillig * return type bool.
233 1.1 rillig */
234 1.1 rillig Q1 = (13 > 12) ? 100 : 101,
235 1.1 rillig
236 1.1 rillig /*
237 1.1 rillig * Not ok: The 7 is irrelevant for the final result of the
238 1.1 rillig * expression, yet it turns the result type of the operator
239 1.1 rillig * '?:' to be int, not bool.
240 1.1 rillig */
241 1.1 rillig Q2 = (13 > 12 ? 1 : 7) ? 100 : 101,
242 1.1 rillig
243 1.1 rillig BINAND = 0 & 1, /* ok */
244 1.1 rillig
245 1.1 rillig BINXOR = 0 ^ 1, /* ok */
246 1.1 rillig
247 1.1 rillig BINOR = 0 | 1, /* ok */
248 1.1 rillig
249 1.1 rillig LOGOR = 0 || 1, /* ok */
250 1.1 rillig
251 1.1 rillig LOGAND = 0 && 1, /* ok */
252 1.1 rillig };
253 1.2 rillig
254 1.2 rillig enum BitSet {
255 1.2 rillig ONE = 1 << 0,
256 1.2 rillig TWO = 1 << 1,
257 1.2 rillig FOUR = 1 << 2
258 1.2 rillig };
259 1.2 rillig
260 1.2 rillig /*
261 1.2 rillig * It is debatable whether it is a good idea to allow expressions like these
262 1.2 rillig * for _Bool. The strict rules above ensure that the code works in the same
263 1.2 rillig * way whether or not the special rule C99 6.3.1.2 is active or not.
264 1.2 rillig *
265 1.2 rillig * If the code were to switch away from the C99 bool type to an ordinary
266 1.2 rillig * unsigned integer type, the behavior might silently change. Because the
267 1.2 rillig * rule C99 6.3.1.2 is no longer active in that case, high bits of the enum
268 1.2 rillig * constant may get lost, thus evaluating to false even though a bit is set.
269 1.2 rillig *
270 1.2 rillig * It's probably better to not allow this kind of expressions, even though
271 1.2 rillig * it may be popular, especially in usr.bin/make.
272 1.2 rillig */
273 1.2 rillig int
274 1.2 rillig S007_allow_flag_test_on_bit_set_enums(enum BitSet bs)
275 1.2 rillig {
276 1.2 rillig if (bs & ONE)
277 1.2 rillig return 1;
278 1.2 rillig if (!(bs & TWO))
279 1.2 rillig return 2;
280 1.2 rillig if (bs & FOUR)
281 1.2 rillig return 2;
282 1.2 rillig return 4;
283 1.2 rillig }
284