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;