Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/usr.bin/xlint/lint1 lint: split typeok into several smaller ...
details: https://anonhg.NetBSD.org/src/rev/d78d3a3f5add
branches: trunk
changeset: 958535:d78d3a3f5add
user: rillig <rillig%NetBSD.org@localhost>
date: Sat Jan 09 19:07:07 2021 +0000
description:
lint: split typeok into several smaller functions
This reduces the number of local variables from 16 to around 5, in most
of the smaller functions.
No functional change.
diffstat:
usr.bin/xlint/lint1/tree.c | 488 ++++++++++++++++++++++++++------------------
1 files changed, 288 insertions(+), 200 deletions(-)
diffs (truncated from 553 to 300 lines):
diff -r 9e3941bcce64 -r d78d3a3f5add usr.bin/xlint/lint1/tree.c
--- a/usr.bin/xlint/lint1/tree.c Sat Jan 09 18:26:03 2021 +0000
+++ b/usr.bin/xlint/lint1/tree.c Sat Jan 09 19:07:07 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tree.c,v 1.139 2021/01/09 18:21:08 rillig Exp $ */
+/* $NetBSD: tree.c,v 1.140 2021/01/09 19:07:07 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.139 2021/01/09 18:21:08 rillig Exp $");
+__RCSID("$NetBSD: tree.c,v 1.140 2021/01/09 19:07:07 rillig Exp $");
#endif
#include <float.h>
@@ -745,6 +745,274 @@
return true;
}
+static bool
+typeok_star(tspec_t lt)
+{
+ /* until now there were no type checks for this operator */
+ if (lt != PTR) {
+ /* cannot dereference non-pointer type */
+ error(96);
+ return false;
+ }
+ return true;
+}
+
+static bool
+typeok_plus(op_t op, tspec_t lt, tspec_t rt)
+{
+ /* operands have scalar types (checked above) */
+ if ((lt == PTR && !tspec_is_int(rt)) ||
+ (rt == PTR && !tspec_is_int(lt))) {
+ warn_incompatible_types(op, lt, rt);
+ return false;
+ }
+ return true;
+}
+
+static bool
+typeok_minus(op_t op, tspec_t lt, type_t *lstp, tspec_t rt, type_t *rstp)
+{
+ /* operands have scalar types (checked above) */
+ if (lt == PTR && (!tspec_is_int(rt) && rt != PTR)) {
+ warn_incompatible_types(op, lt, rt);
+ return false;
+ } else if (rt == PTR && lt != PTR) {
+ warn_incompatible_types(op, lt, rt);
+ return false;
+ }
+ if (lt == PTR && rt == PTR) {
+ if (!eqtype(lstp, rstp, 1, 0, NULL)) {
+ /* illegal pointer subtraction */
+ error(116);
+ }
+ }
+ return true;
+}
+
+static void
+typeok_shr(mod_t *mp,
+ tnode_t *ln, tspec_t lt, tspec_t olt,
+ tspec_t rt, tspec_t ort)
+{
+ /* operands have integer types (checked above) */
+ if (pflag && !tspec_is_uint(lt)) {
+ /*
+ * The left operand is signed. This means that
+ * the operation is (possibly) nonportable.
+ */
+ if (ln->tn_op != CON) {
+ /* bitop. on signed value possibly nonportable */
+ warning(117);
+ } else if (ln->tn_val->v_quad < 0) {
+ /* bitop. on signed value nonportable */
+ warning(120);
+ }
+ } else if (!tflag && !sflag &&
+ !tspec_is_uint(olt) && tspec_is_uint(ort)) {
+ /*
+ * The left operand would become unsigned in
+ * traditional C.
+ */
+ if (hflag &&
+ (ln->tn_op != CON || ln->tn_val->v_quad < 0)) {
+ /* semantics of '%s' change in ANSI C; ... */
+ warning(118, mp->m_name);
+ }
+ } else if (!tflag && !sflag &&
+ !tspec_is_uint(olt) && !tspec_is_uint(ort) &&
+ psize(lt) < psize(rt)) {
+ /*
+ * In traditional C the left operand would be extended,
+ * possibly with 1, and then shifted.
+ */
+ if (hflag &&
+ (ln->tn_op != CON || ln->tn_val->v_quad < 0)) {
+ /* semantics of '%s' change in ANSI C; use ... */
+ warning(118, mp->m_name);
+ }
+ }
+}
+
+static void
+typeok_shl(mod_t *mp, tspec_t lt, tspec_t rt) {
+ /*
+ * ANSI C does not perform balancing for shift operations,
+ * but traditional C does. If the width of the right operand
+ * is greater than the width of the left operand, than in
+ * traditional C the left operand would be extended to the
+ * width of the right operand. For SHL this may result in
+ * different results.
+ */
+ if (psize(lt) < psize(rt)) {
+ /*
+ * XXX If both operands are constant, make sure
+ * that there is really a difference between
+ * ANSI C and traditional C.
+ */
+ if (hflag)
+ /* semantics of '%s' change in ANSI C; use ... */
+ warning(118, mp->m_name);
+ }
+}
+
+static void
+typeok_shift(tspec_t lt, tnode_t *rn, tspec_t rt)
+{
+ if (rn->tn_op == CON) {
+ if (!tspec_is_uint(rt) && rn->tn_val->v_quad < 0) {
+ /* negative shift */
+ warning(121);
+ } else if ((uint64_t)rn->tn_val->v_quad == (uint64_t)size(lt)) {
+ /* shift equal to size of object */
+ warning(267);
+ } else if ((uint64_t)rn->tn_val->v_quad > (uint64_t)size(lt)) {
+ /* shift greater than size of object */
+ warning(122);
+ }
+ }
+}
+
+static bool
+typeok_eq(tnode_t *ln, tspec_t lt, tspec_t lst,
+ tnode_t *rn, tspec_t rt, tspec_t rst)
+{
+ if (lt == PTR && ((rt == PTR && rst == VOID) ||
+ tspec_is_int(rt))) {
+ if (rn->tn_op == CON && rn->tn_val->v_quad == 0)
+ return true;
+ }
+ if (rt == PTR && ((lt == PTR && lst == VOID) ||
+ tspec_is_int(lt))) {
+ if (ln->tn_op == CON && ln->tn_val->v_quad == 0)
+ return true;
+ }
+ return false;
+}
+
+static bool
+typeok_ordered_comparison(op_t op, mod_t *mp,
+ tnode_t *ln, type_t *ltp, tspec_t lt,
+ tnode_t *rn, type_t *rtp, tspec_t rt)
+{
+ if ((lt == PTR || rt == PTR) && lt != rt) {
+ if (tspec_is_int(lt) || tspec_is_int(rt)) {
+ const char *lx = lt == PTR ?
+ "pointer" : "integer";
+ const char *rx = rt == PTR ?
+ "pointer" : "integer";
+ /* illegal combination of %s (%s) and ... */
+ warning(123, lx, type_name(ltp),
+ rx, type_name(rtp), mp->m_name);
+ } else {
+ warn_incompatible_types(op, lt, rt);
+ return false;
+ }
+ } else if (lt == PTR && rt == PTR) {
+ check_pointer_comparison(op, ln, rn);
+ }
+ return true;
+}
+
+static bool
+typeok_quest(tspec_t lt, tnode_t **rn)
+{
+ if (!tspec_is_scalar(lt)) {
+ /* first operand must have scalar type, op ? : */
+ error(170);
+ return false;
+ }
+ while ((*rn)->tn_op == CVT)
+ *rn = (*rn)->tn_left;
+ lint_assert((*rn)->tn_op == COLON);
+ return true;
+}
+
+static bool
+typeok_colon(mod_t *mp,
+ tnode_t *ln, type_t *ltp, tspec_t lt, type_t *lstp, tspec_t lst,
+ tnode_t *rn, type_t *rtp, tspec_t rt, type_t *rstp, tspec_t rst)
+{
+ if (tspec_is_arith(lt) && tspec_is_arith(rt))
+ return true;
+
+ if (lt == STRUCT && rt == STRUCT && ltp->t_str == rtp->t_str)
+ return true;
+ if (lt == UNION && rt == UNION && ltp->t_str == rtp->t_str)
+ return true;
+
+ /* combination of any pointer and 0, 0L or (void *)0 is ok */
+ if (lt == PTR && ((rt == PTR && rst == VOID) || tspec_is_int(rt))) {
+ if (rn->tn_op == CON && rn->tn_val->v_quad == 0)
+ return true;
+ }
+ if (rt == PTR && ((lt == PTR && lst == VOID) || tspec_is_int(lt))) {
+ if (ln->tn_op == CON && ln->tn_val->v_quad == 0)
+ return true;
+ }
+
+ if ((lt == PTR && tspec_is_int(rt)) ||
+ (tspec_is_int(lt) && rt == PTR)) {
+ const char *lx = lt == PTR ? "pointer" : "integer";
+ const char *rx = rt == PTR ? "pointer" : "integer";
+ /* illegal combination of %s (%s) and %s (%s), op %s */
+ warning(123, lx, type_name(ltp),
+ rx, type_name(rtp), mp->m_name);
+ return true;
+ }
+
+ if (lt == VOID || rt == VOID) {
+ if (lt != VOID || rt != VOID)
+ /* incompatible types in conditional */
+ warning(126);
+ return true;
+ }
+
+ if (lt == PTR && rt == PTR && ((lst == VOID && rst == FUNC) ||
+ (lst == FUNC && rst == VOID))) {
+ /* (void *)0 handled above */
+ if (sflag)
+ /* ANSI C forbids conv. of %s to %s, op %s */
+ warning(305, "function pointer", "'void *'",
+ mp->m_name);
+ return true;
+ }
+
+ if (rt == PTR && lt == PTR) {
+ if (eqptrtype(lstp, rstp, 1))
+ return true;
+ if (!eqtype(lstp, rstp, 1, 0, NULL))
+ warn_incompatible_pointers(mp, ltp, rtp);
+ return true;
+ }
+
+ /* incompatible types in conditional */
+ error(126);
+ return false;
+}
+
+static bool
+typeok_assign(mod_t *mp, tnode_t *ln, type_t *ltp, tspec_t lt)
+{
+ if (!ln->tn_lvalue) {
+ if (ln->tn_op == CVT && ln->tn_cast &&
+ ln->tn_left->tn_op == LOAD) {
+ if (ln->tn_type->t_tspec == PTR)
+ return true;
+ /* a cast does not yield an lvalue */
+ error(163);
+ }
+ /* %soperand of '%s' must be lvalue */
+ error(114, "left ", mp->m_name);
+ return false;
+ } else if (ltp->t_const || ((lt == STRUCT || lt == UNION) &&
+ has_constant_member(ltp))) {
+ if (!tflag)
+ /* %soperand of '%s' must be modifiable lvalue */
+ warning(115, "left ", mp->m_name);
+ }
+ return true;
+}
+
/*
* Perform most type checks. First the types are checked using
* the information from modtab[]. After that it is done by hand for
@@ -850,108 +1118,24 @@
return 0;
break;
case STAR:
- /* until now there were no type checks for this operator */
- if (lt != PTR) {
- /* cannot dereference non-pointer type */
Home |
Main Index |
Thread Index |
Old Index