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