Module Name: src
Committed By: rillig
Date: Tue Apr 6 13:17:04 UTC 2021
Modified Files:
src/usr.bin/xlint/lint1: Makefile externs1.h tree.c
Added Files:
src/usr.bin/xlint/lint1: ckbool.c
Log Message:
lint: move check for strict bool mode into separate file
No functional change.
To generate a diff of this commit:
cvs rdiff -u -r1.65 -r1.66 src/usr.bin/xlint/lint1/Makefile
cvs rdiff -u -r0 -r1.1 src/usr.bin/xlint/lint1/ckbool.c
cvs rdiff -u -r1.100 -r1.101 src/usr.bin/xlint/lint1/externs1.h
cvs rdiff -u -r1.266 -r1.267 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/usr.bin/xlint/lint1/Makefile
diff -u src/usr.bin/xlint/lint1/Makefile:1.65 src/usr.bin/xlint/lint1/Makefile:1.66
--- src/usr.bin/xlint/lint1/Makefile:1.65 Mon Apr 5 02:05:47 2021
+++ src/usr.bin/xlint/lint1/Makefile Tue Apr 6 13:17:04 2021
@@ -1,10 +1,11 @@
-# $NetBSD: Makefile,v 1.65 2021/04/05 02:05:47 rillig Exp $
+# $NetBSD: Makefile,v 1.66 2021/04/06 13:17:04 rillig Exp $
.include <bsd.own.mk>
PROG= lint1
-SRCS= cgram.y ckctype.c ckgetopt.c decl.c emit.c emit1.c err.c \
- func.c init.c inittyp.c lex.c \
+SRCS= cgram.y \
+ ckbool.c ckctype.c ckgetopt.c \
+ decl.c emit.c emit1.c err.c func.c init.c inittyp.c lex.c \
main1.c mem.c mem1.c oper.c print.c scan.l tree.c tyname.c
MAN= lint.7
Index: src/usr.bin/xlint/lint1/externs1.h
diff -u src/usr.bin/xlint/lint1/externs1.h:1.100 src/usr.bin/xlint/lint1/externs1.h:1.101
--- src/usr.bin/xlint/lint1/externs1.h:1.100 Mon Apr 5 02:05:47 2021
+++ src/usr.bin/xlint/lint1/externs1.h Tue Apr 6 13:17:04 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: externs1.h,v 1.100 2021/04/05 02:05:47 rillig Exp $ */
+/* $NetBSD: externs1.h,v 1.101 2021/04/06 13:17:04 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@@ -336,6 +336,13 @@ extern int lex_input(void);
extern char *print_tnode(char *, size_t, const tnode_t *);
/*
+ * ckbool.c
+ */
+extern bool typeok_scalar_strict_bool(op_t, const mod_t *, int,
+ const tnode_t *, const tnode_t *);
+extern bool fallback_symbol_strict_bool(sym_t *);
+
+/*
* ckctype.c
*/
extern void check_ctype_function_call(const tnode_t *, const tnode_t *);
Index: src/usr.bin/xlint/lint1/tree.c
diff -u src/usr.bin/xlint/lint1/tree.c:1.266 src/usr.bin/xlint/lint1/tree.c:1.267
--- src/usr.bin/xlint/lint1/tree.c:1.266 Mon Apr 5 02:05:47 2021
+++ src/usr.bin/xlint/lint1/tree.c Tue Apr 6 13:17:04 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: tree.c,v 1.266 2021/04/05 02:05:47 rillig Exp $ */
+/* $NetBSD: tree.c,v 1.267 2021/04/06 13:17:04 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.266 2021/04/05 02:05:47 rillig Exp $");
+__RCSID("$NetBSD: tree.c,v 1.267 2021/04/06 13:17:04 rillig Exp $");
#endif
#include <float.h>
@@ -207,23 +207,8 @@ static void
fallback_symbol(sym_t *sym)
{
- if (Tflag && strcmp(sym->s_name, "__lint_false") == 0) {
- sym->s_scl = CTCONST; /* 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;
+ if (fallback_symbol_strict_bool(sym))
return;
- }
-
- if (Tflag && strcmp(sym->s_name, "__lint_true") == 0) {
- sym->s_scl = CTCONST; /* 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;
- return;
- }
if (block_level > 0 && (strcmp(sym->s_name, "__FUNCTION__") == 0 ||
strcmp(sym->s_name, "__PRETTY_FUNCTION__") == 0)) {
@@ -736,42 +721,6 @@ is_null_pointer(const tnode_t *tn)
&& (tn->tn_op == CON && tn->tn_val->v_quad == 0);
}
-/*
- * See if the node is valid as operand of an operator that compares its
- * argument with 0.
- */
-bool
-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 (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". */
- if (tn->tn_op == BITAND &&
- tn->tn_left->tn_op == CVT &&
- tn->tn_left->tn_type->t_tspec == INT && !tn->tn_left->tn_cast &&
- tn->tn_left->tn_left->tn_type->t_tspec == ENUM &&
- /*
- * XXX: Somehow the type information got lost here. The type
- * of the enum constant on the right-hand side should still be
- * ENUM, but is INT.
- */
- tn->tn_right->tn_type->t_tspec == INT)
- return true;
-
- return false;
-}
-
static bool
typeok_incdec(op_t op, const tnode_t *tn, const type_t *tp)
{
@@ -1109,159 +1058,7 @@ typeok_assign(const mod_t *mp, const tno
return true;
}
-/*
- * See if in strict bool mode, the operator takes either two bool operands
- * or two arbitrary other operands.
- */
-static bool
-is_assignment_bool_or_other(op_t op)
-{
- return op == ASSIGN ||
- op == ANDASS || op == XORASS || op == ORASS ||
- op == RETURN || op == INIT || 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;
-}
-
-static bool
-is_int_constant_zero(const tnode_t *tn, tspec_t t)
-{
- return t == INT && tn->tn_op == CON && tn->tn_val->v_quad == 0;
-}
-
-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 ((ln->tn_from_system_header || rn->tn_from_system_header) &&
- (is_int_constant_zero(ln, lt) || is_int_constant_zero(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);
-}
-
-/*
- * Some operators require that either both operands are bool or both are
- * scalar.
- *
- * Code that passes this check can be compiled in a pre-C99 environment that
- * doesn't implement the special rule C99 6.3.1.2, without silent change in
- * behavior.
- */
-static bool
-typeok_strict_bool_compatible(op_t op, int arg,
- const tnode_t *ln, tspec_t lt,
- const tnode_t *rn, tspec_t rt)
-{
-
- if (is_typeok_strict_bool(op, ln, lt, rn, rt))
- return true;
-
- if (op == FARG) {
- /* argument #%d expects '%s', gets passed '%s' */
- error(334, arg, tspec_name(lt), tspec_name(rt));
- } else if (op == RETURN) {
- /* return value type mismatch (%s) and (%s) */
- error(211, tspec_name(lt), tspec_name(rt));
- } else {
- /* operands of '%s' have incompatible types (%s != %s) */
- error(107, op_name(op), tspec_name(lt), tspec_name(rt));
- }
-
- return false;
-}
-
-/*
- * In strict bool mode, check whether the types of the operands match the
- * operator.
- */
-static bool
-typeok_scalar_strict_bool(op_t op, const mod_t *mp, int arg,
- const tnode_t *ln,
- const tnode_t *rn)
-
-{
- tspec_t lt, rt;
-
- ln = before_conversion(ln);
- lt = ln->tn_type->t_tspec;
-
- if (rn != NULL) {
- rn = before_conversion(rn);
- rt = rn->tn_type->t_tspec;
- } else {
- rt = NOTSPEC;
- }
-
- if (!typeok_strict_bool_compatible(op, arg, ln, lt, rn, rt))
- return false;
- if (mp->m_requires_bool || op == QUEST) {
- bool binary = mp->m_binary;
- bool lbool = is_typeok_bool_operand(ln);
- bool ok = true;
-
- if (!binary && !lbool) {
- /* operand of '%s' must be bool, not '%s' */
- error(330, op_name(op), tspec_name(lt));
- ok = false;
- }
- if (binary && !lbool) {
- /* left operand of '%s' must be bool, not '%s' */
- error(331, op_name(op), tspec_name(lt));
- ok = false;
- }
- if (binary && op != QUEST && !is_typeok_bool_operand(rn)) {
- /* right operand of '%s' must be bool, not '%s' */
- error(332, op_name(op), tspec_name(rt));
- ok = false;
- }
- return ok;
- }
-
- if (!mp->m_takes_bool) {
- bool binary = mp->m_binary;
- bool lbool = ln->tn_type->t_tspec == BOOL;
- bool ok = true;
-
- if (!binary && lbool) {
- /* operand of '%s' must not be bool */
- error(335, op_name(op));
- ok = false;
- }
- if (binary && lbool) {
- /* left operand of '%s' must not be bool */
- error(336, op_name(op));
- ok = false;
- }
- if (binary && rn->tn_type->t_tspec == BOOL) {
- /* right operand of '%s' must not be bool */
- error(337, op_name(op));
- ok = false;
- }
- return ok;
- }
-
- return true;
-}
/* Check the types using the information from modtab[]. */
static bool
Added files:
Index: src/usr.bin/xlint/lint1/ckbool.c
diff -u /dev/null src/usr.bin/xlint/lint1/ckbool.c:1.1
--- /dev/null Tue Apr 6 13:17:04 2021
+++ src/usr.bin/xlint/lint1/ckbool.c Tue Apr 6 13:17:04 2021
@@ -0,0 +1,270 @@
+/* $NetBSD: ckbool.c,v 1.1 2021/04/06 13:17:04 rillig Exp $ */
+
+/*-
+ * Copyright (c) 2021 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Roland Illig <[email protected]>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+
+#if defined(__RCSID) && !defined(lint)
+__RCSID("$NetBSD: ckbool.c,v 1.1 2021/04/06 13:17:04 rillig Exp $");
+#endif
+
+#include <string.h>
+
+#include "lint1.h"
+
+
+/*
+ * The option -T treats _Bool as incompatible with all other scalar types.
+ * See d_c99_bool_strict.c for the exact rules and for examples.
+ */
+
+static const char *
+op_name(op_t op)
+{
+ return modtab[op].m_name;
+}
+
+/*
+ * See if in strict bool mode, the operator takes either two bool operands
+ * or two arbitrary other operands.
+ */
+static bool
+is_assignment_bool_or_other(op_t op)
+{
+ return op == ASSIGN ||
+ op == ANDASS || op == XORASS || op == ORASS ||
+ op == RETURN || op == INIT || 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;
+}
+
+static bool
+is_int_constant_zero(const tnode_t *tn, tspec_t t)
+{
+ return t == INT && tn->tn_op == CON && tn->tn_val->v_quad == 0;
+}
+
+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 ((ln->tn_from_system_header || rn->tn_from_system_header) &&
+ (is_int_constant_zero(ln, lt) || is_int_constant_zero(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);
+}
+
+/*
+ * Some operators require that either both operands are bool or both are
+ * scalar.
+ *
+ * Code that passes this check can be compiled in a pre-C99 environment that
+ * doesn't implement the special rule C99 6.3.1.2, without silent change in
+ * behavior.
+ */
+static bool
+typeok_strict_bool_compatible(op_t op, int arg,
+ const tnode_t *ln, tspec_t lt,
+ const tnode_t *rn, tspec_t rt)
+{
+
+ if (is_typeok_strict_bool(op, ln, lt, rn, rt))
+ return true;
+
+ if (op == FARG) {
+ /* argument #%d expects '%s', gets passed '%s' */
+ error(334, arg, tspec_name(lt), tspec_name(rt));
+ } else if (op == RETURN) {
+ /* return value type mismatch (%s) and (%s) */
+ error(211, tspec_name(lt), tspec_name(rt));
+ } else {
+ /* operands of '%s' have incompatible types (%s != %s) */
+ error(107, op_name(op), tspec_name(lt), tspec_name(rt));
+ }
+
+ return false;
+}
+
+/*
+ * In strict bool mode, check whether the types of the operands match the
+ * operator.
+ */
+bool
+typeok_scalar_strict_bool(op_t op, const mod_t *mp, int arg,
+ const tnode_t *ln,
+ const tnode_t *rn)
+
+{
+ tspec_t lt, rt;
+
+ ln = before_conversion(ln);
+ lt = ln->tn_type->t_tspec;
+
+ if (rn != NULL) {
+ rn = before_conversion(rn);
+ rt = rn->tn_type->t_tspec;
+ } else {
+ rt = NOTSPEC;
+ }
+
+ if (!typeok_strict_bool_compatible(op, arg, ln, lt, rn, rt))
+ return false;
+
+ if (mp->m_requires_bool || op == QUEST) {
+ bool binary = mp->m_binary;
+ bool lbool = is_typeok_bool_operand(ln);
+ bool ok = true;
+
+ if (!binary && !lbool) {
+ /* operand of '%s' must be bool, not '%s' */
+ error(330, op_name(op), tspec_name(lt));
+ ok = false;
+ }
+ if (binary && !lbool) {
+ /* left operand of '%s' must be bool, not '%s' */
+ error(331, op_name(op), tspec_name(lt));
+ ok = false;
+ }
+ if (binary && op != QUEST && !is_typeok_bool_operand(rn)) {
+ /* right operand of '%s' must be bool, not '%s' */
+ error(332, op_name(op), tspec_name(rt));
+ ok = false;
+ }
+ return ok;
+ }
+
+ if (!mp->m_takes_bool) {
+ bool binary = mp->m_binary;
+ bool lbool = ln->tn_type->t_tspec == BOOL;
+ bool ok = true;
+
+ if (!binary && lbool) {
+ /* operand of '%s' must not be bool */
+ error(335, op_name(op));
+ ok = false;
+ }
+ if (binary && lbool) {
+ /* left operand of '%s' must not be bool */
+ error(336, op_name(op));
+ ok = false;
+ }
+ if (binary && rn->tn_type->t_tspec == BOOL) {
+ /* right operand of '%s' must not be bool */
+ error(337, op_name(op));
+ ok = false;
+ }
+ return ok;
+ }
+
+ return true;
+}
+
+/*
+ * See if the node is valid as operand of an operator that compares its
+ * argument with 0.
+ */
+bool
+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 (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". */
+ if (tn->tn_op == BITAND &&
+ tn->tn_left->tn_op == CVT &&
+ tn->tn_left->tn_type->t_tspec == INT && !tn->tn_left->tn_cast &&
+ tn->tn_left->tn_left->tn_type->t_tspec == ENUM &&
+ /*
+ * XXX: Somehow the type information got lost here. The type
+ * of the enum constant on the right-hand side should still be
+ * ENUM, but is INT.
+ */
+ tn->tn_right->tn_type->t_tspec == INT)
+ return true;
+
+ return false;
+}
+
+bool
+fallback_symbol_strict_bool(sym_t *sym)
+{
+ if (Tflag && strcmp(sym->s_name, "__lint_false") == 0) {
+ sym->s_scl = CTCONST; /* 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;
+ return true;
+ }
+
+ if (Tflag && strcmp(sym->s_name, "__lint_true") == 0) {
+ sym->s_scl = CTCONST; /* 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;
+ return true;
+ }
+
+ return false;
+}