Home | History | Annotate | Line # | Download | only in lint1
d_c99_bool_strict.c revision 1.13
      1 /*	$NetBSD: d_c99_bool_strict.c,v 1.13 2021/01/17 11:32:06 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	no
     35  *	The other binary operators do not accept bool operands.
     36  *
     37  * strict-bool-operand-binary:
     38  *	Operator	left:	bool?	other?	right:	bool?	other?
     39  *	.			-	yes		yes	yes
     40  *	->			-	yes		yes	yes
     41  *	<=, <, >=, >		-	yes		-	yes
     42  *	==, !=			yes	yes		yes	yes
     43  *	&			yes	yes		yes	yes
     44  *	^			yes	yes		yes	yes
     45  *	|			yes	yes		yes	yes
     46  *	&&			yes	-		yes	-
     47  *	||			yes	-		yes	-
     48  *	?			yes	-		yes	yes
     49  *	:			yes	yes		yes	yes
     50  *	=			yes	yes		yes	yes
     51  *	&=, ^=, |=		yes	yes		yes	yes
     52  *	,			yes	yes		yes	yes
     53  *	The other binary operators do not accept bool operands.
     54  *
     55  * strict-bool-operator-result:
     56  *	The result type of the operators '!', '<', '<=', '>', '>=',
     57  *	'==', '!=', '&&', '||' is _Bool instead of int.
     58  *
     59  * strict-bool-bitwise-and:
     60  *	Expressions of the form "flags & FLAG" are compatible with _Bool if
     61  *	the left operand has enum type, the right operand is an integer
     62  *	constant and the resulting value is used in a context where it is
     63  *	implicitly and immediately compared to zero.
     64  *
     65  *	Note: An efficient implementation technique for a collection of bool
     66  *	flags is an enum.  The enum declaration groups the available
     67  *	constants, and as of 2020, compilers such as GCC and Clang have basic
     68  *	support for detecting type mismatches on enums.
     69  *
     70  *	Note: Examples for such contexts are controlling expressions or the
     71  *	operands of the operators '!', '&&', '||'.
     72  *
     73  *	Note: Counterexamples for contexts are assignments to a bool variable.
     74  *
     75  *	Note: These rules ensure that conforming code can be compiled without
     76  *	change in behavior using old compilers that implement bool as an
     77  *	ordinary integer type, without the special rule C99 6.3.1.2.
     78  *
     79  *	Note: There is a crucial difference between a _Bool variable and an
     80  *	ordinary integer variable.  C99 6.3.1.2 defines a conversion from an
     81  *	arbitrary scalar value to _Bool as equivalent to (value != 0 ? 1 : 0).
     82  *	This means that even if _Bool is implemented as an 8-bit unsigned
     83  *	integer, assigning 256 to it would still result in the value 1 being
     84  *	stored.  Storing 256 in an ordinary 8-bit unsigned integer would
     85  *	result in the value 0 being stored.  See the test d_c99_bool.c for
     86  *	more details.
     87  */
     88 
     89 /*
     90  * The header <stdbool.h> defines the macros bool = _Bool, false = 0 and
     91  * true = 1.  Without further hacks, this would mean that constant expressions
     92  * of integer type have to be regarded as possible boolean constants if their
     93  * value is either 0 or 1.
     94  *
     95  * This would not help in migrating old code to use bool consistently.
     96  * Therefore lint provides its own <stdbool.h> header that expands false to
     97  * __lint_false and true to __lint_true, two predefined constant expressions.
     98  */
     99 
    100 /* lint1-extra-flags: -T */
    101 
    102 /*
    103  * strict-bool-typedef
    104  */
    105 
    106 /*
    107  * Using a typedef for bool does not hurt the checks, they all use the
    108  * underlying basic type (see tspec_t), which is BOOL.
    109  */
    110 typedef _Bool bool;
    111 
    112 extern void accept_bool(bool);
    113 extern void println(const char *);
    114 extern void take_arguments(bool, int, const char *, ...);
    115 extern void do_nothing(void);
    116 
    117 /*
    118  * strict-bool-constant
    119  */
    120 
    121 void
    122 strict_bool_constant(void)
    123 {
    124 	accept_bool(__lint_false);
    125 	accept_bool(__lint_true);
    126 	accept_bool(0);		/* expect: 334 */
    127 	accept_bool(1);		/* expect: 334 */
    128 	accept_bool(2);		/* expect: 334 */
    129 }
    130 
    131 enum strict_bool_constant_expressions {
    132 	/* Ok: __lint_false is a boolean constant expression. */
    133 	FALSE = __lint_false ? 100 : 101,
    134 
    135 	/* Ok: __lint_true is a boolean constant expression. */
    136 	TRUE = __lint_true ? 100 : 101,
    137 
    138 	/* Not ok: an integer is not a boolean constant expression. */
    139 	INT0 = 0 ? 100 : 101,	/* expect: 331 */
    140 
    141 	/* Not ok: an integer is not a boolean constant expression. */
    142 	INT1 = 1 ? 100 : 101,	/* expect: 331 */
    143 
    144 	/* Not ok: 2 is not a boolean constant. */
    145 	INT2 = 2 ? 100 : 101,	/* expect: 331 */
    146 
    147 	/* Not ok: compound integer expressions are not bool. */
    148 	ARITH = (2 - 2) ? 100 : 101,	/* expect: 331 */
    149 
    150 	/*
    151 	 * Without strict bool mode, these two variants of an expression can
    152 	 * occur when a preprocessor macro is either defined to 1 or left
    153 	 * empty, as in lint1/ops.def.
    154 	 *
    155 	 * TODO: figure out an elegant way to achieve the same effect in
    156 	 *  strict bool mode.
    157 	 */
    158 	BINARY_PLUS = (1 + 0) ? 100 : 101, /* expect: 331 */
    159 	UNARY_PLUS = (+0) ? 100 : 101,	/* expect: 331 */
    160 
    161 	/* The main operator '>' has return type bool. */
    162 	Q1 = (13 > 12) ? 100 : 101,
    163 
    164 	/*
    165 	 * The parenthesized expression has type int and thus cannot be
    166 	 * used as the controlling expression in the '?:' operator.
    167 	 */
    168 	Q2 = (13 > 12 ? 1 : 7) ? 100 : 101,	/* expect: 331 */
    169 
    170 	BINAND_BOOL = __lint_false & __lint_true,
    171 	BINAND_INT = 0 & 1,
    172 
    173 	BINXOR_BOOL = __lint_false ^ __lint_true,
    174 	BINXOR_INT = 0 ^ 1,
    175 
    176 	BINOR_BOOL = __lint_false | __lint_true,
    177 	BINOR_INT = 0 | 1,
    178 
    179 	LOGOR_BOOL = __lint_false || __lint_true,
    180 	LOGOR_INT = 0 || 1,	/* expect: 331, 332 */
    181 
    182 	LOGAND_BOOL = __lint_false && __lint_true,
    183 	LOGAND_INT = 0 && 1,	/* expect: 331, 332 */
    184 };
    185 
    186 /*
    187  * strict-bool-bit-fields
    188  */
    189 
    190 void
    191 strict_bool_bit_fields(void)
    192 {
    193 	struct flags {
    194 		bool bool_flag: 1;
    195 		unsigned uint_flag: 1;
    196 	};
    197 
    198 	struct flags flags = { __lint_false, 0 };
    199 	struct flags *flags_ptr = &flags;
    200 	bool b;
    201 
    202 	b = flags.bool_flag;
    203 	b = flags.uint_flag;		/* expect: 107 */
    204 	flags.bool_flag = b;
    205 	flags.uint_flag = b;		/* expect: 107 */
    206 
    207 	b = flags_ptr->bool_flag;
    208 	b = flags_ptr->uint_flag;	/* expect: 107 */
    209 	flags_ptr->bool_flag = b;
    210 	flags_ptr->uint_flag = b;	/* expect: 107 */
    211 }
    212 
    213 void
    214 strict_bool_bit_fields_operand_conversion(void)
    215 {
    216 	struct s {
    217 		bool ordinary;
    218 		bool bit_field: 1;
    219 	};
    220 
    221 	struct s s = { 0 };
    222 
    223 	s.ordinary = s.ordinary | s.ordinary;
    224 	s.bit_field = s.bit_field | s.bit_field; /* FIXME *//* expect: 107 */
    225 }
    226 
    227 /*
    228  * strict-bool-conversion
    229  */
    230 
    231 bool
    232 strict_bool_conversion_return_false(void)
    233 {
    234 	return __lint_false;
    235 }
    236 
    237 bool
    238 strict_bool_conversion_return_true(void)
    239 {
    240 	return __lint_true;
    241 }
    242 
    243 bool
    244 strict_bool_conversion_return_bool(bool b)
    245 {
    246 	return b;
    247 }
    248 
    249 bool
    250 strict_bool_conversion_return_0(void)
    251 {
    252 	return 0;		/* expect: 211 */
    253 }
    254 
    255 bool
    256 strict_bool_conversion_return_1(void)
    257 {
    258 	return 1;		/* expect: 211 */
    259 }
    260 
    261 bool
    262 strict_bool_conversion_return_2(void)
    263 {
    264 	return 2;		/* expect: 211 */
    265 }
    266 
    267 bool
    268 strict_bool_conversion_return_pointer(const void *p) /* expect: 231 */
    269 {
    270 	return p;		/* expect: 211 */
    271 }
    272 
    273 char
    274 strict_bool_conversion_return_false_as_char(void)
    275 {
    276 	return __lint_false;	/* expect: 211 */
    277 }
    278 
    279 char
    280 strict_bool_conversion_return_true_as_char(void)
    281 {
    282 	return __lint_true;	/* expect: 211 */
    283 }
    284 
    285 
    286 void
    287 strict_bool_conversion_function_argument(void)
    288 {
    289 	accept_bool(__lint_false);
    290 	accept_bool(__lint_true);
    291 }
    292 
    293 void
    294 strict_bool_conversion_function_argument_pass(bool b, int i, const char *p)
    295 {
    296 	/* No conversion necessary. */
    297 	take_arguments(b, i, p);
    298 
    299 	/* Implicitly converting bool to other scalar types. */
    300 	take_arguments(b, b, b);	/* expect: 334, 334 */
    301 
    302 	/* Implicitly converting int to bool (arg #1). */
    303 	take_arguments(i, i, i);	/* expect: 334, 154 */
    304 
    305 	/* Implicitly converting pointer to bool (arg #1). */
    306 	take_arguments(p, p, p);	/* expect: 334, 154 */
    307 
    308 	/* Passing bool as vararg. */
    309 	take_arguments(b, i, p, b, i, p); /* expect: arg#4 */ // TODO
    310 
    311 	/* Passing a bool constant. */
    312 	take_arguments(__lint_false, i, p);
    313 
    314 	/* Passing a bool constant. */
    315 	take_arguments(__lint_true, i, p);
    316 
    317 	/* Trying to pass integer constants. */
    318 	take_arguments(0, i, p);	/* expect: 334 */
    319 	take_arguments(1, i, p);	/* expect: 334 */
    320 	take_arguments(2, i, p);	/* expect: 334 */
    321 }
    322 
    323 void
    324 strict_bool_conversion_between_bool_and_int(void)
    325 {
    326 	bool b;
    327 	int i;
    328 
    329 	b = 0;			/* expect: 107 */
    330 	b = __lint_false;
    331 	b = 1;			/* expect: 107 */
    332 	b = __lint_true;
    333 
    334 	i = 0;
    335 	i = __lint_false;	/* expect: 107 */
    336 	i = 1;
    337 	i = __lint_true;	/* expect: 107 */
    338 
    339 	i = b;			/* expect: 107 */
    340 	b = i;			/* expect: 107 */
    341 }
    342 
    343 void
    344 strict_bool_conversion_from_bool_to_scalar(bool b) /* expect: 231 */
    345 {
    346 	int i;
    347 	unsigned u;
    348 	double d;
    349 	void *p;
    350 
    351 	i = b;			/* expect: 107 */
    352 	u = b;			/* expect: 107 */
    353 	d = b;			/* expect: 107 */
    354 	p = b;			/* expect: 107 */
    355 }
    356 
    357 /*
    358  * strict-bool-controlling-expression:
    359  *	Controlling expressions in 'if', 'while', 'for', '?:' must be of
    360  *	type bool.
    361  */
    362 
    363 void
    364 strict_bool_controlling_expression(bool b, int i, double d, const void *p)
    365 {
    366 	if (__lint_false)
    367 		do_nothing();
    368 
    369 	if (__lint_true)
    370 		do_nothing();
    371 
    372 	if (b)
    373 		do_nothing();
    374 
    375 	if (0)			/* expect: 333 */
    376 		do_nothing();
    377 
    378 	if (1)			/* expect: 333 */
    379 		do_nothing();
    380 
    381 	if (2)			/* expect: 333 */
    382 		do_nothing();
    383 
    384 	/* Not allowed: There is no implicit conversion from scalar to bool. */
    385 	if (i)			/* expect: 333 */
    386 		do_nothing();
    387 	if (i != 0)
    388 		do_nothing();
    389 
    390 	/* Not allowed: There is no implicit conversion from scalar to bool. */
    391 	if (d)			/* expect: 333 */
    392 		do_nothing();
    393 	if (d != 0.0)
    394 		do_nothing();
    395 
    396 	/* Not allowed: There is no implicit conversion from scalar to bool. */
    397 	if (p)			/* expect: 333 */
    398 		do_nothing();
    399 	if (p != (void *)0)
    400 		do_nothing();
    401 }
    402 
    403 /*
    404  * strict-bool-operand-unary:
    405  *	Operator	bool?	scalar?
    406  *	!		yes	-
    407  *	&		yes	yes
    408  *	The other binary operators do not accept bool operands.
    409  */
    410 
    411 void
    412 strict_bool_operand_unary_not(void)
    413 {
    414 	bool b = __lint_false;
    415 
    416 	b = !b;
    417 	b = !!!b;
    418 	b = !__lint_false;
    419 	b = !__lint_true;
    420 
    421 	int i = 0;
    422 
    423 	i = !i;			/* expect: 330 */
    424 	i = !!!i;		/* expect: 330 */
    425 	i = !0;			/* expect: 330 */
    426 	i = !1;			/* expect: 330 */
    427 }
    428 
    429 void
    430 strict_bool_operand_unary_address(void)
    431 {
    432 	bool b = __lint_false;
    433 
    434 	/* Taking the address of a bool lvalue. */
    435 	bool *bp;
    436 	bp = &b;
    437 	*bp = b;
    438 	b = *bp;
    439 }
    440 
    441 /*
    442  * strict-bool-operand-binary:
    443  *	Operator	left:	bool?	other?	right:	bool?	other?
    444  *	.			-	yes		yes	yes
    445  *	->			-	yes		yes	yes
    446  *	<=, <, >=, >		-	yes		-	yes
    447  *	==, !=			yes	yes		yes	yes
    448  *	&			yes	yes		yes	yes
    449  *	^			yes	yes		yes	yes
    450  *	|			yes	yes		yes	yes
    451  *	&&			yes	-		yes	-
    452  *	||			yes	-		yes	-
    453  *	?			yes	-		yes	yes
    454  *	:			yes	yes		yes	yes
    455  *	=			yes	yes		yes	yes
    456  *	&=, ^=, |=		yes	yes		yes	yes
    457  *	,			yes	yes		yes	yes
    458  *	The other binary operators do not accept bool operands.
    459  */
    460 
    461 /*
    462  * Ensure that bool members can be accessed as usual.
    463  */
    464 void
    465 strict_bool_operand_binary_dot_arrow(void)
    466 {
    467 	struct bool_struct {
    468 		bool b;
    469 	};
    470 
    471 	/* Initialize and assign using boolean constants. */
    472 	bool b = __lint_false;
    473 	b = __lint_true;
    474 
    475 	/* Access a struct member using the '.' operator. */
    476 	struct bool_struct bs = { __lint_true };
    477 	b = bs.b;
    478 	bs.b = b;
    479 	bs.b = 0;		/* expect: 107 */
    480 
    481 	/* Access a struct member using the '->' operator. */
    482 	struct bool_struct *bsp = &bs;
    483 	b = bsp->b;
    484 	bsp->b = b;
    485 	bsp->b = 0;		/* expect: 107 */
    486 }
    487 
    488 int
    489 strict_bool_operand_binary(bool b, int i)
    490 {
    491 
    492 	/* The right-hand sides of these assignments are ok. */
    493 	b = !b;
    494 	b = b && b;
    495 	b = b || b;
    496 
    497 	/*
    498 	 * The right-hand sides of these assignments implicitly convert from
    499 	 * scalar to bool.
    500 	 */
    501 	b = !i;			/* expect: 330 */
    502 	b = i && i;		/* expect: 331, 332 */
    503 	b = i || i;		/* expect: 331, 332 */
    504 
    505 	b = b && 0;		/* expect: 332 */
    506 	b = 0 && b;		/* expect: 331 */
    507 	b = b || 0;		/* expect: 332 */
    508 	b = 0 || b;		/* expect: 331 */
    509 
    510 	return i;
    511 }
    512 
    513 void
    514 strict_bool_operand_binary_all(bool b, unsigned u)
    515 {
    516 	b = !b;
    517 	b = ~b;			/* expect: 335 */
    518 	++b;			/* expect: 335 */
    519 	--b;			/* expect: 335 */
    520 	b++;			/* expect: 335 */
    521 	b--;			/* expect: 335 */
    522 	b = +b;			/* expect: 335 */
    523 	b = -b;			/* expect: 335 */
    524 
    525 	b = b * b;		/* expect: 336, 337 */
    526 	b = b / b;		/* expect: 336, 337 */
    527 	b = b % b;		/* expect: 336, 337 */
    528 	b = b + b;		/* expect: 336, 337 */
    529 	b = b - b;		/* expect: 336, 337 */
    530 	b = b << b;		/* expect: 336, 337 */
    531 	b = b >> b;		/* expect: 336, 337 */
    532 
    533 	b = b < b;		/* expect: 336, 337 */
    534 	b = b <= b;		/* expect: 336, 337 */
    535 	b = b > b;		/* expect: 336, 337 */
    536 	b = b >= b;		/* expect: 336, 337 */
    537 	b = b == b;
    538 	b = b != b;
    539 
    540 	b = b & b;
    541 	b = b ^ b;
    542 	b = b | b;
    543 	b = b && b;
    544 	b = b || b;
    545 	b = b ? b : b;
    546 
    547 	b = b;
    548 	b *= b;			/* expect: 336, 337 */
    549 	b /= b;			/* expect: 336, 337 */
    550 	b %= b;			/* expect: 336, 337 */
    551 	b += b;			/* expect: 336, 337 */
    552 	b -= b;			/* expect: 336, 337 */
    553 	b <<= b;		/* expect: 336, 337 */
    554 	b >>= b;		/* expect: 336, 337 */
    555 	b &= b;
    556 	b ^= b;
    557 	b |= b;
    558 
    559 	/* Operations with mixed types. */
    560 	u = b * u;		/* expect: 336 */
    561 	u = u * b;		/* expect: 337 */
    562 	u = b / u;		/* expect: 336 */
    563 	u = u / b;		/* expect: 337 */
    564 	u = b % u;		/* expect: 336 */
    565 	u = u % b;		/* expect: 337 */
    566 	u = b + u;		/* expect: 336 */
    567 	u = u + b;		/* expect: 337 */
    568 	u = b - u;		/* expect: 336 */
    569 	u = u - b;		/* expect: 337 */
    570 	u = b << u;		/* expect: 336 */
    571 	u = u << b;		/* expect: 337 */
    572 	u = b >> u;		/* expect: 336 */
    573 	u = u >> b;		/* expect: 337 */
    574 	u = b ? u : u;
    575 	u = b ? b : u;		/* expect: 107 */
    576 	u = b ? u : b;		/* expect: 107 */
    577 }
    578 
    579 bool
    580 strict_bool_operand_binary_comma(bool b, int i)
    581 {
    582 	b = (b, !b);
    583 	i = (i, i + 1);
    584 	return b;
    585 }
    586 
    587 /*
    588  * strict-bool-operator-result:
    589  *	The result type of the operators '!', '<', '<=', '>', '>=',
    590  *	'==', '!=', '&&', '||' is _Bool instead of int.
    591  */
    592 
    593 void
    594 strict_bool_operator_result(bool b)
    595 {
    596 	char c = b;		/* expect: 107 */
    597 	int i = b;		/* expect: 107 */
    598 	double d = b;		/* expect: 107 */
    599 	void *p = b;		/* expect: 107 */
    600 
    601 	/* The right-hand sides of these assignments are all ok. */
    602 	b = !b;
    603 	b = i == i;
    604 	b = i != i;
    605 	b = i < i;
    606 	b = i <= i;
    607 	b = i >= i;
    608 	b = i > i;
    609 	b = b && b;
    610 	b = b || b;
    611 
    612 	/*
    613 	 * The right-hand sides of these assignments are not ok, they
    614 	 * implicitly convert from bool to int.
    615 	 */
    616 	i = !b;			/* expect: 107 */
    617 	i = i == i;		/* expect: 107 */
    618 	i = i != i;		/* expect: 107 */
    619 	i = i < i;		/* expect: 107 */
    620 	i = i <= i;		/* expect: 107 */
    621 	i = i >= i;		/* expect: 107 */
    622 	i = i > i;		/* expect: 107 */
    623 	i = b && b;		/* expect: 107 */
    624 	i = b || b;		/* expect: 107 */
    625 }
    626 
    627 
    628 /*
    629  * strict-bool-bitwise-and:
    630  *	Expressions of the form "flags & FLAG" are compatible with _Bool if
    631  *	the left operand has enum type, the right operand is an integer
    632  *	constant and the resulting value is used in a context where it is
    633  *	implicitly and immediately compared to zero.
    634  *
    635  *	Note: Examples for such contexts are controlling expressions or the
    636  *	operands of the operators '!', '&&', '||'.
    637  *
    638  *	Note: Counterexamples for contexts are assignments to a bool variable.
    639  *
    640  *	Note: These rules ensure that conforming code can be compiled without
    641  *	change in behavior using old compilers that implement bool as an
    642  *	ordinary integer type, without the special rule C99 6.3.1.2.
    643  */
    644 
    645 enum Flags {
    646 	FLAG0 = 1 << 0,
    647 	FLAG1 = 1 << 1,
    648 	FLAG28 = 1 << 28
    649 };
    650 
    651 void
    652 strict_bool_bitwise_and_enum(enum Flags flags) /* expect: 231 */
    653 {
    654 	bool b;
    655 
    656 	/*
    657 	 * FLAG0 has the value 1 and thus can be stored in a bool variable
    658 	 * without truncation.  Nevertheless this special case is not allowed
    659 	 * because it would be too confusing if FLAG0 would work and all the
    660 	 * other flags wouldn't.
    661 	 */
    662 	b = flags & FLAG0;	/* expect: 107 */
    663 
    664 	/*
    665 	 * Assuming that FLAG1 is set in flags, a _Bool variable stores this
    666 	 * as 1, as defined by C99 6.3.1.2.  A uint8_t variable would store
    667 	 * it as 2, as that is the integer value of FLAG1.  Since FLAG1 fits
    668 	 * in a uint8_t, no truncation takes place.
    669 	 */
    670 	b = flags & FLAG1;	/* expect: 107 */
    671 
    672 	/*
    673 	 * In a _Bool variable, FLAG28 is stored as 1, since it is unequal to
    674 	 * zero.  In a uint8_t, the stored value would be 0 since bit 28 is
    675 	 * out of range for a uint8_t and thus gets truncated.
    676 	 */
    677 	b = flags & FLAG28;	/* expect: 107 */
    678 }
    679 
    680 /*
    681  * Demonstrate idiomatic code to query flags from an enum bit set.
    682  *
    683  * In all the controlling expressions in this function, the result of the
    684  * operator '&' is compared against 0.  This makes this pattern work, no
    685  * matter whether the bits are in the low-value range or in the high-value
    686  * range (such as FLAG28, which has the value 1073741824, which is more than
    687  * what would fit into an unsigned char).  Even if an enum could be extended
    688  * to larger types than int, this pattern would work.
    689  */
    690 void
    691 query_flag_from_enum_bit_set(enum Flags flags)
    692 {
    693 	if (flags & FLAG0)
    694 		println("FLAG0 is set");
    695 
    696 	if ((flags & FLAG1) != 0)
    697 		println("FLAG1 is set");
    698 
    699 	if ((flags & (FLAG0 | FLAG1)) == (FLAG0 | FLAG1))
    700 		println("FLAG0 and FLAG1 are both set");
    701 
    702 	if (flags & FLAG0 && flags & FLAG1)
    703 		println("FLAG0 and FLAG1 are both set");
    704 
    705 	if ((flags & (FLAG0 | FLAG1)) != 0)
    706 		println("At least one of FLAG0 and FLAG1 is set");
    707 
    708 	if (flags & FLAG28)
    709 		println("FLAG28 is set");
    710 }
    711 
    712 
    713 void
    714 strict_bool_operator_eq_bool_int(void)
    715 {
    716 	(void)(strict_bool_conversion_return_false() == 0); /* expect: 107 */
    717 }
    718 
    719 void
    720 strict_bool_assign_bit_field_then_compare(void)
    721 {
    722 	struct s {
    723 		bool flag: 1;
    724 	};
    725 
    726 	struct s s = { __lint_false };
    727 
    728 	/* FIXME: The __lint_false is converted irreversibly to an INT. */
    729 	(void)((s.flag = s.flag) != __lint_false); /* expect: 107 */
    730 }
    731