Module Name:    src
Committed By:   rillig
Date:           Sat Jan 23 22:20:18 UTC 2021

Modified Files:
        src/tests/usr.bin/xlint/lint1: d_c99_bool_strict_syshdr.c
            d_c99_bool_strict_syshdr.exp
        src/usr.bin/xlint/lint1: externs1.h func.c lint1.h mem1.c tree.c

Log Message:
lint: fix two wrong error messages in strict bool mode

The strict bool mode gets complicated because for system headers the
rules need to be relaxed since they cannot be changed easily, often not at all.

Still, if lint validates a program in strict bool mode, that program
must run with equal behavior regarding boolean expressions even on a
pre-C99 platform.


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 \
    src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.c \
    src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.exp
cvs rdiff -u -r1.60 -r1.61 src/usr.bin/xlint/lint1/externs1.h
cvs rdiff -u -r1.64 -r1.65 src/usr.bin/xlint/lint1/func.c
cvs rdiff -u -r1.59 -r1.60 src/usr.bin/xlint/lint1/lint1.h
cvs rdiff -u -r1.24 -r1.25 src/usr.bin/xlint/lint1/mem1.c
cvs rdiff -u -r1.182 -r1.183 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/lint1/d_c99_bool_strict_syshdr.c
diff -u src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.c:1.3 src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.c:1.4
--- src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.c:1.3	Sat Jan 23 19:03:55 2021
+++ src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.c	Sat Jan 23 22:20:18 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: d_c99_bool_strict_syshdr.c,v 1.3 2021/01/23 19:03:55 rillig Exp $	*/
+/*	$NetBSD: d_c99_bool_strict_syshdr.c,v 1.4 2021/01/23 22:20:18 rillig Exp $	*/
 # 3 "d_c99_bool_strict_syshdr.c"
 
 /*
@@ -79,13 +79,13 @@ strict_bool_system_header_ctype(int c)
 # 80 "d_c99_bool_strict_syshdr.c" 3 4
 	    (int)((ctype_table + 1)[c] & 0x0040) != 0	/* BOOL */
 # 82 "d_c99_bool_strict_syshdr.c"
-	;			/* expect: 107 */
+	;
 
 	if (
 # 86 "d_c99_bool_strict_syshdr.c" 3 4
 	    (int)((ctype_table + 1)[c] & 0x0040)	/* INT */
 # 88 "d_c99_bool_strict_syshdr.c"
-	)			/*FIXME*//* expect: 333 */
+	)
 		println("system macro returning INT");
 
 	if (
Index: src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.exp
diff -u src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.exp:1.3 src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.exp:1.4
--- src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.exp:1.3	Sat Jan 23 19:03:55 2021
+++ src/tests/usr.bin/xlint/lint1/d_c99_bool_strict_syshdr.exp	Sat Jan 23 22:20:18 2021
@@ -1,8 +1,6 @@
 d_c99_bool_strict_syshdr.c(32): controlling expression must be bool, not 'int' [333]
 d_c99_bool_strict_syshdr.c(42): controlling expression must be bool, not 'int' [333]
 d_c99_bool_strict_syshdr.c(76): operands of '=' have incompatible types (_Bool != int) [107]
-d_c99_bool_strict_syshdr.c(82): operands of '=' have incompatible types (int != _Bool) [107]
-d_c99_bool_strict_syshdr.c(88): controlling expression must be bool, not 'int' [333]
 d_c99_bool_strict_syshdr.c(121): operands of '!=' have incompatible types (_Bool != int) [107]
 d_c99_bool_strict_syshdr.c(121): warning: function ch_isspace_sys_bool expects to return value [214]
 d_c99_bool_strict_syshdr.c(115): warning: argument c unused in function ch_isspace_sys_bool [231]

Index: src/usr.bin/xlint/lint1/externs1.h
diff -u src/usr.bin/xlint/lint1/externs1.h:1.60 src/usr.bin/xlint/lint1/externs1.h:1.61
--- src/usr.bin/xlint/lint1/externs1.h:1.60	Sat Jan 23 17:58:03 2021
+++ src/usr.bin/xlint/lint1/externs1.h	Sat Jan 23 22:20:17 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: externs1.h,v 1.60 2021/01/23 17:58:03 rillig Exp $	*/
+/*	$NetBSD: externs1.h,v 1.61 2021/01/23 22:20:17 rillig Exp $	*/
 
 /*
  * Copyright (c) 1994, 1995 Jochen Pohl
@@ -205,7 +205,7 @@ extern	tnode_t	*new_string_node(strg_t *
 extern	sym_t	*struct_or_union_member(tnode_t *, op_t, sym_t *);
 extern	tnode_t	*build(op_t, tnode_t *, tnode_t *);
 extern	tnode_t	*cconv(tnode_t *);
-extern	bool	is_strict_bool(const tnode_t *);
+extern	bool	is_typeok_bool_operand(const tnode_t *);
 extern	bool	typeok(op_t, int, const tnode_t *, const tnode_t *);
 extern	tnode_t	*promote(op_t, bool, tnode_t *);
 extern	tnode_t	*convert(op_t, int, type_t *, tnode_t *);

Index: src/usr.bin/xlint/lint1/func.c
diff -u src/usr.bin/xlint/lint1/func.c:1.64 src/usr.bin/xlint/lint1/func.c:1.65
--- src/usr.bin/xlint/lint1/func.c:1.64	Mon Jan 18 20:02:34 2021
+++ src/usr.bin/xlint/lint1/func.c	Sat Jan 23 22:20:17 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: func.c,v 1.64 2021/01/18 20:02:34 rillig Exp $	*/
+/*	$NetBSD: func.c,v 1.65 2021/01/23 22:20:17 rillig Exp $	*/
 
 /*
  * Copyright (c) 1994, 1995 Jochen Pohl
@@ -37,7 +37,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: func.c,v 1.64 2021/01/18 20:02:34 rillig Exp $");
+__RCSID("$NetBSD: func.c,v 1.65 2021/01/23 22:20:17 rillig Exp $");
 #endif
 
 #include <stdlib.h>
@@ -550,7 +550,7 @@ check_controlling_expression(tnode_t *tn
 		return NULL;
 	}
 
-	if (tn != NULL && Tflag && !is_strict_bool(tn)) {
+	if (tn != NULL && Tflag && !is_typeok_bool_operand(tn)) {
 		/* controlling expression must be bool, not '%s' */
 		error(333, tspec_name(tn->tn_type->t_tspec));
 		return NULL;

Index: src/usr.bin/xlint/lint1/lint1.h
diff -u src/usr.bin/xlint/lint1/lint1.h:1.59 src/usr.bin/xlint/lint1/lint1.h:1.60
--- src/usr.bin/xlint/lint1/lint1.h:1.59	Mon Jan 18 19:24:09 2021
+++ src/usr.bin/xlint/lint1/lint1.h	Sat Jan 23 22:20:17 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: lint1.h,v 1.59 2021/01/18 19:24:09 rillig Exp $ */
+/* $NetBSD: lint1.h,v 1.60 2021/01/23 22:20:17 rillig Exp $ */
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All Rights Reserved.
@@ -288,6 +288,7 @@ typedef	struct tnode {
 	bool	tn_lvalue : 1;	/* node is lvalue */
 	bool	tn_cast : 1;	/* if tn_op == CVT, it's an explicit cast */
 	bool	tn_parenthesized : 1;
+	bool	tn_from_system_header : 1;
 	union {
 		struct {
 			struct	tnode *_tn_left;	/* (left) operand */

Index: src/usr.bin/xlint/lint1/mem1.c
diff -u src/usr.bin/xlint/lint1/mem1.c:1.24 src/usr.bin/xlint/lint1/mem1.c:1.25
--- src/usr.bin/xlint/lint1/mem1.c:1.24	Mon Jan 18 20:02:34 2021
+++ src/usr.bin/xlint/lint1/mem1.c	Sat Jan 23 22:20:17 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: mem1.c,v 1.24 2021/01/18 20:02:34 rillig Exp $	*/
+/*	$NetBSD: mem1.c,v 1.25 2021/01/23 22:20:17 rillig Exp $	*/
 
 /*
  * Copyright (c) 1994, 1995 Jochen Pohl
@@ -37,7 +37,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: mem1.c,v 1.24 2021/01/18 20:02:34 rillig Exp $");
+__RCSID("$NetBSD: mem1.c,v 1.25 2021/01/23 22:20:17 rillig Exp $");
 #endif
 
 #include <sys/types.h>
@@ -348,13 +348,14 @@ tgetblk(size_t s)
 }
 
 /*
- * Get memory for a new tree node.
+ * Return a freshly allocated tree node.
  */
 tnode_t *
 getnode(void)
 {
-
-	return tgetblk(sizeof (tnode_t));
+	tnode_t *tn = tgetblk(sizeof *tn);
+	tn->tn_from_system_header = in_system_header;
+	return tn;
 }
 
 /*

Index: src/usr.bin/xlint/lint1/tree.c
diff -u src/usr.bin/xlint/lint1/tree.c:1.182 src/usr.bin/xlint/lint1/tree.c:1.183
--- src/usr.bin/xlint/lint1/tree.c:1.182	Mon Jan 18 20:02:34 2021
+++ src/usr.bin/xlint/lint1/tree.c	Sat Jan 23 22:20:17 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: tree.c,v 1.182 2021/01/18 20:02:34 rillig Exp $	*/
+/*	$NetBSD: tree.c,v 1.183 2021/01/23 22:20:17 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.182 2021/01/18 20:02:34 rillig Exp $");
+__RCSID("$NetBSD: tree.c,v 1.183 2021/01/23 22:20:17 rillig Exp $");
 #endif
 
 #include <float.h>
@@ -722,25 +722,24 @@ before_conversion(const tnode_t *tn)
 	return tn;
 }
 
-static bool
-is_bool_compatible(tspec_t t, const tnode_t *tn)
-{
-	if (t == BOOL)
-		return true;
-	return in_system_header && t == INT && tn->tn_op == CON &&
-	       (tn->tn_val->v_quad == 0 || tn->tn_val->v_quad == 1);
-}
-
-/* In strict bool mode, see if the node's type is compatible with bool. */
+/*
+ * See if the node is valid as operand of an operator that compares its
+ * argument with 0.
+ */
 bool
-is_strict_bool(const tnode_t *tn)
+is_typeok_bool_operand(const tnode_t *tn)
 {
 	tspec_t t;
 
+	lint_assert(Tflag);
+
 	tn = before_conversion(tn);
 	t = tn->tn_type->t_tspec;
 
-	if (is_bool_compatible(t, tn))
+	if (t == BOOL)
+		return true;
+
+	if (tn->tn_from_system_header && is_scalar(t))
 		return true;
 
 	/* For enums that are used as bit sets, allow "flags & FLAG". */
@@ -1101,18 +1100,54 @@ typeok_assign(const mod_t *mp, const tno
 }
 
 /*
- * Whether the operator can handle (bool, bool) as well as (scalar, scalar),
- * but not mixtures between the two type classes.
+ * See if in strict bool mode, the operator takes either two bool operands
+ * or two arbitrary other operands.
  */
 static bool
-needs_compatible_types(op_t op)
+is_assignment_bool_or_other(op_t op)
+{
+	return op == ASSIGN ||
+	       op == ANDASS || op == XORASS || op == ORASS ||
+	       op == RETURN || op == FARG;
+}
+
+static bool
+is_symmetric_bool_or_other(op_t op)
 {
 	return op == EQ || op == NE ||
 	       op == BITAND || op == BITXOR || op == BITOR ||
-	       op == COLON ||
-	       op == ASSIGN || op == ANDASS || op == XORASS || op == ORASS ||
-	       op == RETURN ||
-	       op == FARG;
+	       op == COLON;
+}
+
+static bool
+is_bool_int_constant(const tnode_t *tn, tspec_t t)
+{
+	return t == INT &&
+	       tn->tn_from_system_header &&
+	       tn->tn_op == CON &&
+	       (tn->tn_val->v_quad == 0 || tn->tn_val->v_quad == 1);
+}
+
+static bool
+is_typeok_strict_bool(op_t op,
+		      const tnode_t *ln, tspec_t lt,
+		      const tnode_t *rn, tspec_t rt)
+{
+	if (rn == NULL)
+		return true;	/* TODO: check unary operators as well. */
+
+	if ((lt == BOOL) == (rt == BOOL))
+		return true;
+
+	if (is_bool_int_constant(ln, lt) || is_bool_int_constant(rn, rt))
+		return true;
+
+	if (is_assignment_bool_or_other(op)) {
+		return lt != BOOL &&
+		       (ln->tn_from_system_header || rn->tn_from_system_header);
+	}
+
+	return !is_symmetric_bool_or_other(op);
 }
 
 /*
@@ -1129,9 +1164,7 @@ typeok_strict_bool_compatible(op_t op, i
 			      const tnode_t *rn, tspec_t rt)
 {
 
-	if (!needs_compatible_types(op))
-		return true;
-	if (is_bool_compatible(lt, ln) == is_bool_compatible(rt, rn))
+	if (is_typeok_strict_bool(op, ln, lt, rn, rt))
 		return true;
 
 	if (op == FARG) {
@@ -1175,7 +1208,7 @@ typeok_scalar_strict_bool(op_t op, const
 
 	if (mp->m_requires_bool || op == QUEST) {
 		bool binary = mp->m_binary;
-		bool lbool = is_strict_bool(ln);
+		bool lbool = is_typeok_bool_operand(ln);
 		bool ok = true;
 
 		if (!binary && !lbool) {
@@ -1188,7 +1221,7 @@ typeok_scalar_strict_bool(op_t op, const
 			error(331, getopname(op), tspec_name(lt));
 			ok = false;
 		}
-		if (binary && op != QUEST && !is_strict_bool(rn)) {
+		if (binary && op != QUEST && !is_typeok_bool_operand(rn)) {
 			/* right operand of '%s' must be bool, not '%s' */
 			error(332, getopname(op), tspec_name(rt));
 			ok = false;
@@ -1521,7 +1554,7 @@ check_assign_types_compatible(op_t op, i
 	if (lt == BOOL && is_scalar(rt))	/* C99 6.3.1.2 */
 		return true;
 
-	if (is_arithmetic(lt) && is_arithmetic(rt))
+	if (is_arithmetic(lt) && (is_arithmetic(rt) || rt == BOOL))
 		return true;
 
 	if ((lt == STRUCT || lt == UNION) && (rt == STRUCT || rt == UNION))
@@ -1773,6 +1806,10 @@ new_tnode(op_t op, type_t *type, tnode_t
 
 	ntn->tn_op = op;
 	ntn->tn_type = type;
+	if (ln->tn_from_system_header)
+		ntn->tn_from_system_header = true;
+	if (rn != NULL && rn->tn_from_system_header)
+		ntn->tn_from_system_header = true;
 	ntn->tn_left = ln;
 	ntn->tn_right = rn;
 
@@ -2019,6 +2056,7 @@ convert(op_t op, int arg, type_t *tp, tn
 	ntn->tn_op = CVT;
 	ntn->tn_type = tp;
 	ntn->tn_cast = op == CVT;
+	ntn->tn_from_system_header |= tn->tn_from_system_header;
 	ntn->tn_right = NULL;
 	if (tn->tn_op != CON || nt == VOID) {
 		ntn->tn_left = tn;

Reply via email to