Module Name:    src
Committed By:   rillig
Date:           Sat Jan  9 19:07:07 UTC 2021

Modified Files:
        src/usr.bin/xlint/lint1: tree.c

Log Message:
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.


To generate a diff of this commit:
cvs rdiff -u -r1.139 -r1.140 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/tree.c
diff -u src/usr.bin/xlint/lint1/tree.c:1.139 src/usr.bin/xlint/lint1/tree.c:1.140
--- src/usr.bin/xlint/lint1/tree.c:1.139	Sat Jan  9 18:21:08 2021
+++ src/usr.bin/xlint/lint1/tree.c	Sat Jan  9 19:07:07 2021
@@ -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 @@ typeok_amper(mod_t *const mp,
 	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 @@ typeok(op_t op, int arg, tnode_t *ln, tn
 			return 0;
 		break;
 	case STAR:
-		/* until now there were no type checks for this operator */
-		if (lt != PTR) {
-			/* cannot dereference non-pointer type */
-			error(96);
+		if (!typeok_star(lt))
 			return 0;
-		}
 		break;
 	case PLUS:
-		/* 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);
+		if (!typeok_plus(op, lt, rt))
 			return 0;
-		}
 		break;
 	case MINUS:
-		/* operands have scalar types (checked above) */
-		if (lt == PTR && (!tspec_is_int(rt) && rt != PTR)) {
-			warn_incompatible_types(op, lt, rt);
-			return 0;
-		} else if (rt == PTR && lt != PTR) {
-			warn_incompatible_types(op, lt, rt);
+		if (!typeok_minus(op, lt, lstp, rt, rstp))
 			return 0;
-		}
-		if (lt == PTR && rt == PTR) {
-			if (!eqtype(lstp, rstp, 1, 0, NULL)) {
-				/* illegal pointer subtraction */
-				error(116);
-			}
-		}
 		break;
 	case SHR:
-		/* 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 poss. 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; ... */
-				warning(118, mp->m_name);
-			}
-		}
+		typeok_shr(mp, ln, lt, olt, rt, ort);
 		goto shift;
 	case SHL:
-		/*
-		 * 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; ... */
-				warning(118, mp->m_name);
-		}
+		typeok_shl(mp, lt, rt);
 	shift:
-		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);
-			}
-		}
+		typeok_shift(lt, rn, rt);
 		break;
 	case EQ:
 	case NE:
@@ -959,108 +1143,27 @@ typeok(op_t op, int arg, tnode_t *ln, tn
 		 * Accept some things which are allowed with EQ and NE,
 		 * but not with ordered comparisons.
 		 */
-		if (lt == PTR && ((rt == PTR && rst == VOID) ||
-				  tspec_is_int(rt))) {
-			if (rn->tn_op == CON && rn->tn_val->v_quad == 0)
-				break;
-		}
-		if (rt == PTR && ((lt == PTR && lst == VOID) ||
-				  tspec_is_int(lt))) {
-			if (ln->tn_op == CON && ln->tn_val->v_quad == 0)
-				break;
-		}
+		if (typeok_eq(ln, lt, lst, rn, rt, rst))
+			break;
 		/* FALLTHROUGH */
 	case LT:
 	case GT:
 	case LE:
 	case GE:
-		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 0;
-			}
-		} else if (lt == PTR && rt == PTR) {
-			check_pointer_comparison(op, ln, rn);
-		}
+		if (!typeok_ordered_comparison(op, mp,
+		    ln, ltp, lt, rn, rtp, rt))
+			return 0;
 		break;
 	case QUEST:
-		if (!tspec_is_scalar(lt)) {
-			/* first operand must have scalar type, op ? : */
-			error(170);
+		if (!typeok_quest(lt, &rn))
 			return 0;
-		}
-		while (rn->tn_op == CVT)
-			rn = rn->tn_left;
-		lint_assert(rn->tn_op == COLON);
 		break;
 	case COLON:
-		if (tspec_is_arith(lt) && tspec_is_arith(rt))
-			break;
-
-		if (lt == STRUCT && rt == STRUCT && ltp->t_str == rtp->t_str)
-			break;
-		if (lt == UNION && rt == UNION && ltp->t_str == rtp->t_str)
-			break;
-
-		/* 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)
-				break;
-		}
-		if (rt == PTR && ((lt == PTR && lst == VOID) ||
-				  tspec_is_int(lt))) {
-			if (ln->tn_op == CON && ln->tn_val->v_quad == 0)
-				break;
-		}
-
-		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);
-			break;
-		}
-
-		if (lt == VOID || rt == VOID) {
-			if (lt != VOID || rt != VOID)
-				/* incompatible types in conditional */
-				warning(126);
-			break;
-		}
-
-		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);
-			break;
-		}
-
-		if (rt == PTR && lt == PTR) {
-			if (eqptrtype(lstp, rstp, 1))
-				break;
-			if (!eqtype(lstp, rstp, 1, 0, NULL))
-				warn_incompatible_pointers(mp, ltp, rtp);
-			break;
-		}
-
-		/* incompatible types in conditional */
-		error(126);
-		return 0;
-
+		if (!typeok_colon(mp,
+		    ln, ltp, lt, lstp, lst,
+		    rn, rtp, rt, rstp, rst))
+			return 0;
+		break;
 	case ASSIGN:
 	case INIT:
 	case FARG:
@@ -1094,23 +1197,8 @@ typeok(op_t op, int arg, tnode_t *ln, tn
 	case ORASS:
 		goto assign;
 	assign:
-		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)
-					break;
-				/* a cast does not yield an lvalue */
-				error(163);
-			}
-			/* %soperand of '%s' must be lvalue */
-			error(114, "left ", mp->m_name);
+		if (!typeok_assign(mp, ln, ltp, lt))
 			return 0;
-		} 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);
-		}
 		break;
 	case COMMA:
 		if (!modtab[ln->tn_op].m_sideeff)

Reply via email to