Module Name:    src
Committed By:   rillig
Date:           Wed Jul  6 22:26:31 UTC 2022

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

Log Message:
lint: do not warn about 'may lose accuracy' in safe cases of '%'

The possible values of the expression 'a % b' for unsigned integers lie
between 0 and (b - 1).  For signed integers, it's more complicated, so
ignore them for now.


To generate a diff of this commit:
cvs rdiff -u -r1.22 -r1.23 src/tests/usr.bin/xlint/lint1/msg_132.c
cvs rdiff -u -r1.471 -r1.472 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/msg_132.c
diff -u src/tests/usr.bin/xlint/lint1/msg_132.c:1.22 src/tests/usr.bin/xlint/lint1/msg_132.c:1.23
--- src/tests/usr.bin/xlint/lint1/msg_132.c:1.22	Wed Jul  6 21:59:06 2022
+++ src/tests/usr.bin/xlint/lint1/msg_132.c	Wed Jul  6 22:26:31 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: msg_132.c,v 1.22 2022/07/06 21:59:06 rillig Exp $	*/
+/*	$NetBSD: msg_132.c,v 1.23 2022/07/06 22:26:31 rillig Exp $	*/
 # 3 "msg_132.c"
 
 // Test for message: conversion from '%s' to '%s' may lose accuracy [132]
@@ -290,18 +290,22 @@ void
 test_ic_mod(void)
 {
 	/* The result is between 0 and 254. */
-	/* expect+1: warning: conversion from 'unsigned long long' to 'unsigned char' may lose accuracy [132] */
 	u8 = u64 % u8;
 
+	/* The result is between 0 and 255. */
+	u8 = u64 % 256;
+
+	/* The result is between 0 and 256. */
+	/* expect+1: warning: conversion from 'unsigned long long' to 'unsigned char' may lose accuracy [132] */
+	u8 = u64 % 257;
+
 	/* The result is between 0 and 1000. */
 	/* expect+1: warning: conversion from 'unsigned long long' to 'unsigned char' may lose accuracy [132] */
 	u8 = u64 % 1000;
-	/* expect+1: warning: conversion from 'unsigned long long' to 'unsigned short' may lose accuracy [132] */
-	u16 = u64 % 1000;
 	/* expect+1: warning: conversion from 'unsigned long long' to 'unsigned int:9' may lose accuracy [132] */
 	bits.u9 = u64 % 1000;
-	/* expect+1: warning: conversion from 'unsigned long long' to 'unsigned int:10' may lose accuracy [132] */
 	bits.u10 = u64 % 1000;
+	u16 = u64 % 1000;
 
 	/*
 	 * For signed division, if the result of 'a / b' is not representable
@@ -309,8 +313,19 @@ test_ic_mod(void)
 	 * '(a / b) * a + a % b == a'.
 	 *
 	 * If the result of 'a / b' is not representable exactly, the result
-	 * of 'a % b' is not defined.
+	 * of 'a % b' is not defined.  Due to this uncertainty, lint does not
+	 * narrow down the range for signed modulo expressions.
 	 *
 	 * C90 6.3.5, C99 6.5.5.
 	 */
+
+	/* expect+1: warning: conversion from 'int' to 'signed char' may lose accuracy [132] */
+	s8 = s16 % s8;
+
+	/*
+	 * The result is always 0, it's a theoretical edge case though, so
+	 * lint doesn't care to implement this.
+	 */
+	/* expect+1: warning: conversion from 'long long' to 'signed char' may lose accuracy [132] */
+	s8 = s64 % 1;
 }

Index: src/usr.bin/xlint/lint1/tree.c
diff -u src/usr.bin/xlint/lint1/tree.c:1.471 src/usr.bin/xlint/lint1/tree.c:1.472
--- src/usr.bin/xlint/lint1/tree.c:1.471	Tue Jul  5 22:50:41 2022
+++ src/usr.bin/xlint/lint1/tree.c	Wed Jul  6 22:26:30 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: tree.c,v 1.471 2022/07/05 22:50:41 rillig Exp $	*/
+/*	$NetBSD: tree.c,v 1.472 2022/07/06 22:26:30 rillig Exp $	*/
 
 /*
  * Copyright (c) 1994, 1995 Jochen Pohl
@@ -37,7 +37,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID)
-__RCSID("$NetBSD: tree.c,v 1.471 2022/07/05 22:50:41 rillig Exp $");
+__RCSID("$NetBSD: tree.c,v 1.472 2022/07/06 22:26:30 rillig Exp $");
 #endif
 
 #include <float.h>
@@ -104,6 +104,18 @@ static	void	check_precedence_confusion(t
 
 extern sig_atomic_t fpe;
 
+static uint64_t
+u64_fill_right(uint64_t x)
+{
+	x |= x >> 1;
+	x |= x >> 2;
+	x |= x >> 4;
+	x |= x >> 8;
+	x |= x >> 16;
+	x |= x >> 32;
+	return x;
+}
+
 static bool
 ic_maybe_signed(const type_t *tp, const integer_constraints *ic)
 {
@@ -200,6 +212,23 @@ ic_bitor(integer_constraints a, integer_
 }
 
 static integer_constraints
+ic_mod(const type_t *tp, integer_constraints a, integer_constraints b)
+{
+	integer_constraints c;
+
+	if (ic_maybe_signed(tp, &a) || ic_maybe_signed(tp, &b))
+		return ic_any(tp);
+
+	c.smin = INT64_MIN;
+	c.smax = INT64_MAX;
+	c.umin = 0;
+	c.umax = b.umax - 1;
+	c.bset = 0;
+	c.bclr = ~u64_fill_right(c.umax);
+	return c;
+}
+
+static integer_constraints
 ic_shl(const type_t *tp, integer_constraints a, integer_constraints b)
 {
 	integer_constraints c;
@@ -264,6 +293,10 @@ ic_expr(const tnode_t *tn)
 			return ic_any(tn->tn_type);
 		lc = ic_expr(tn->tn_left);
 		return ic_cvt(tn->tn_type, tn->tn_left->tn_type, lc);
+	case MOD:
+		lc = ic_expr(before_conversion(tn->tn_left));
+		rc = ic_expr(before_conversion(tn->tn_right));
+		return ic_mod(tn->tn_type, lc, rc);
 	case SHL:
 		lc = ic_expr(tn->tn_left);
 		rc = ic_expr(tn->tn_right);

Reply via email to