Module Name:    src
Committed By:   rillig
Date:           Sun May 12 11:46:14 UTC 2024

Modified Files:
        src/tests/usr.bin/xlint/lint1: d_c99_bool_strict.c
            d_c99_bool_strict_syshdr.c

Log Message:
tests/lint: clean up tests for strict bool mode


To generate a diff of this commit:
cvs rdiff -u -r1.48 -r1.49 src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c
cvs rdiff -u -r1.22 -r1.23 \
    src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.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/lint1/d_c99_bool_strict.c
diff -u src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c:1.48 src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c:1.49
--- src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c:1.48	Sat Dec 30 17:09:42 2023
+++ src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c	Sun May 12 11:46:14 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: d_c99_bool_strict.c,v 1.48 2023/12/30 17:09:42 rillig Exp $	*/
+/*	$NetBSD: d_c99_bool_strict.c,v 1.49 2024/05/12 11:46:14 rillig Exp $	*/
 # 3 "d_c99_bool_strict.c"
 
 /*
@@ -27,7 +27,7 @@
  *
  * strict-bool-controlling-expression:
  *	Controlling expressions in 'if', 'while', 'for', '?:' must be of
- *	type bool.
+ *	type bool, except for a literal 0 in a do-while loop.
  *
  * strict-bool-operand-unary:
  *	Operator	bool?	scalar?
@@ -62,29 +62,17 @@
  *	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.  Another implementation
- *	technique for bit sets is a plain integer.
- *
  *	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.
+ *	Note: Counterexamples for contexts are assignments to a bool variable,
+ *	as without the conversion from C99 6.3.1.2, converting an integer to a
+ *	"bool-like" integer type truncated the value instead of comparing it
+ *	to 0.
+ *
+ *	Note: These rules ensure that conforming code behaves the same in both
+ *	C99 and in environments that emulate a boolean type using a small
+ *	integer type.
  */
 
 /*
@@ -413,9 +401,7 @@ strict_bool_conversion_from_bool_to_scal
 }
 
 /*
- * strict-bool-controlling-expression:
- *	Controlling expressions in 'if', 'while', 'for', '?:' must be of
- *	type bool.
+ * strict-bool-controlling-expression
  */
 
 void
@@ -466,14 +452,36 @@ strict_bool_controlling_expression(bool 
 		do_nothing();
 	if (p != (void *)0)
 		do_nothing();
+
+	// An endless loop. The preferred form is 'for (;;)' instead.
+	do {
+	/* expect+1: warning: constant in conditional context [161] */
+	} while (__lint_true);
+
+	// A do-once "loop", often used in statement macros.
+	/* expect+1: warning: loop not entered at top [207] */
+	do {
+	} while (__lint_false);
+
+	// This form is too unusual to be allowed in strict bool mode.
+	do {
+	/* expect+2: error: controlling expression must be bool, not 'int' [333] */
+	/* expect+1: warning: constant in conditional context [161] */
+	} while (1);
+
+	// Even though 0 is an integer instead of a bool, this idiom is so
+	// common that it is frequently used in system headers.  Since the
+	// Clang preprocessor does not mark each token as coming from a system
+	// header or from user code, this idiom can only be allowed everywhere
+	// or nowhere.
+	/* expect+1: warning: loop not entered at top [207] */
+	do {
+	/* expect+1: error: controlling expression must be bool, not 'int' [333] */
+	} while (0);
 }
 
 /*
- * strict-bool-operand-unary:
- *	Operator	bool?	scalar?
- *	!		yes	-
- *	&		yes	yes
- *	The other unary operators do not accept bool operands.
+ * strict-bool-operand-unary
  */
 
 void
@@ -517,23 +525,7 @@ strict_bool_operand_unary_address(void)
 /* see strict_bool_operand_unary_all below for the other unary operators. */
 
 /*
- * 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
- *	The other binary operators do not accept bool operands.
+ * strict-bool-operand-binary
  */
 
 /*
@@ -739,9 +731,7 @@ strict_bool_operand_binary_comma(bool b,
 }
 
 /*
- * strict-bool-operator-result:
- *	The result type of the operators '!', '<', '<=', '>', '>=',
- *	'==', '!=', '&&', '||' is _Bool instead of int.
+ * strict-bool-operator-result
  */
 
 void
@@ -793,20 +783,7 @@ strict_bool_operator_result(bool b)
 
 
 /*
- * strict-bool-bitwise-and:
- *	Expressions of the form "flags & FLAG" are compatible with _Bool if
- *	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,
- *	as before C99, the conversion was defined differently.
- *
- *	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.
+ * strict-bool-bitwise-and
  */
 
 enum Flags {
@@ -955,23 +932,6 @@ bool_as_array_index(bool cond)
 }
 
 void
-do_while_false(void)
-{
-	do {
-
-	} while (__lint_false);
-}
-
-void
-do_while_true(void)
-{
-	do {
-
-	} while (__lint_true);
-	/* expect-1: warning: constant in conditional context [161] */
-}
-
-void
 initialization(void)
 {
 	struct {
@@ -985,127 +945,3 @@ initialization(void)
 	    { 1 },
 	};
 }
-
-/*
- * For expressions that originate from a system header, the strict type rules
- * are relaxed a bit, to allow for expressions like 'flags & FLAG', even
- * though they are not strictly boolean.
- *
- * This shouldn't apply to function call expressions though since one of the
- * goals of strict bool mode is to normalize all expressions calling 'strcmp'
- * to be of the form 'strcmp(a, b) == 0' instead of '!strcmp(a, b)'.
- */
-# 1 "stdio.h" 1 3 4
-typedef struct stdio_file {
-	int fd;
-} FILE;
-int ferror(FILE *);
-FILE stdio_files[3];
-FILE *stdio_stdout;
-# 1006 "d_c99_bool_strict.c" 2
-# 1 "string.h" 1 3 4
-int strcmp(const char *, const char *);
-# 1009 "d_c99_bool_strict.c" 2
-
-void
-controlling_expression(FILE *f, const char *a, const char *b)
-{
-	/* expect+1: error: controlling expression must be bool, not 'int' [333] */
-	if (ferror(f))
-		return;
-	/* expect+1: error: controlling expression must be bool, not 'int' [333] */
-	if (strcmp(a, b))
-		return;
-	/* expect+1: error: operand of '!' must be bool, not 'int' [330] */
-	if (!ferror(f))
-		return;
-	/* expect+1: error: operand of '!' must be bool, not 'int' [330] */
-	if (!strcmp(a, b))
-		return;
-
-	/*
-	 * Before tree.c 1.395 from 2021-11-16, the expression below didn't
-	 * produce a warning since the expression 'stdio_files' came from a
-	 * system header (via a macro), and this property was passed up to
-	 * the expression 'ferror(stdio_files[1])'.
-	 *
-	 * That was wrong though since the type of a function call expression
-	 * only depends on the function itself but not its arguments types.
-	 * The old rule had allowed a raw condition 'strcmp(a, b)' without
-	 * the comparison '!= 0', as long as one of its arguments came from a
-	 * system header.
-	 *
-	 * Seen in bin/echo/echo.c, function main, call to ferror.
-	 */
-	/* expect+5: error: controlling expression must be bool, not 'int' [333] */
-	if (ferror(
-# 1043 "d_c99_bool_strict.c" 3 4
-	    &stdio_files[1]
-# 1045 "d_c99_bool_strict.c"
-	    ))
-		return;
-
-	/*
-	 * Before cgram.y 1.369 from 2021-11-16, at the end of parsing the
-	 * name 'stdio_stdout', the parser already looked ahead to the next
-	 * token, to see whether it was the '(' of a function call.
-	 *
-	 * At that point, the parser was no longer in a system header,
-	 * therefore 'stdio_stdout' had tn_sys == false, and this information
-	 * was pushed down to the whole function call expression (which was
-	 * another bug that got fixed in tree.c 1.395 from 2021-11-16).
-	 */
-	/* expect+5: error: controlling expression must be bool, not 'int' [333] */
-	if (ferror(
-# 1061 "d_c99_bool_strict.c" 3 4
-	    stdio_stdout
-# 1063 "d_c99_bool_strict.c"
-	    ))
-		return;
-
-	/*
-	 * In this variant of the pattern, there is a token ')' after the
-	 * name 'stdio_stdout', which even before tree.c 1.395 from
-	 * 2021-11-16 had the effect that at the end of parsing the name, the
-	 * parser was still in the system header, thus setting tn_sys (or
-	 * rather tn_relaxed at that time) to true.
-	 */
-	/* expect+5: error: controlling expression must be bool, not 'int' [333] */
-	if (ferror(
-# 1076 "d_c99_bool_strict.c" 3 4
-	    (stdio_stdout)
-# 1078 "d_c99_bool_strict.c"
-	    ))
-		return;
-
-	/*
-	 * Before cgram.y 1.369 from 2021-11-16, the comment following
-	 * 'stdio_stdout' did not prevent the search for '('.  At the point
-	 * where build_name called expr_alloc_tnode, the parser was already
-	 * in the main file again, thus treating 'stdio_stdout' as not coming
-	 * from a system header.
-	 *
-	 * This has been fixed in tree.c 1.395 from 2021-11-16.  Before that,
-	 * an expression had come from a system header if its operands came
-	 * from a system header, but that was only close to the truth.  In a
-	 * case where both operands come from a system header but the
-	 * operator comes from the main translation unit, the main
-	 * translation unit still has control over the whole expression.  So
-	 * the correct approach is to focus on the operator, not the
-	 * operands.  There are a few corner cases where the operator is
-	 * invisible (for implicit conversions) or synthetic (for translating
-	 * 'arr[index]' to '*(arr + index)', but these are handled as well.
-	 */
-	/* expect+5: error: controlling expression must be bool, not 'int' [333] */
-	if (ferror(
-# 1102 "d_c99_bool_strict.c" 3 4
-	    stdio_stdout /* comment */
-# 1104 "d_c99_bool_strict.c"
-	    ))
-		return;
-}
-
-// In strict bool mode, the identifiers '__lint_false' and '__lint_true' are
-// predefined, but not any others.
-/* expect+1: error: '__lint_unknown' undefined [99] */
-int unknown = sizeof __lint_unknown;

Index: src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.c
diff -u src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.c:1.22 src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.c:1.23
--- src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.c:1.22	Sun Aug  6 19:44:50 2023
+++ src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.c	Sun May 12 11:46:14 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: d_c99_bool_strict_syshdr.c,v 1.22 2023/08/06 19:44:50 rillig Exp $	*/
+/*	$NetBSD: d_c99_bool_strict_syshdr.c,v 1.23 2024/05/12 11:46:14 rillig Exp $	*/
 # 3 "d_c99_bool_strict_syshdr.c"
 
 /*
@@ -286,3 +286,123 @@ if_pointer_or_int(void)
 		       )
 		return;
 }
+
+
+/*
+ * For expressions that originate from a system header, the strict type rules
+ * are relaxed a bit, to allow for expressions like 'flags & FLAG', even
+ * though they are not strictly boolean.
+ *
+ * This shouldn't apply to function call expressions though since one of the
+ * goals of strict bool mode is to normalize all expressions calling 'strcmp'
+ * to be of the form 'strcmp(a, b) == 0' instead of '!strcmp(a, b)'.
+ */
+# 1 "stdio.h" 1 3 4
+typedef struct stdio_file {
+	int fd;
+} FILE;
+int ferror(FILE *);
+FILE stdio_files[3];
+FILE *stdio_stdout;
+# 308 "d_c99_bool_strict_syshdr.c" 2
+# 1 "string.h" 1 3 4
+int strcmp(const char *, const char *);
+# 311 "d_c99_bool_strict_syshdr.c" 2
+
+void
+controlling_expression(FILE *f, const char *a, const char *b)
+{
+	/* expect+1: error: controlling expression must be bool, not 'int' [333] */
+	if (ferror(f))
+		return;
+	/* expect+1: error: controlling expression must be bool, not 'int' [333] */
+	if (strcmp(a, b))
+		return;
+	/* expect+1: error: operand of '!' must be bool, not 'int' [330] */
+	if (!ferror(f))
+		return;
+	/* expect+1: error: operand of '!' must be bool, not 'int' [330] */
+	if (!strcmp(a, b))
+		return;
+
+	/*
+	 * Before tree.c 1.395 from 2021-11-16, the expression below didn't
+	 * produce a warning since the expression 'stdio_files' came from a
+	 * system header (via a macro), and this property was passed up to
+	 * the expression 'ferror(stdio_files[1])'.
+	 *
+	 * That was wrong though since the type of a function call expression
+	 * only depends on the function itself but not its arguments types.
+	 * The old rule had allowed a raw condition 'strcmp(a, b)' without
+	 * the comparison '!= 0', as long as one of its arguments came from a
+	 * system header.
+	 *
+	 * Seen in bin/echo/echo.c, function main, call to ferror.
+	 */
+	/* expect+5: error: controlling expression must be bool, not 'int' [333] */
+	if (ferror(
+# 345 "d_c99_bool_strict_syshdr.c" 3 4
+	    &stdio_files[1]
+# 347 "d_c99_bool_strict_syshdr.c"
+	    ))
+		return;
+
+	/*
+	 * Before cgram.y 1.369 from 2021-11-16, at the end of parsing the
+	 * name 'stdio_stdout', the parser already looked ahead to the next
+	 * token, to see whether it was the '(' of a function call.
+	 *
+	 * At that point, the parser was no longer in a system header,
+	 * therefore 'stdio_stdout' had tn_sys == false, and this information
+	 * was pushed down to the whole function call expression (which was
+	 * another bug that got fixed in tree.c 1.395 from 2021-11-16).
+	 */
+	/* expect+5: error: controlling expression must be bool, not 'int' [333] */
+	if (ferror(
+# 363 "d_c99_bool_strict_syshdr.c" 3 4
+	    stdio_stdout
+# 365 "d_c99_bool_strict_syshdr.c"
+	    ))
+		return;
+
+	/*
+	 * In this variant of the pattern, there is a token ')' after the
+	 * name 'stdio_stdout', which even before tree.c 1.395 from
+	 * 2021-11-16 had the effect that at the end of parsing the name, the
+	 * parser was still in the system header, thus setting tn_sys (or
+	 * rather tn_relaxed at that time) to true.
+	 */
+	/* expect+5: error: controlling expression must be bool, not 'int' [333] */
+	if (ferror(
+# 378 "d_c99_bool_strict_syshdr.c" 3 4
+	    (stdio_stdout)
+# 380 "d_c99_bool_strict_syshdr.c"
+	    ))
+		return;
+
+	/*
+	 * Before cgram.y 1.369 from 2021-11-16, the comment following
+	 * 'stdio_stdout' did not prevent the search for '('.  At the point
+	 * where build_name called expr_alloc_tnode, the parser was already
+	 * in the main file again, thus treating 'stdio_stdout' as not coming
+	 * from a system header.
+	 *
+	 * This has been fixed in tree.c 1.395 from 2021-11-16.  Before that,
+	 * an expression had come from a system header if its operands came
+	 * from a system header, but that was only close to the truth.  In a
+	 * case where both operands come from a system header but the
+	 * operator comes from the main translation unit, the main
+	 * translation unit still has control over the whole expression.  So
+	 * the correct approach is to focus on the operator, not the
+	 * operands.  There are a few corner cases where the operator is
+	 * invisible (for implicit conversions) or synthetic (for translating
+	 * 'arr[index]' to '*(arr + index)', but these are handled as well.
+	 */
+	/* expect+5: error: controlling expression must be bool, not 'int' [333] */
+	if (ferror(
+# 404 "d_c99_bool_strict_syshdr.c" 3 4
+	    stdio_stdout /* comment */
+# 406 "d_c99_bool_strict_syshdr.c"
+	    ))
+		return;
+}

Reply via email to