Module Name:    src
Committed By:   rillig
Date:           Sat Jan 16 15:02:12 UTC 2021

Modified Files:
        src/tests/usr.bin/xlint: check-expect.lua
        src/tests/usr.bin/xlint/lint1: d_c99_bool_strict.c
            d_c99_bool_strict.exp
        src/usr.bin/xlint/lint1: tree.c

Log Message:
lint: prepare to make strict bool mode even stricter

Currently, strict bool mode still allows integer constant expressions to
be converted implicitly to bool.  This is something that other languages
such as Go, Java, C#, Pascal don't allow.

By providing a custom implementation of <stdbool.h> that defines false
and true to custom bool constant identifiers, lint will cover these
cases as well.

To prepare for this, reword the rules and restructure the tests in
d_c99_bool_strict.c.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/tests/usr.bin/xlint/check-expect.lua
cvs rdiff -u -r1.7 -r1.8 src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c
cvs rdiff -u -r1.6 -r1.7 src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.exp
cvs rdiff -u -r1.154 -r1.155 src/usr.bin/xlint/lint1/tree.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/tests/usr.bin/xlint/check-expect.lua
diff -u src/tests/usr.bin/xlint/check-expect.lua:1.1 src/tests/usr.bin/xlint/check-expect.lua:1.2
--- src/tests/usr.bin/xlint/check-expect.lua:1.1	Tue Jan 12 20:42:01 2021
+++ src/tests/usr.bin/xlint/check-expect.lua	Sat Jan 16 15:02:11 2021
@@ -1,5 +1,5 @@
 #!  /usr/bin/lua
--- $NetBSD: check-expect.lua,v 1.1 2021/01/12 20:42:01 rillig Exp $
+-- $NetBSD: check-expect.lua,v 1.2 2021/01/16 15:02:11 rillig Exp $
 
 --[[
 
@@ -99,8 +99,8 @@ local function check_test(c_fname, error
     end
 
     if not found then
-      errors:add("error: %s:%d: message \"%s\" is not declared in %s:%d",
-        exp_fname, act.exp_lineno, act.msg, c_fname, act.c_lineno)
+      errors:add("error: %s:%d: must expect \"%s\"",
+        c_fname, act.c_lineno, act.msg)
     end
   end
 

Index: src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c
diff -u src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c:1.7 src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c:1.8
--- src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c:1.7	Fri Jan 15 23:15:28 2021
+++ src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c	Sat Jan 16 15:02:11 2021
@@ -1,45 +1,106 @@
-/*	$NetBSD: d_c99_bool_strict.c,v 1.7 2021/01/15 23:15:28 rillig Exp $	*/
+/*	$NetBSD: d_c99_bool_strict.c,v 1.8 2021/01/16 15:02:11 rillig Exp $	*/
 # 3 "d_c99_bool_strict.c"
 
 /*
  * The option -T treats _Bool as incompatible with all other scalar types.
- * This means:
+ * This is implemented by the following rules:
  *
- * SB001: Controlling expressions in 'if', 'while', 'for', '?:' must be of
- * type _Bool instead of scalar.
+ * strict-bool-typedef:
+ *	The type _Bool is compatible with any typedef of _Bool.
  *
- * SB002: The operators '!', '==', '!=', '<', '<=', '>=', '>', '&&', '||'
- * return _Bool instead of int.
+ *	Note: Since <stdbool.h> defines bool as textual alias of _Bool,
+ *	having another typedef for bool is unusual.
  *
- * SB003: The operators '!', '&&', '||' take _Bool instead of scalar.
+ * strict-bool-constant:
+ *	There are 2 bool constants named false and true.
+ *	No other constants are compatible with type _Bool.
  *
- * SB004: The only operators that take _Bool are '!', '==', '!=',
- * '&', '^', '|', '&&', '||', '?', ':', '=', '&=', '^=', '|='.
+ *	Note: Internally these constants are named __lint_false and
+ *	__lint_true.
  *
- * SB005: There is no implicit conversion from _Bool to any other type.
+ * strict-bool-bit-field:
+ *	A struct or union member that is a bit field with underlying type
+ *	bool is compatible with plain bool.
  *
- * SB006: An expression is compatible with type _Bool if its main operator
- * returns type _Bool, or if the expression is an integer constant expression
- * with value 0 or 1.
+ * strict-bool-conversion:
+ *	There is no implicit conversion between _Bool and any other type.
  *
- * SB007: Expressions like "flags & FLAG" are compatible with _Bool if
- * they appear in a context where they are immediately compared to zero.
- * Assigning to a _Bool variable does not count as such a context, to
- * allow programs to be compiled without silent changes on a compiler that
- * is lacking the special _Bool type.
+ * strict-bool-controlling-expression:
+ *	Controlling expressions in 'if', 'while', 'for', '?:' must be of
+ *	type bool.
  *
- * SB008: Bit fields in struct may be based on _Bool.  These bit fields
- * typically have type _Bool:1 and can be converted to _Bool and back.
+ * strict-bool-operand-unary:
+ *	Operator	bool?	scalar?
+ *	!		yes	no
+ *	The other binary operators do not accept bool operands.
+ *
+ * strict-bool-operand-binary:
+ *	Operator	left:	bool?	other?	right:	bool?	other?
+ *	.			-	yes		yes	yes
+ *	->			-	yes		yes	yes
+ *	<=, <, >=, >		yes	yes		yes	yes
+ *	==, !=			yes	yes		yes	yes
+ *	&			yes	yes		yes	yes
+ *	^			yes	yes		yes	yes
+ *	|			yes	yes		yes	yes
+ *	&&			yes	-		yes	-
+ *	||			yes	-		yes	-
+ *	?			yes	-		yes	yes
+ *	:			yes	yes		yes	yes
+ *	=			yes	yes		yes	yes
+ *	&=, ^=, |=		yes	yes		yes	yes
+ *	,			yes	yes		yes	yes
+ *	The other binary operators do not accept bool operands.
+ *
+ * strict-bool-operator-result:
+ *	The result type of the operators '!', '<', '<=', '>', '>=',
+ *	'==', '!=', '&&', '||' is _Bool instead of int.
+ *
+ * strict-bool-bitwise-and:
+ *	Expressions of the form "flags & FLAG" are compatible with _Bool if
+ *	the left operand has enum type, the right operand is an integer
+ *	constant and the resulting value is used in a context where it is
+ *	implicitly and immediately compared to zero.
+ *
+ *	Note: An efficient implementation technique for a collection of bool
+ *	flags is an enum.  The enum declaration groups the available
+ *	constants, and as of 2020, compilers such as GCC and Clang have basic
+ *	support for detecting type mismatches on enums.
+ *
+ *	Note: Examples for such contexts are controlling expressions or the
+ *	operands of the operators '!', '&&', '||'.
+ *
+ *	Note: Counterexamples for contexts are assignments to a bool variable.
+ *
+ *	Note: These rules ensure that conforming code can be compiled without
+ *	change in behavior using old compilers that implement bool as an
+ *	ordinary integer type, without the special rule C99 6.3.1.2.
+ *
+ *	Note: There is a crucial difference between a _Bool variable and an
+ *	ordinary integer variable.  C99 6.3.1.2 defines a conversion from an
+ *	arbitrary scalar value to _Bool as equivalent to (value != 0 ? 1 : 0).
+ *	This means that even if _Bool is implemented as an 8-bit unsigned
+ *	integer, assigning 256 to it would still result in the value 1 being
+ *	stored.  Storing 256 in an ordinary 8-bit unsigned integer would
+ *	result in the value 0 being stored.  See the test d_c99_bool.c for
+ *	more details.
+ */
+
+/*
+ * The header <stdbool.h> defines the macros bool = _Bool, false = 0 and
+ * true = 1.  Without further hacks, this would mean that constant expressions
+ * of integer type have to be regarded as possible boolean constants if their
+ * value is either 0 or 1.
+ *
+ * This would not help in migrating old code to use bool consistently.
+ * Therefore lint provides its own <stdbool.h> header that expands false to
+ * __lint_false and true to __lint_true, two predefined constant expressions.
  */
 
 /* lint1-extra-flags: -T */
 
 /*
- * The header <stdbool.h> defines the macros bool = _Bool, false = 0 and
- * true = 1.  Therefore, constant expressions of integer type have to be
- * regarded as possible boolean constants if their value is either 0 or 1.
- * At this point of the translation, the preprocessor has already removed
- * the words "false" and "true" from the source code.
+ * strict-bool-typedef
  */
 
 /*
@@ -48,82 +109,384 @@
  */
 typedef _Bool bool;
 
+extern void accept_bool(bool);
+extern void println(const char *);
+extern void take_arguments(bool, int, const char *, ...);
+extern void do_nothing(void);
+
+/*
+ * strict-bool-constant
+ */
+
+void
+strict_bool_constant(void)
+{
+	accept_bool(__lint_false);
+	accept_bool(__lint_true);
+	accept_bool(0);		/* TODO: expect: 334 */
+	accept_bool(1);		/* TODO: expect: 334 */
+	accept_bool(2);		/* expect: 334 */
+}
+
+enum strict_bool_constant_expressions {
+	/* Ok: __lint_false is a boolean constant expression. */
+	FALSE = __lint_false ? 100 : 101,
+
+	/* Ok: __lint_true is a boolean constant expression. */
+	TRUE = __lint_true ? 100 : 101,
+
+	/* Not ok: an integer is not a boolean constant expression. */
+	INT0 = 0 ? 100 : 101,	/* TODO: expect: 331 */
+
+	/* Not ok: an integer is not a boolean constant expression. */
+	INT1 = 1 ? 100 : 101,	/* TODO: expect: 331 */
+
+	/* Not ok: 2 is not a boolean constant. */
+	INT2 = 2 ? 100 : 101,	/* expect: 331 */
+
+	/* Not ok: compound integer expressions are not bool. */
+	ARITH = (2 - 2) ? 100 : 101,	/* TODO: expect: 331 */
+
+	/*
+	 * Without strict bool mode, these two variants of an expression can
+	 * occur when a preprocessor macro is either defined to 1 or left
+	 * empty, as in lint1/ops.def.
+	 *
+	 * TODO: figure out an elegant way to achieve the same effect in
+	 *  strict bool mode.
+	 */
+	BINARY_PLUS = (1 + 0) ? 100 : 101, /* TODO: expect: 331 */
+	UNARY_PLUS = (+0) ? 100 : 101,	/* TODO: expect: 331 */
+
+	/* The main operator '>' has return type bool. */
+	Q1 = (13 > 12) ? 100 : 101,
+
+	/*
+	 * The parenthesized expression has type int and thus cannot be
+	 * used as the controlling expression in the '?:' operator.
+	 */
+	Q2 = (13 > 12 ? 1 : 7) ? 100 : 101,
+
+	BINAND_BOOL = __lint_false & __lint_true,
+	BINAND_INT = 0 & 1,
+
+	BINXOR_BOOL = __lint_false ^ __lint_true,
+	BINXOR_INT = 0 ^ 1,
+
+	BINOR_BOOL = __lint_false | __lint_true,
+	BINOR_INT = 0 | 1,
+
+	LOGOR_BOOL = __lint_false || __lint_true,
+	LOGOR_INT = 0 || 1,	/* TODO: expect: 331, 332 */
+
+	LOGAND_BOOL = __lint_false && __lint_true,
+	LOGAND_INT = 0 && 1,	/* TODO: expect: 331, 332 */
+};
+
+/*
+ * strict-bool-bit-fields
+ */
+
+void
+strict_bool_bit_fields(void)
+{
+	struct flags {
+		bool bool_flag: 1;
+		unsigned uint_flag: 1;
+	};
+
+	struct flags flags = { __lint_false, 0 };
+	struct flags *flags_ptr = &flags;
+	bool b;
+
+	b = flags.bool_flag;
+	b = flags.uint_flag;		/* expect: 107 */
+	flags.bool_flag = b;
+	flags.uint_flag = b;		/* expect: 107 */
+
+	b = flags_ptr->bool_flag;
+	b = flags_ptr->uint_flag;	/* expect: 107 */
+	flags_ptr->bool_flag = b;
+	flags_ptr->uint_flag = b;	/* expect: 107 */
+}
+
+void
+strict_bool_bit_fields_operand_conversion(void)
+{
+	struct s {
+		bool ordinary;
+		bool bit_field: 1;
+	};
+
+	struct s s = { 0 };
+
+	s.ordinary = s.ordinary | s.ordinary;
+	s.bit_field = s.bit_field | s.bit_field; /* FIXME *//* expect: 107 */
+}
+
+/*
+ * strict-bool-conversion
+ */
+
+bool
+strict_bool_conversion_return_false(void)
+{
+	return __lint_false;
+}
+
+bool
+strict_bool_conversion_return_true(void)
+{
+	return __lint_true;
+}
+
+bool
+strict_bool_conversion_return_bool(bool b)
+{
+	return b;
+}
+
+bool
+strict_bool_conversion_return_0(void)
+{
+	return 0;		/* TODO: expect: 211 */
+}
+
+bool
+strict_bool_conversion_return_1(void)
+{
+	return 1;		/* TODO: expect: 211 */
+}
+
+bool
+strict_bool_conversion_return_2(void)
+{
+	return 2;		/* expect: 211 */
+}
+
+bool
+strict_bool_conversion_return_pointer(const void *p) /* expect: 231 */
+{
+	return p;		/* expect: 211 */
+}
+
+char
+strict_bool_conversion_return_false_as_char(void)
+{
+	return __lint_false;	/* expect: 211 */
+}
+
+char
+strict_bool_conversion_return_true_as_char(void)
+{
+	return __lint_true;	/* expect: 211 */
+}
+
+
 void
-SB001_controlling_expression(bool b, int i, double d, const void *p)
+strict_bool_conversion_function_argument(void)
 {
+	accept_bool(__lint_false);
+	accept_bool(__lint_true);
+}
+
+void
+strict_bool_conversion_function_argument_pass(bool b, int i, const char *p)
+{
+	/* No conversion necessary. */
+	take_arguments(b, i, p);
+
+	/* Implicitly converting bool to other scalar types. */
+	take_arguments(b, b, b);	/* expect: 334, 334 */
+
+	/* Implicitly converting int to bool (arg #1). */
+	take_arguments(i, i, i);	/* expect: 334, 154 */
+
+	/* Implicitly converting pointer to bool (arg #1). */
+	take_arguments(p, p, p);	/* expect: 334, 154 */
+
+	/* Passing bool as vararg. */
+	take_arguments(b, i, p, b, i, p); /* expect: arg#4 */ // TODO
+
+	/* Passing a bool constant. */
+	take_arguments(__lint_false, i, p);
+
+	/* Passing a bool constant. */
+	take_arguments(__lint_true, i, p);
+
+	/* Trying to pass integer constants. */
+	take_arguments(0, i, p);	/* TODO: expect: 334 */
+	take_arguments(1, i, p);	/* TODO: expect: 334 */
+	take_arguments(2, i, p);	/* expect: 334 */
+}
 
-	/* Fine due to SB006. */
-	if (/*CONSTCOND*/0)
-		return;
+void
+strict_bool_conversion_between_bool_and_int(void)
+{
+	bool b;
+	int i;
 
-	/* Fine due to SB006. */
-	if (/*CONSTCOND*/1)
-		return;
+	b = 0;
+	b = __lint_false;	/* TODO: expect: 107 */
+	b = 1;
+	b = __lint_true;
 
-	/* Not allowed: 2 is not a boolean expression. */
-	if (/*CONSTCOND*/2)	/* expect: 333 */
-		return;
+	i = 0;
+	i = __lint_false;	/* expect: 107 */
+	i = 1;
+	i = __lint_true;	/* expect: 107 */
+
+	i = b;			/* expect: 107 */
+	b = i;			/* expect: 107 */
+}
+
+void
+strict_bool_conversion_from_bool_to_scalar(bool b) /* expect: 231 */
+{
+	int i;
+	unsigned u;
+	double d;
+	void *p;
+
+	i = b;			/* expect: 107 */
+	u = b;			/* expect: 107 */
+	d = b;			/* expect: 107 */
+	p = b;			/* expect: 107 */
+}
+
+/*
+ * strict-bool-controlling-expression:
+ *	Controlling expressions in 'if', 'while', 'for', '?:' must be of
+ *	type bool.
+ */
+
+void
+strict_bool_controlling_expression(bool b, int i, double d, const void *p)
+{
+	if (__lint_false)
+		do_nothing();
+
+	if (__lint_true)
+		do_nothing();
+
+	if (b)
+		do_nothing();
+
+	if (0)			/* TODO: expect: 333 */
+		do_nothing();
+
+	if (1)			/* TODO: expect: 333 */
+		do_nothing();
+
+	if (2)			/* expect: 333 */
+		do_nothing();
 
 	/* Not allowed: There is no implicit conversion from scalar to bool. */
 	if (i)			/* expect: 333 */
-		return;
+		do_nothing();
 	if (i != 0)
-		return;
+		do_nothing();
 
 	/* Not allowed: There is no implicit conversion from scalar to bool. */
 	if (d)			/* expect: 333 */
-		return;
+		do_nothing();
 	if (d != 0.0)
-		return;
+		do_nothing();
 
 	/* Not allowed: There is no implicit conversion from scalar to bool. */
 	if (p)			/* expect: 333 */
-		return;
+		do_nothing();
 	if (p != (void *)0)
-		return;
-
-	/* Using a bool expression is allowed. */
-	if (b)
-		return;
+		do_nothing();
 }
 
+/*
+ * strict-bool-operand-unary:
+ *	Operator	bool?	scalar?
+ *	!		yes	-
+ *	&		yes	yes
+ *	The other binary operators do not accept bool operands.
+ */
+
 void
-SB002_operator_result_type(bool b)
+strict_bool_operand_unary_not(void)
 {
-	b = b;
-	char c = b;		/* expect: 107 */
-	int i = b;		/* expect: 107 */
-	double d = b;		/* expect: 107 */
-	void *p = b;		/* expect: 107 */
+	bool b = __lint_false;
 
-	/* The right-hand sides of these assignments are all ok. */
 	b = !b;
-	b = i == i;
-	b = i != i;
-	b = i < i;
-	b = i <= i;
-	b = i >= i;
-	b = i > i;
-	b = b && b;
-	b = b || b;
+	b = !!!b;
+	b = !__lint_false;
+	b = !__lint_true;
+
+	int i = 0;
+
+	i = !i;			/* expect: 330 */
+	i = !!!i;		/* expect: 330 */
+	i = !0;			/* expect: 107 */
+	i = !1;			/* expect: 107 */
+}
 
-	/*
-	 * The right-hand sides of these assignments are not ok, they
-	 * implicitly convert from bool to int.
-	 */
-	i = !b;			/* expect: 107 */
-	i = i == i;		/* expect: 107 */
-	i = i != i;		/* expect: 107 */
-	i = i < i;		/* expect: 107 */
-	i = i <= i;		/* expect: 107 */
-	i = i >= i;		/* expect: 107 */
-	i = i > i;		/* expect: 107 */
-	i = b && b;		/* expect: 107 */
-	i = b || b;		/* expect: 107 */
+void
+strict_bool_operand_unary_address(void)
+{
+	bool b = __lint_false;
+
+	/* Taking the address of a bool lvalue. */
+	bool *bp;
+	bp = &b;
+	*bp = b;
+	b = *bp;
+}
+
+/*
+ * strict-bool-operand-binary:
+ *	Operator	left:	bool?	other?	right:	bool?	other?
+ *	.			-	yes		yes	yes
+ *	->			-	yes		yes	yes
+ *	<=, <, >=, >		yes	yes		yes	yes
+ *	==, !=			yes	yes		yes	yes
+ *	&			yes	yes		yes	yes
+ *	^			yes	yes		yes	yes
+ *	|			yes	yes		yes	yes
+ *	&&			yes	-		yes	-
+ *	||			yes	-		yes	-
+ *	?			yes	-		yes	yes
+ *	:			yes	yes		yes	yes
+ *	=			yes	yes		yes	yes
+ *	&=, ^=, |=		yes	yes		yes	yes
+ *	,			yes	yes		yes	yes
+ *	The other binary operators do not accept bool operands.
+ */
+
+/*
+ * Ensure that bool members can be accessed as usual.
+ */
+void
+strict_bool_operand_binary_dot_arrow(void)
+{
+	struct bool_struct {
+		bool b;
+	};
+
+	/* Initialize and assign using boolean constants. */
+	bool b = __lint_false;
+	b = __lint_true;
+
+	/* Access a struct member using the '.' operator. */
+	struct bool_struct bs = { __lint_true };
+	b = bs.b;
+	bs.b = b;
+	bs.b = 0;		/* TODO: expect: incompatible types */
+
+	/* Access a struct member using the '->' operator. */
+	struct bool_struct *bsp = &bs;
+	b = bsp->b;
+	bsp->b = b;
+	bsp->b = 0;
 }
 
 int
-SB003_operands(bool b, int i)
+strict_bool_operand_binary(bool b, int i)
 {
 
 	/* The right-hand sides of these assignments are ok. */
@@ -147,11 +510,10 @@ SB003_operands(bool b, int i)
 	return i;
 }
 
-/*ARGSUSED*/
 void
-SB004_operators_and_bool_operands(bool b, unsigned u)
+strict_bool_operand_binary_all(bool b, unsigned u)
 {
-	b = !b;			/* ok */
+	b = !b;
 	b = ~b;			/* expect: 335 */
 	++b;			/* expect: 335 */
 	--b;			/* expect: 335 */
@@ -172,17 +534,17 @@ SB004_operators_and_bool_operands(bool b
 	b = b <= b;		/* expect: 336, 337 */
 	b = b > b;		/* expect: 336, 337 */
 	b = b >= b;		/* expect: 336, 337 */
-	b = b == b;		/* ok */
-	b = b != b;		/* ok */
+	b = b == b;
+	b = b != b;
 
-	b = b & b;		/* ok */
-	b = b ^ b;		/* ok */
-	b = b | b;		/* ok */
-	b = b && b;		/* ok */
-	b = b || b;		/* ok */
-	b = b ? b : b;		/* ok */
+	b = b & b;
+	b = b ^ b;
+	b = b | b;
+	b = b && b;
+	b = b || b;
+	b = b ? b : b;
 
-	b = b;			/* ok */
+	b = b;
 	b *= b;			/* expect: 336, 337 */
 	b /= b;			/* expect: 336, 337 */
 	b %= b;			/* expect: 336, 337 */
@@ -190,9 +552,9 @@ SB004_operators_and_bool_operands(bool b
 	b -= b;			/* expect: 336, 337 */
 	b <<= b;		/* expect: 336, 337 */
 	b >>= b;		/* expect: 336, 337 */
-	b &= b;			/* ok */
-	b ^= b;			/* ok */
-	b |= b;			/* ok */
+	b &= b;
+	b ^= b;
+	b |= b;
 
 	/* Operations with mixed types. */
 	u = b * u;		/* expect: 336 */
@@ -209,79 +571,75 @@ SB004_operators_and_bool_operands(bool b
 	u = u << b;		/* expect: 337 */
 	u = b >> u;		/* expect: 336 */
 	u = u >> b;		/* expect: 337 */
-	u = b ? u : u;		/* ok */
+	u = b ? u : u;
 	u = b ? b : u;		/* expect: 107 */
 	u = b ? u : b;		/* expect: 107 */
 }
 
-/*ARGSUSED*/
-void
-SB005_convert_from_bool_to_scalar(bool b)
+bool
+strict_bool_operand_binary_comma(bool b, int i)
 {
-	int i;
-	unsigned u;
-	double d;
-	void *p;
-
-	i = b;			/* expect: 107 */
-	u = b;			/* expect: 107 */
-	d = b;			/* expect: 107 */
-	p = b;			/* expect: 107 */
+	b = (b, !b);
+	i = (i, i + 1);
+	return b;
 }
 
-enum SB006_bool_constant_expression {
-	/* Ok: 0 is a boolean constant expression. */
-	INT0 = 0 ? 100 : 101,
-
-	/* Ok: 1 is a boolean constant expression. */
-	INT1 = 1 ? 100 : 101,
-
-	/* Not ok: 2 is not a boolean constant (neither 0 nor 1). */
-	INT2 = 2 ? 100 : 101,	/* expect: 331 */
-
-	/*
-	 * The intermediate expression "2" has type int, which is not
-	 * compatible with _Bool.  The expression "2 - 2" is an integer
-	 * constant expression with value 0 and is thus a bool constant
-	 * expression.  This particular case probably does not occur in
-	 * practice.
-	 */
-	ARITH = (2 - 2) ? 100 : 101,
+/*
+ * strict-bool-operator-result:
+ *	The result type of the operators '!', '<', '<=', '>', '>=',
+ *	'==', '!=', '&&', '||' is _Bool instead of int.
+ */
 
-	/*
-	 * These two variants of an expression can occur when a preprocessor
-	 * macro is either defined to 1 or left empty, as in lint1/ops.def.
-	 */
-	BINARY_PLUS = (1 + 0) ? 100 : 101,
-	UNARY_PLUS = (+0) ? 100 : 101,
+void
+strict_bool_operator_result(bool b)
+{
+	char c = b;		/* expect: 107 */
+	int i = b;		/* expect: 107 */
+	double d = b;		/* expect: 107 */
+	void *p = b;		/* expect: 107 */
 
-	/* The main operator '>' has return type bool. */
-	Q1 = (13 > 12) ? 100 : 101,
+	/* The right-hand sides of these assignments are all ok. */
+	b = !b;
+	b = i == i;
+	b = i != i;
+	b = i < i;
+	b = i <= i;
+	b = i >= i;
+	b = i > i;
+	b = b && b;
+	b = b || b;
 
 	/*
-	 * The 7 is part of the integer constant expression, but it is
-	 * irrelevant for the final result.  The expression in parentheses
-	 * is an integer constant expression with value 1 and thus is a
-	 * bool constant expression.
+	 * The right-hand sides of these assignments are not ok, they
+	 * implicitly convert from bool to int.
 	 */
-	Q2 = (13 > 12 ? 1 : 7) ? 100 : 101,
-
-	BINAND = 0 & 1,		/* ok */
-
-	BINXOR = 0 ^ 1,		/* ok */
-
-	BINOR = 0 | 1,		/* ok */
-
-	LOGOR = 0 || 1,		/* ok */
+	i = !b;			/* expect: 107 */
+	i = i == i;		/* expect: 107 */
+	i = i != i;		/* expect: 107 */
+	i = i < i;		/* expect: 107 */
+	i = i <= i;		/* expect: 107 */
+	i = i >= i;		/* expect: 107 */
+	i = i > i;		/* expect: 107 */
+	i = b && b;		/* expect: 107 */
+	i = b || b;		/* expect: 107 */
+}
 
-	LOGAND = 0 && 1,	/* ok */
-};
 
 /*
- * An efficient implementation technique for a collection of boolean flags
- * is an enum.  The enum declaration groups the available constants, and as
- * of 2020, compilers such as GCC and Clang have basic support for detecting
- * type mismatches on enums.
+ * strict-bool-bitwise-and:
+ *	Expressions of the form "flags & FLAG" are compatible with _Bool if
+ *	the left operand has enum type, the right operand is an integer
+ *	constant and the resulting value is used in a context where it is
+ *	implicitly and immediately compared to zero.
+ *
+ *	Note: Examples for such contexts are controlling expressions or the
+ *	operands of the operators '!', '&&', '||'.
+ *
+ *	Note: Counterexamples for contexts are assignments to a bool variable.
+ *
+ *	Note: These rules ensure that conforming code can be compiled without
+ *	change in behavior using old compilers that implement bool as an
+ *	ordinary integer type, without the special rule C99 6.3.1.2.
  */
 
 enum Flags {
@@ -290,63 +648,8 @@ enum Flags {
 	FLAG28 = 1 << 28
 };
 
-/*
- * The usual way to query one of the flags is demonstrated below.
- */
-
-extern void
-println(const char *);
-
-void
-query_flag_from_enum_bit_set(enum Flags flags)
-{
-
-	if (flags & FLAG0)
-		println("FLAG0 is set");
-
-	if ((flags & FLAG1) != 0)
-		println("FLAG1 is set");
-
-	if ((flags & (FLAG0 | FLAG1)) == (FLAG0 | FLAG1))
-		println("FLAG0 and FLAG1 are both set");
-
-	if (flags & FLAG0 && flags & FLAG1)
-		println("FLAG0 and FLAG1 are both set");
-
-	if ((flags & (FLAG0 | FLAG1)) != 0)
-		println("At least one of FLAG0 and FLAG1 is set");
-
-	if (flags & FLAG28)
-		println("FLAG28 is set");
-}
-
-/*
- * In all the above conditions (or controlling expressions, as the C standard
- * calls them), the result of the operator '&' is compared against 0.  This
- * makes this pattern work, no matter whether the bits are in the low-value
- * range or in the high-value range (such as FLAG28, which has the value
- * 1073741824, which is more than what would fit into an unsigned char).
- * Even if an enum could be extended to larger types than int, this pattern
- * would work.
- */
-
-/*
- * There is a crucial difference between a _Bool variable and an ordinary
- * integer variable.  C99 6.3.1.2 defines a conversion from an arbitrary
- * scalar value to _Bool as equivalent to (value != 0 ? 1 : 0).  This means
- * that even if _Bool is implemented as an 8-bit unsigned integer, assigning
- * 256 to it would still result in the value 1 being stored.  Storing 256 in
- * an ordinary 8-bit unsigned integer would result in the value 0 being
- * stored.  See the test d_c99_bool.c for more details.
- *
- * Because of this, expressions like (flags & FLAG28) are only allowed in
- * bool context if they are guaranteed not to be truncated, even if the
- * result were to be stored in a plain unsigned integer.
- */
-
-/*ARGSUSED*/
 void
-SB007_allow_flag_test_on_bit_set_enums(enum Flags flags)
+strict_bool_bitwise_and_enum(enum Flags flags) /* expect: 231 */
 {
 	bool b;
 
@@ -374,172 +677,34 @@ SB007_allow_flag_test_on_bit_set_enums(e
 	b = flags & FLAG28;	/* expect: 107 */
 }
 
-/* A bool bit field is compatible with bool. Other bit fields are not. */
-
-struct flags {
-	bool bool_flag: 1;
-	unsigned uint_flag: 1;
-};
-
-/*ARGSUSED*/
-void
-SB008_bit_fields(const struct flags *flags)
-{
-	bool b;
-
-	b = flags->bool_flag;	/* ok */
-	b = flags->uint_flag;	/* expect: 107 */
-	flags->bool_flag = b;
-	flags->uint_flag = b;	/* expect: 107 */
-}
-
-/* Test implicit conversion when returning a value from a function. */
-
-/*ARGSUSED*/
-bool
-returning_bool(bool b, int i, const char *p)
-{
-	if (i > 0)
-		return b;	/* ok */
-	if (i < 0)
-		return i;	/* expect: 211 */
-	return p;		/* expect: 211 */
-}
-
-/*ARGSUSED*/
-char
-returning_char(bool b, int i, const char *p)
-{
-	if (i > 0)
-		return b;	/* expect: 211 */
-	if (i < 0)
-		return i;	/* XXX: narrowing conversion */
-	return p;		/* expect: 183 */
-}
-
-bool
-return_constant_false(void)
-{
-	return 0;
-}
-
-bool
-return_constant_true(void)
-{
-	return 1;
-}
-
-bool
-return_invalid_integer(void)
-{
-	return 2;		/* expect: 211 */
-}
-
-/* Test passing arguments to a function. */
-
-extern void
-taking_arguments(bool, int, const char *, ...);
-
-void
-passing_arguments(bool b, int i, const char *p)
-{
-	/* No conversion necessary. */
-	taking_arguments(b, i, p);
-
-	/* Implicitly converting bool to other scalar types. */
-	taking_arguments(b, b, b);	/* expect: 334, 334 */
-
-	/* Implicitly converting int to bool (arg #1). */
-	taking_arguments(i, i, i);	/* expect: 334, 154 */
-
-	/* Implicitly converting pointer to bool (arg #1). */
-	taking_arguments(p, p, p);	/* expect: 334, 154 */
-
-	/* Passing bool as vararg. */
-	taking_arguments(b, i, p, b, i, p); /* expect: arg#4 */ // TODO
-
-	/* Passing a bool constant. */
-	taking_arguments(0, i, p);
-
-	/* Passing a bool constant. */
-	taking_arguments(1, i, p);
-
-	/* Trying to pass an invalid integer. */
-	taking_arguments(2, i, p);	/* expect: 334 */
-}
-
 /*
- * This is just normal access to a bool member of a struct, to ensure that
- * these produce no errors.
+ * Demonstrate idiomatic code to query flags from an enum bit set.
+ *
+ * In all the controlling expressions in this function, the result of the
+ * operator '&' is compared against 0.  This makes this pattern work, no
+ * matter whether the bits are in the low-value range or in the high-value
+ * range (such as FLAG28, which has the value 1073741824, which is more than
+ * what would fit into an unsigned char).  Even if an enum could be extended
+ * to larger types than int, this pattern would work.
  */
 void
-struct_access_operators(void)
+query_flag_from_enum_bit_set(enum Flags flags)
 {
-	struct bool_struct {
-		bool b;
-	};
-
-	/* Initialize and assign using boolean constants. */
-	bool b = 0;
-	b = 1;
-
-	/* Access a struct member using the '.' operator. */
-	struct bool_struct bs = { 1 };
-	b = bs.b;
-	bs.b = b;
-	bs.b = 0;
-
-	/* Access a struct member using the '->' operator. */
-	struct bool_struct *bsp = &bs;
-	b = bsp->b;
-	bsp->b = b;
-	bsp->b = 0;
-
-	/* Taking the address of a bool lvalue. */
-	bool *bp;
-	bp = &b;
-	*bp = b;
-	b = *bp;
-}
+	if (flags & FLAG0)
+		println("FLAG0 is set");
 
-/*
- * Comparing a _Bool expression to 0 or 1 is redundant.  It may come from
- * an earlier version of the code, before it got migrated to using _Bool.
- * Usually, bool expressions are used directly as control expressions or
- * as argument to the boolean operators such as '!', '&&', '||'.
- *
- * Since lint steps in after the C preprocessor, it has no chance of seeing
- * the original source code, which may well have been "b == false" instead
- * of "b == 0".
- */
-bool
-compare_var_with_constant(bool b)
-{
-	bool t1 = b == 0;
-	bool t2 = t1 != 0;
-	bool t3 = t2 == 1;
-	bool t4 = t3 != 1;
-	return t4 ^ t3;
-}
+	if ((flags & FLAG1) != 0)
+		println("FLAG1 is set");
 
-bool
-SB003_operand_comma(bool b, int i)
-{
-	b = (b, !b);
-	i = (i, i + 1);
-	return b;
-}
+	if ((flags & (FLAG0 | FLAG1)) == (FLAG0 | FLAG1))
+		println("FLAG0 and FLAG1 are both set");
 
-void
-bit_field_as_operator_argument(void)
-{
-	struct s {
-		bool ordinary;
-		bool bit_field: 1;
-	};
+	if (flags & FLAG0 && flags & FLAG1)
+		println("FLAG0 and FLAG1 are both set");
 
-	struct s s = { 0 };
+	if ((flags & (FLAG0 | FLAG1)) != 0)
+		println("At least one of FLAG0 and FLAG1 is set");
 
-	s.ordinary = s.ordinary | s.ordinary;
-	s.bit_field = s.bit_field | s.bit_field; /* FIXME *//* expect: 107 */
+	if (flags & FLAG28)
+		println("FLAG28 is set");
 }

Index: src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.exp
diff -u src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.exp:1.6 src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.exp:1.7
--- src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.exp:1.6	Fri Jan 15 23:15:28 2021
+++ src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.exp	Sat Jan 16 15:02:11 2021
@@ -1,104 +1,117 @@
-d_c99_bool_strict.c(64): controlling expression must be bool, not 'int' [333]
-d_c99_bool_strict.c(68): controlling expression must be bool, not 'int' [333]
-d_c99_bool_strict.c(74): controlling expression must be bool, not 'double' [333]
-d_c99_bool_strict.c(80): controlling expression must be bool, not 'pointer' [333]
-d_c99_bool_strict.c(94): operands of '=' have incompatible types (char != _Bool) [107]
-d_c99_bool_strict.c(95): operands of '=' have incompatible types (int != _Bool) [107]
-d_c99_bool_strict.c(96): operands of '=' have incompatible types (double != _Bool) [107]
-d_c99_bool_strict.c(97): operands of '=' have incompatible types (pointer != _Bool) [107]
-d_c99_bool_strict.c(114): operands of '=' have incompatible types (int != _Bool) [107]
-d_c99_bool_strict.c(115): operands of '=' have incompatible types (int != _Bool) [107]
-d_c99_bool_strict.c(116): operands of '=' have incompatible types (int != _Bool) [107]
-d_c99_bool_strict.c(117): operands of '=' have incompatible types (int != _Bool) [107]
-d_c99_bool_strict.c(118): operands of '=' have incompatible types (int != _Bool) [107]
-d_c99_bool_strict.c(119): operands of '=' have incompatible types (int != _Bool) [107]
-d_c99_bool_strict.c(120): operands of '=' have incompatible types (int != _Bool) [107]
-d_c99_bool_strict.c(121): operands of '=' have incompatible types (int != _Bool) [107]
-d_c99_bool_strict.c(122): operands of '=' have incompatible types (int != _Bool) [107]
-d_c99_bool_strict.c(138): operand of '!' must be bool, not 'int' [330]
-d_c99_bool_strict.c(139): left operand of '&&' must be bool, not 'int' [331]
-d_c99_bool_strict.c(139): right operand of '&&' must be bool, not 'int' [332]
-d_c99_bool_strict.c(140): left operand of '||' must be bool, not 'int' [331]
-d_c99_bool_strict.c(140): right operand of '||' must be bool, not 'int' [332]
-d_c99_bool_strict.c(155): operand of '~' must not be bool [335]
-d_c99_bool_strict.c(156): operand of '++x' must not be bool [335]
-d_c99_bool_strict.c(157): operand of '--x' must not be bool [335]
-d_c99_bool_strict.c(158): operand of 'x++' must not be bool [335]
-d_c99_bool_strict.c(159): operand of 'x--' must not be bool [335]
-d_c99_bool_strict.c(160): operand of '+' must not be bool [335]
-d_c99_bool_strict.c(161): operand of '-' must not be bool [335]
-d_c99_bool_strict.c(163): left operand of '*' must not be bool [336]
-d_c99_bool_strict.c(163): right operand of '*' must not be bool [337]
-d_c99_bool_strict.c(164): left operand of '/' must not be bool [336]
-d_c99_bool_strict.c(164): right operand of '/' must not be bool [337]
-d_c99_bool_strict.c(165): left operand of '%' must not be bool [336]
-d_c99_bool_strict.c(165): right operand of '%' must not be bool [337]
-d_c99_bool_strict.c(166): left operand of '+' must not be bool [336]
-d_c99_bool_strict.c(166): right operand of '+' must not be bool [337]
-d_c99_bool_strict.c(167): left operand of '-' must not be bool [336]
-d_c99_bool_strict.c(167): right operand of '-' must not be bool [337]
-d_c99_bool_strict.c(168): left operand of '<<' must not be bool [336]
-d_c99_bool_strict.c(168): right operand of '<<' must not be bool [337]
-d_c99_bool_strict.c(169): left operand of '>>' must not be bool [336]
-d_c99_bool_strict.c(169): right operand of '>>' must not be bool [337]
-d_c99_bool_strict.c(171): left operand of '<' must not be bool [336]
-d_c99_bool_strict.c(171): right operand of '<' must not be bool [337]
-d_c99_bool_strict.c(172): left operand of '<=' must not be bool [336]
-d_c99_bool_strict.c(172): right operand of '<=' must not be bool [337]
-d_c99_bool_strict.c(173): left operand of '>' must not be bool [336]
-d_c99_bool_strict.c(173): right operand of '>' must not be bool [337]
-d_c99_bool_strict.c(174): left operand of '>=' must not be bool [336]
-d_c99_bool_strict.c(174): right operand of '>=' must not be bool [337]
-d_c99_bool_strict.c(186): left operand of '*=' must not be bool [336]
-d_c99_bool_strict.c(186): right operand of '*=' must not be bool [337]
-d_c99_bool_strict.c(187): left operand of '/=' must not be bool [336]
-d_c99_bool_strict.c(187): right operand of '/=' must not be bool [337]
-d_c99_bool_strict.c(188): left operand of '%=' must not be bool [336]
-d_c99_bool_strict.c(188): right operand of '%=' must not be bool [337]
-d_c99_bool_strict.c(189): left operand of '+=' must not be bool [336]
-d_c99_bool_strict.c(189): right operand of '+=' must not be bool [337]
-d_c99_bool_strict.c(190): left operand of '-=' must not be bool [336]
-d_c99_bool_strict.c(190): right operand of '-=' must not be bool [337]
-d_c99_bool_strict.c(191): left operand of '<<=' must not be bool [336]
-d_c99_bool_strict.c(191): right operand of '<<=' must not be bool [337]
-d_c99_bool_strict.c(192): left operand of '>>=' must not be bool [336]
-d_c99_bool_strict.c(192): right operand of '>>=' must not be bool [337]
-d_c99_bool_strict.c(198): left operand of '*' must not be bool [336]
-d_c99_bool_strict.c(199): right operand of '*' must not be bool [337]
-d_c99_bool_strict.c(200): left operand of '/' must not be bool [336]
-d_c99_bool_strict.c(201): right operand of '/' must not be bool [337]
-d_c99_bool_strict.c(202): left operand of '%' must not be bool [336]
-d_c99_bool_strict.c(203): right operand of '%' must not be bool [337]
-d_c99_bool_strict.c(204): left operand of '+' must not be bool [336]
-d_c99_bool_strict.c(205): right operand of '+' must not be bool [337]
-d_c99_bool_strict.c(206): left operand of '-' must not be bool [336]
-d_c99_bool_strict.c(207): right operand of '-' must not be bool [337]
-d_c99_bool_strict.c(208): left operand of '<<' must not be bool [336]
-d_c99_bool_strict.c(209): right operand of '<<' must not be bool [337]
-d_c99_bool_strict.c(210): left operand of '>>' must not be bool [336]
-d_c99_bool_strict.c(211): right operand of '>>' must not be bool [337]
-d_c99_bool_strict.c(213): operands of ':' have incompatible types (_Bool != unsigned int) [107]
-d_c99_bool_strict.c(214): operands of ':' have incompatible types (unsigned int != _Bool) [107]
-d_c99_bool_strict.c(226): operands of '=' have incompatible types (int != _Bool) [107]
-d_c99_bool_strict.c(227): operands of '=' have incompatible types (unsigned int != _Bool) [107]
-d_c99_bool_strict.c(228): operands of '=' have incompatible types (double != _Bool) [107]
-d_c99_bool_strict.c(229): operands of '=' have incompatible types (pointer != _Bool) [107]
-d_c99_bool_strict.c(240): left operand of '?' must be bool, not 'int' [331]
-d_c99_bool_strict.c(359): operands of '=' have incompatible types (_Bool != int) [107]
-d_c99_bool_strict.c(367): operands of '=' have incompatible types (_Bool != int) [107]
-d_c99_bool_strict.c(374): operands of '=' have incompatible types (_Bool != int) [107]
-d_c99_bool_strict.c(391): operands of '=' have incompatible types (_Bool != unsigned int) [107]
-d_c99_bool_strict.c(393): operands of '=' have incompatible types (unsigned int != _Bool) [107]
-d_c99_bool_strict.c(405): return value type mismatch (_Bool) and (int) [211]
-d_c99_bool_strict.c(406): return value type mismatch (_Bool) and (pointer to const char) [211]
-d_c99_bool_strict.c(414): return value type mismatch (char) and (_Bool) [211]
-d_c99_bool_strict.c(417): warning: illegal combination of integer (char) and pointer (pointer to const char) [183]
-d_c99_bool_strict.c(435): return value type mismatch (_Bool) and (int) [211]
-d_c99_bool_strict.c(450): argument #2 expects 'int', gets passed '_Bool' [334]
-d_c99_bool_strict.c(450): argument #3 expects 'pointer', gets passed '_Bool' [334]
-d_c99_bool_strict.c(453): argument #1 expects '_Bool', gets passed 'int' [334]
-d_c99_bool_strict.c(453): warning: illegal combination of pointer (pointer to const char) and integer (int), arg #3 [154]
-d_c99_bool_strict.c(456): argument #1 expects '_Bool', gets passed 'pointer' [334]
-d_c99_bool_strict.c(456): warning: illegal combination of integer (int) and pointer (pointer to const char), arg #2 [154]
-d_c99_bool_strict.c(468): argument #1 expects '_Bool', gets passed 'int' [334]
-d_c99_bool_strict.c(544): operands of '=' have incompatible types (_Bool != int) [107]
+d_c99_bool_strict.c(128): argument #1 expects '_Bool', gets passed 'int' [334]
+d_c99_bool_strict.c(145): left operand of '?' must be bool, not 'int' [331]
+d_c99_bool_strict.c(203): operands of '=' have incompatible types (_Bool != unsigned int) [107]
+d_c99_bool_strict.c(205): operands of '=' have incompatible types (unsigned int != _Bool) [107]
+d_c99_bool_strict.c(208): operands of '=' have incompatible types (_Bool != unsigned int) [107]
+d_c99_bool_strict.c(210): operands of '=' have incompatible types (unsigned int != _Bool) [107]
+d_c99_bool_strict.c(224): operands of '=' have incompatible types (_Bool != int) [107]
+d_c99_bool_strict.c(264): return value type mismatch (_Bool) and (int) [211]
+d_c99_bool_strict.c(270): return value type mismatch (_Bool) and (pointer to const void) [211]
+d_c99_bool_strict.c(268): warning: argument p unused in function strict_bool_conversion_return_pointer [231]
+d_c99_bool_strict.c(276): return value type mismatch (char) and (_Bool) [211]
+d_c99_bool_strict.c(282): return value type mismatch (char) and (_Bool) [211]
+d_c99_bool_strict.c(300): argument #2 expects 'int', gets passed '_Bool' [334]
+d_c99_bool_strict.c(300): argument #3 expects 'pointer', gets passed '_Bool' [334]
+d_c99_bool_strict.c(303): argument #1 expects '_Bool', gets passed 'int' [334]
+d_c99_bool_strict.c(303): warning: illegal combination of pointer (pointer to const char) and integer (int), arg #3 [154]
+d_c99_bool_strict.c(306): argument #1 expects '_Bool', gets passed 'pointer' [334]
+d_c99_bool_strict.c(306): warning: illegal combination of integer (int) and pointer (pointer to const char), arg #2 [154]
+d_c99_bool_strict.c(320): argument #1 expects '_Bool', gets passed 'int' [334]
+d_c99_bool_strict.c(335): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(337): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(339): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(340): operands of '=' have incompatible types (_Bool != int) [107]
+d_c99_bool_strict.c(351): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(352): operands of '=' have incompatible types (unsigned int != _Bool) [107]
+d_c99_bool_strict.c(353): operands of '=' have incompatible types (double != _Bool) [107]
+d_c99_bool_strict.c(354): operands of '=' have incompatible types (pointer != _Bool) [107]
+d_c99_bool_strict.c(344): warning: argument b unused in function strict_bool_conversion_from_bool_to_scalar [231]
+d_c99_bool_strict.c(381): controlling expression must be bool, not 'int' [333]
+d_c99_bool_strict.c(385): controlling expression must be bool, not 'int' [333]
+d_c99_bool_strict.c(391): controlling expression must be bool, not 'double' [333]
+d_c99_bool_strict.c(397): controlling expression must be bool, not 'pointer' [333]
+d_c99_bool_strict.c(423): operand of '!' must be bool, not 'int' [330]
+d_c99_bool_strict.c(424): operand of '!' must be bool, not 'int' [330]
+d_c99_bool_strict.c(425): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(426): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(501): operand of '!' must be bool, not 'int' [330]
+d_c99_bool_strict.c(502): left operand of '&&' must be bool, not 'int' [331]
+d_c99_bool_strict.c(502): right operand of '&&' must be bool, not 'int' [332]
+d_c99_bool_strict.c(503): left operand of '||' must be bool, not 'int' [331]
+d_c99_bool_strict.c(503): right operand of '||' must be bool, not 'int' [332]
+d_c99_bool_strict.c(517): operand of '~' must not be bool [335]
+d_c99_bool_strict.c(518): operand of '++x' must not be bool [335]
+d_c99_bool_strict.c(519): operand of '--x' must not be bool [335]
+d_c99_bool_strict.c(520): operand of 'x++' must not be bool [335]
+d_c99_bool_strict.c(521): operand of 'x--' must not be bool [335]
+d_c99_bool_strict.c(522): operand of '+' must not be bool [335]
+d_c99_bool_strict.c(523): operand of '-' must not be bool [335]
+d_c99_bool_strict.c(525): left operand of '*' must not be bool [336]
+d_c99_bool_strict.c(525): right operand of '*' must not be bool [337]
+d_c99_bool_strict.c(526): left operand of '/' must not be bool [336]
+d_c99_bool_strict.c(526): right operand of '/' must not be bool [337]
+d_c99_bool_strict.c(527): left operand of '%' must not be bool [336]
+d_c99_bool_strict.c(527): right operand of '%' must not be bool [337]
+d_c99_bool_strict.c(528): left operand of '+' must not be bool [336]
+d_c99_bool_strict.c(528): right operand of '+' must not be bool [337]
+d_c99_bool_strict.c(529): left operand of '-' must not be bool [336]
+d_c99_bool_strict.c(529): right operand of '-' must not be bool [337]
+d_c99_bool_strict.c(530): left operand of '<<' must not be bool [336]
+d_c99_bool_strict.c(530): right operand of '<<' must not be bool [337]
+d_c99_bool_strict.c(531): left operand of '>>' must not be bool [336]
+d_c99_bool_strict.c(531): right operand of '>>' must not be bool [337]
+d_c99_bool_strict.c(533): left operand of '<' must not be bool [336]
+d_c99_bool_strict.c(533): right operand of '<' must not be bool [337]
+d_c99_bool_strict.c(534): left operand of '<=' must not be bool [336]
+d_c99_bool_strict.c(534): right operand of '<=' must not be bool [337]
+d_c99_bool_strict.c(535): left operand of '>' must not be bool [336]
+d_c99_bool_strict.c(535): right operand of '>' must not be bool [337]
+d_c99_bool_strict.c(536): left operand of '>=' must not be bool [336]
+d_c99_bool_strict.c(536): right operand of '>=' must not be bool [337]
+d_c99_bool_strict.c(548): left operand of '*=' must not be bool [336]
+d_c99_bool_strict.c(548): right operand of '*=' must not be bool [337]
+d_c99_bool_strict.c(549): left operand of '/=' must not be bool [336]
+d_c99_bool_strict.c(549): right operand of '/=' must not be bool [337]
+d_c99_bool_strict.c(550): left operand of '%=' must not be bool [336]
+d_c99_bool_strict.c(550): right operand of '%=' must not be bool [337]
+d_c99_bool_strict.c(551): left operand of '+=' must not be bool [336]
+d_c99_bool_strict.c(551): right operand of '+=' must not be bool [337]
+d_c99_bool_strict.c(552): left operand of '-=' must not be bool [336]
+d_c99_bool_strict.c(552): right operand of '-=' must not be bool [337]
+d_c99_bool_strict.c(553): left operand of '<<=' must not be bool [336]
+d_c99_bool_strict.c(553): right operand of '<<=' must not be bool [337]
+d_c99_bool_strict.c(554): left operand of '>>=' must not be bool [336]
+d_c99_bool_strict.c(554): right operand of '>>=' must not be bool [337]
+d_c99_bool_strict.c(560): left operand of '*' must not be bool [336]
+d_c99_bool_strict.c(561): right operand of '*' must not be bool [337]
+d_c99_bool_strict.c(562): left operand of '/' must not be bool [336]
+d_c99_bool_strict.c(563): right operand of '/' must not be bool [337]
+d_c99_bool_strict.c(564): left operand of '%' must not be bool [336]
+d_c99_bool_strict.c(565): right operand of '%' must not be bool [337]
+d_c99_bool_strict.c(566): left operand of '+' must not be bool [336]
+d_c99_bool_strict.c(567): right operand of '+' must not be bool [337]
+d_c99_bool_strict.c(568): left operand of '-' must not be bool [336]
+d_c99_bool_strict.c(569): right operand of '-' must not be bool [337]
+d_c99_bool_strict.c(570): left operand of '<<' must not be bool [336]
+d_c99_bool_strict.c(571): right operand of '<<' must not be bool [337]
+d_c99_bool_strict.c(572): left operand of '>>' must not be bool [336]
+d_c99_bool_strict.c(573): right operand of '>>' must not be bool [337]
+d_c99_bool_strict.c(575): operands of ':' have incompatible types (_Bool != unsigned int) [107]
+d_c99_bool_strict.c(576): operands of ':' have incompatible types (unsigned int != _Bool) [107]
+d_c99_bool_strict.c(596): operands of '=' have incompatible types (char != _Bool) [107]
+d_c99_bool_strict.c(597): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(598): operands of '=' have incompatible types (double != _Bool) [107]
+d_c99_bool_strict.c(599): operands of '=' have incompatible types (pointer != _Bool) [107]
+d_c99_bool_strict.c(616): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(617): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(618): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(619): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(620): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(621): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(622): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(623): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(624): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(662): operands of '=' have incompatible types (_Bool != int) [107]
+d_c99_bool_strict.c(670): operands of '=' have incompatible types (_Bool != int) [107]
+d_c99_bool_strict.c(677): operands of '=' have incompatible types (_Bool != int) [107]
+d_c99_bool_strict.c(652): warning: argument flags unused in function strict_bool_bitwise_and_enum [231]

Index: src/usr.bin/xlint/lint1/tree.c
diff -u src/usr.bin/xlint/lint1/tree.c:1.154 src/usr.bin/xlint/lint1/tree.c:1.155
--- src/usr.bin/xlint/lint1/tree.c:1.154	Sat Jan 16 02:40:02 2021
+++ src/usr.bin/xlint/lint1/tree.c	Sat Jan 16 15:02:11 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: tree.c,v 1.154 2021/01/16 02:40:02 rillig Exp $	*/
+/*	$NetBSD: tree.c,v 1.155 2021/01/16 15:02:11 rillig Exp $	*/
 
 /*
  * Copyright (c) 1994, 1995 Jochen Pohl
@@ -37,7 +37,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: tree.c,v 1.154 2021/01/16 02:40:02 rillig Exp $");
+__RCSID("$NetBSD: tree.c,v 1.155 2021/01/16 15:02:11 rillig Exp $");
 #endif
 
 #include <float.h>
@@ -227,7 +227,20 @@ new_name_node(sym_t *sym, int ntok)
 			 */
 			sym->s_type = incref(sym->s_type, FUNC);
 		} else {
-			if (blklev == 0) {
+			if (Tflag && strcmp(sym->s_name, "__lint_false") == 0) {
+				sym->s_scl = ENUMCON; /* close enough */
+				sym->s_type = gettyp(BOOL);
+				sym->s_value.v_tspec = BOOL;
+				sym->s_value.v_ansiu = false;
+				sym->s_value.v_quad = 0;
+			} else if (Tflag &&
+				   strcmp(sym->s_name, "__lint_true") == 0) {
+				sym->s_scl = ENUMCON; /* close enough */
+				sym->s_type = gettyp(BOOL);
+				sym->s_value.v_tspec = BOOL;
+				sym->s_value.v_ansiu = false;
+				sym->s_value.v_quad = 1;
+			} else if (blklev == 0) {
 				/* %s undefined */
 				error(99, sym->s_name);
 			} else {

Reply via email to