Module Name:    src
Committed By:   rillig
Date:           Thu Jan  2 17:35:02 UTC 2025

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

Log Message:
lint: fix a few wrong warnings about possible loss of accuracy


To generate a diff of this commit:
cvs rdiff -u -r1.49 -r1.50 src/tests/usr.bin/xlint/lint1/msg_132.c
cvs rdiff -u -r1.666 -r1.667 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.49 src/tests/usr.bin/xlint/lint1/msg_132.c:1.50
--- src/tests/usr.bin/xlint/lint1/msg_132.c:1.49	Thu Jan  2 03:46:27 2025
+++ src/tests/usr.bin/xlint/lint1/msg_132.c	Thu Jan  2 17:35:02 2025
@@ -1,4 +1,4 @@
-/*	$NetBSD: msg_132.c,v 1.49 2025/01/02 03:46:27 rillig Exp $	*/
+/*	$NetBSD: msg_132.c,v 1.50 2025/01/02 17:35:02 rillig Exp $	*/
 # 3 "msg_132.c"
 
 // Test for message: conversion from '%s' to '%s' may lose accuracy [132]
@@ -250,23 +250,36 @@ test_ic_mult(void)
 
 	// from __BITS, __SHIFTIN, __SHIFTOUT
 	u32 = (u16 & 1023ULL) / 1ULL * 1024ULL | (u16 & 1023ULL) / 1ULL * 1ULL;
+
+	// FIXME
+	/* expect+1: warning: conversion from 'int' to 'signed char' may lose accuracy [132] */
+	s8 = 1 * s8;
+	// FIXME
+	/* expect+1: warning: conversion from 'int' to 'short' may lose accuracy [132] */
+	s16 = 1 * s16;
+	s32 = 1 * s32;
+	s64 = 1 * s64;
 }
 
 void
 test_ic_div(void)
 {
-	// FIXME
-	/* expect+1: warning: conversion from 'int' to 'unsigned char' may lose accuracy [132] */
 	u8 = u8 / u8;
-	// FIXME
 	/* expect+1: warning: conversion from 'int' to 'unsigned char' may lose accuracy [132] */
 	u8 = u16 / u8;
-	// FIXME
-	/* expect+1: warning: conversion from 'int' to 'unsigned short' may lose accuracy [132] */
 	u16 = u8 / u8;
 	u16 = u32 / 65536;
 	/* expect+1: warning: conversion from 'unsigned int' to 'unsigned short' may lose accuracy [132] */
 	u16 = u32 / 65535;
+
+	// FIXME
+	/* expect+1: warning: conversion from 'int' to 'signed char' may lose accuracy [132] */
+	s8 = s8 / 1;
+	// FIXME
+	/* expect+1: warning: conversion from 'int' to 'short' may lose accuracy [132] */
+	s16 = s16 / 1;
+	s32 = s32 / 1;
+	s64 = s64 / 1;
 }
 
 void
@@ -327,6 +340,11 @@ test_ic_plus(void)
 	/* expect+1: warning: conversion from 'unsigned long long' to 'unsigned char' may lose accuracy [132] */
 	u8 = 256 + u64 % 1;
 
+	u8 = s8 + 0x80;
+	u16 = s16 + 0x8000;
+	u32 = s32 + 0x80000000;
+	u64 = s64 + 0x8000000000000000;
+
 	// XXX: No warnings since portable_rank_cmp is the same for both sides.
 	bits.u11 = bits.u10 + bits.u10 + 1;
 	bits.u11 = bits.u10 + bits.u10 + 2;
@@ -377,6 +395,11 @@ test_ic_minus(void)
 	s8 = ((s64 & 0xff) ^ 0x80) - 0x7f;
 	/* expect+1: warning: conversion from 'long long' to 'signed char' may lose accuracy [132] */
 	s8 = ((s64 & 0xff) ^ 0x80) - 0x81;
+
+	u8 = s8 - -0x80;
+	u16 = s16 - -0x8000;
+	u32 = s32 - -0x80000000;
+	u64 = s64 - -0x8000000000000000;
 }
 
 void
@@ -516,6 +539,12 @@ test_ic_cvt(void)
 	u16 = (u32_t)(u32 & 0x0000ff00);
 	u16 = (u16_t)u32;
 	u16 = (u8_t)(u32 & 0xffff) << 8;
+	u16 = (int)3.0;
+
+	u8 = (u8_t)(u64 & 0x0f);
+	u8 = (u8_t)(u64 & 0x0f) << 4;
+	/* expect+1: warning: conversion from 'int' to 'unsigned char' may lose accuracy [132] */
+	u8 = (u8_t)(u64 & 0x0f) << 5;
 }
 
 unsigned char

Index: src/usr.bin/xlint/lint1/tree.c
diff -u src/usr.bin/xlint/lint1/tree.c:1.666 src/usr.bin/xlint/lint1/tree.c:1.667
--- src/usr.bin/xlint/lint1/tree.c:1.666	Thu Jan  2 03:46:27 2025
+++ src/usr.bin/xlint/lint1/tree.c	Thu Jan  2 17:35:01 2025
@@ -1,4 +1,4 @@
-/*	$NetBSD: tree.c,v 1.666 2025/01/02 03:46:27 rillig Exp $	*/
+/*	$NetBSD: tree.c,v 1.667 2025/01/02 17:35:01 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.666 2025/01/02 03:46:27 rillig Exp $");
+__RCSID("$NetBSD: tree.c,v 1.667 2025/01/02 17:35:01 rillig Exp $");
 #endif
 
 #include <float.h>
@@ -77,6 +77,20 @@ s64_abs(int64_t x)
 	return x >= 0 ? (uint64_t)x : -(uint64_t)x;
 }
 
+static int64_t
+s64_shr(int64_t x, unsigned amount)
+{
+	return x >= 0
+	    ? (int64_t)((uint64_t)x >> amount)
+	    : (int64_t)~(~(uint64_t)x >> amount);
+}
+
+static uint64_t
+u64_min(uint64_t a, uint64_t b)
+{
+	return a < b ? a : b;
+}
+
 static uint64_t
 u64_max(uint64_t a, uint64_t b)
 {
@@ -84,9 +98,40 @@ u64_max(uint64_t a, uint64_t b)
 }
 
 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 int
+portable_rank_cmp(tspec_t t1, tspec_t t2)
+{
+	const ttab_t *p1 = type_properties(t1), *p2 = type_properties(t2);
+	lint_assert(p1->tt_rank_kind == p2->tt_rank_kind);
+	lint_assert(p1->tt_rank_value > 0);
+	lint_assert(p2->tt_rank_value > 0);
+	return (int)p1->tt_rank_value - (int)p2->tt_rank_value;
+}
+
+static unsigned
+width_in_bits(const type_t *tp)
+{
+	lint_assert(is_integer(tp->t_tspec));
+	return tp->t_bitfield
+	       ? tp->t_bit_field_width
+	       : size_in_bits(tp->t_tspec);
+}
+
+static uint64_t
 ui_max_value(const type_t *tp)
 {
-	return value_bits(size_in_bits(tp->t_tspec));
+	return value_bits(width_in_bits(tp));
 }
 
 static int64_t
@@ -125,52 +170,17 @@ si_minus_sat(const type_t *tp, int64_t a
 	}
 }
 
-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
-str_ends_with(const char *haystack, const char *needle)
+ic_maybe_signed(const type_t *tp, integer_constraints ic)
 {
-	size_t hlen = strlen(haystack);
-	size_t nlen = strlen(needle);
-
-	return nlen <= hlen &&
-	    memcmp(haystack + hlen - nlen, needle, nlen) == 0;
-}
-
-static unsigned
-width_in_bits(const type_t *tp)
-{
-
-	lint_assert(is_integer(tp->t_tspec));
-	return tp->t_bitfield
-	    ? tp->t_bit_field_width
-	    : size_in_bits(tp->t_tspec);
-}
-
-static int
-portable_rank_cmp(tspec_t t1, tspec_t t2)
-{
-	const ttab_t *p1 = type_properties(t1), *p2 = type_properties(t2);
-	lint_assert(p1->tt_rank_kind == p2->tt_rank_kind);
-	lint_assert(p1->tt_rank_value > 0);
-	lint_assert(p2->tt_rank_value > 0);
-	return (int)p1->tt_rank_value - (int)p2->tt_rank_value;
+	return !is_uinteger(tp->t_tspec) && ic.bclr >> 63 == 0;
 }
 
 static bool
-ic_maybe_signed(const type_t *tp, const integer_constraints *ic)
+ic_maybe_signed_binary(const type_t *tp,
+    integer_constraints a, integer_constraints b)
 {
-	return !is_uinteger(tp->t_tspec) && ic->bclr >> 63 == 0;
+	return !is_uinteger(tp->t_tspec) && (a.bclr & b.bclr) >> 63 == 0;
 }
 
 static integer_constraints
@@ -187,7 +197,7 @@ ic_any(const type_t *tp)
 		c.umax = vbits;
 		c.bclr = ~c.umax;
 	} else {
-		c.smin = (int64_t)-1 - (int64_t)(vbits >> 1);
+		c.smin = -1 - (int64_t)(vbits >> 1);
 		c.smax = (int64_t)(vbits >> 1);
 		c.umin = 0;
 		c.umax = UINT64_MAX;
@@ -201,7 +211,7 @@ ic_mult(const type_t *tp, integer_constr
 {
 	integer_constraints c;
 
-	if (ic_maybe_signed(tp, &a) || ic_maybe_signed(tp, &b)
+	if (ic_maybe_signed_binary(tp, a, b)
 	    || (a.umax > 0 && b.umax > ic_any(tp).umax / a.umax))
 		return ic_any(tp);
 
@@ -216,43 +226,36 @@ ic_mult(const type_t *tp, integer_constr
 static integer_constraints
 ic_div(const type_t *tp, integer_constraints a, integer_constraints b)
 {
-	integer_constraints c;
-
-	if (ic_maybe_signed(tp, &a) || ic_maybe_signed(tp, &b) || b.umin == 0)
+	if (ic_maybe_signed_binary(tp, a, b))
 		return ic_any(tp);
 
+	integer_constraints c;
 	c.smin = INT64_MIN;
 	c.smax = INT64_MAX;
-	c.umin = a.umin / b.umax;
-	c.umax = a.umax / b.umin;
+	c.umin = a.umin / u64_max(b.umax, 1);
+	c.umax = a.umax / u64_max(b.umin, 1);
 	c.bclr = ~u64_fill_right(c.umax);
 	return c;
 }
 
 static integer_constraints
-ic_mod_signed(integer_constraints a, integer_constraints b)
-{
-	integer_constraints c;
-
-	uint64_t max_abs_b = u64_max(s64_abs(b.smin), s64_abs(b.smax));
-	if (max_abs_b >> 63 != 0 || max_abs_b == 0)
-		return a;
-	c.smin = s64_max(a.smin, -(int64_t)(max_abs_b - 1));
-	c.smax = s64_min(a.smax, (int64_t)(max_abs_b - 1));
-	c.umin = 0;
-	c.umax = UINT64_MAX;
-	c.bclr = 0;
-	return c;
-}
-
-static integer_constraints
 ic_mod(const type_t *tp, integer_constraints a, integer_constraints b)
 {
-	integer_constraints c;
+	if (ic_maybe_signed_binary(tp, a, b)) {
+		uint64_t max_abs_b = u64_max(s64_abs(b.smin), s64_abs(b.smax));
+		if (max_abs_b >> 63 != 0 || max_abs_b == 0)
+			return a;
 
-	if (ic_maybe_signed(tp, &a) || ic_maybe_signed(tp, &b))
-		return ic_mod_signed(a, b);
+		integer_constraints c;
+		c.smin = s64_max(a.smin, -(int64_t)(max_abs_b - 1));
+		c.smax = s64_min(a.smax, (int64_t)(max_abs_b - 1));
+		c.umin = 0;
+		c.umax = UINT64_MAX;
+		c.bclr = 0;
+		return c;
+	}
 
+	integer_constraints c;
 	c.smin = INT64_MIN;
 	c.smax = INT64_MAX;
 	c.umin = 0;
@@ -264,12 +267,12 @@ ic_mod(const type_t *tp, integer_constra
 static integer_constraints
 ic_plus(const type_t *tp, integer_constraints a, integer_constraints b)
 {
-	if (ic_maybe_signed(tp, &a) || ic_maybe_signed(tp, &b)) {
+	if (ic_maybe_signed_binary(tp, a, b)) {
 		integer_constraints c;
 		c.smin = si_plus_sat(tp, a.smin, b.smin);
 		c.smax = si_plus_sat(tp, a.smax, b.smax);
-		c.umin = 0;
-		c.umax = UINT64_MAX;
+		c.umin = c.smin >= 0 ? (uint64_t)c.smin : 0;
+		c.umax = c.smin >= 0 ? (uint64_t)c.smax : UINT64_MAX;
 		c.bclr = 0;
 		return c;
 	}
@@ -285,6 +288,10 @@ ic_plus(const type_t *tp, integer_constr
 		c.umin = 0;
 		c.umax = max;
 	}
+	if (c.umax >> 63 == 0) {
+		c.smin = 0;
+		c.smax = (int64_t)c.umax;
+	}
 	c.bclr = ~u64_fill_right(c.umax);
 	return c;
 }
@@ -292,20 +299,14 @@ ic_plus(const type_t *tp, integer_constr
 static integer_constraints
 ic_minus(const type_t *tp, integer_constraints a, integer_constraints b)
 {
-	if (ic_maybe_signed(tp, &a) || ic_maybe_signed(tp, &b)) {
-		integer_constraints c;
-		c.smin = si_minus_sat(tp, a.smin, b.smax);
-		c.smax = si_minus_sat(tp, a.smax, b.smin);
-		c.umin = 0;
-		c.umax = UINT64_MAX;
-		c.bclr = 0;
-		return c;
-	}
-
 	integer_constraints c;
 	c.smin = si_minus_sat(tp, a.smin, b.smax);
 	c.smax = si_minus_sat(tp, a.smax, b.smin);
-	if (a.umin >= b.umax) {
+
+	if (ic_maybe_signed_binary(tp, a, b)) {
+		c.umin = c.smin >= 0 ? (uint64_t)c.smin : 0;
+		c.umax = c.smin >= 0 ? (uint64_t)c.smax : UINT64_MAX;
+	} else if (a.umin >= b.umax) {
 		c.umin = a.umin - b.umax;
 		c.umax = a.umax - b.umin;
 	} else {
@@ -320,23 +321,27 @@ ic_minus(const type_t *tp, integer_const
 static integer_constraints
 ic_shl(const type_t *tp, integer_constraints a, integer_constraints b)
 {
-	integer_constraints c;
-	unsigned int amount;
-
-	if (ic_maybe_signed(tp, &a))
+	if (ic_maybe_signed(tp, a))
 		return ic_any(tp);
 
+	unsigned amount;
 	if (b.smin == b.smax && b.smin >= 0 && b.smin < 64)
-		amount = (unsigned int)b.smin;
+		amount = (unsigned)b.smin;
 	else if (b.umin == b.umax && b.umin < 64)
-		amount = (unsigned int)b.umin;
+		amount = (unsigned)b.umin;
 	else
 		return ic_any(tp);
 
-	c.smin = INT64_MIN;
-	c.smax = INT64_MAX;
-	c.umin = 0;
-	c.umax = UINT64_MAX;
+	integer_constraints c;
+	c.umin = a.umin << amount;
+	c.umax = a.umax << amount;
+	if (c.umax >> (width_in_bits(tp) - 1) == 0) {
+		c.smin = (int64_t)c.umin;
+		c.smax = (int64_t)c.umax;
+	} else {
+		c.smin = INT64_MIN;
+		c.smax = INT64_MAX;
+	}
 	c.bclr = a.bclr << amount | (((uint64_t)1 << amount) - 1);
 	return c;
 }
@@ -344,23 +349,22 @@ ic_shl(const type_t *tp, integer_constra
 static integer_constraints
 ic_shr(const type_t *tp, integer_constraints a, integer_constraints b)
 {
-	integer_constraints c;
-	unsigned int amount;
-
-	if (ic_maybe_signed(tp, &a))
+	if (ic_maybe_signed(tp, a))
 		return ic_any(tp);
 
+	unsigned amount;
 	if (b.smin == b.smax && b.smin >= 0 && b.smin < 64)
-		amount = (unsigned int)b.smin;
+		amount = (unsigned)b.smin;
 	else if (b.umin == b.umax && b.umin < 64)
-		amount = (unsigned int)b.umin;
+		amount = (unsigned)b.umin;
 	else
 		return ic_any(tp);
 
-	c.smin = INT64_MIN;
-	c.smax = INT64_MAX;
-	c.umin = 0;
-	c.umax = UINT64_MAX;
+	integer_constraints c;
+	c.smin = s64_shr(a.smin, amount);
+	c.smax = s64_shr(a.smax, amount);
+	c.umin = a.umin >> amount;
+	c.umax = a.umax >> amount;
 	c.bclr = a.bclr >> amount | ~(~(uint64_t)0 >> amount);
 	return c;
 }
@@ -369,15 +373,10 @@ static integer_constraints
 ic_bitand(integer_constraints a, integer_constraints b)
 {
 	integer_constraints c;
-
-	c.smin = INT64_MIN;
-	c.smax = INT64_MAX;
-	c.umin = 0;
-	c.umax = ~(a.bclr | b.bclr);
-	if (c.umax >> 63 == 0) {
-		c.smin = 0;
-		c.smax = (int64_t)c.umax;
-	}
+	c.smin = a.smin & b.smin;
+	c.smax = a.smax & b.smax;
+	c.umin = a.umin & b.umin;
+	c.umax = a.umax & b.umax;
 	c.bclr = a.bclr | b.bclr;
 	return c;
 }
@@ -385,14 +384,14 @@ ic_bitand(integer_constraints a, integer
 static integer_constraints
 ic_bitxor(const type_t *tp, integer_constraints a, integer_constraints b)
 {
-	integer_constraints c = ic_any(tp);
-	if (ic_maybe_signed(tp, &a) || ic_maybe_signed(tp, &b))
-		return c;
+	if (ic_maybe_signed_binary(tp, a, b))
+		return ic_any(tp);
+
+	integer_constraints c;
+	c.smin = a.smin & b.smin;
+	c.smax = a.smax | b.smax;
+	c.umin = a.umin & b.umin;
 	c.umax = a.umax | b.umax;
-	if (c.umax >> 63 == 0) {
-		c.smin = 0;
-		c.smax = (int64_t)c.umax;
-	}
 	c.bclr = a.bclr & b.bclr;
 	return c;
 }
@@ -401,11 +400,10 @@ static integer_constraints
 ic_bitor(integer_constraints a, integer_constraints b)
 {
 	integer_constraints c;
-
-	c.smin = INT64_MIN;
-	c.smax = INT64_MAX;
-	c.umin = 0;
-	c.umax = ~(a.bclr & b.bclr);
+	c.smin = a.smin | b.smin;
+	c.smax = a.smax | b.smax;
+	c.umin = a.umin | b.umin;
+	c.umax = a.umax | b.umax;
 	c.bclr = a.bclr & b.bclr;
 	return c;
 }
@@ -414,11 +412,10 @@ static integer_constraints
 ic_quest_colon(integer_constraints a, integer_constraints b)
 {
 	integer_constraints c;
-
-	c.smin = a.smin < b.smin ? a.smin : b.smin;
-	c.smax = a.smax > b.smax ? a.smax : b.smax;
-	c.umin = a.umin < b.umin ? a.umin : b.umin;
-	c.umax = a.umax > b.umax ? a.umax : b.umax;
+	c.smin = s64_min(a.smin, b.smin);
+	c.smax = s64_max(a.smax, b.smax);
+	c.umin = u64_min(a.umin, b.umin);
+	c.umax = u64_max(a.umax, b.umax);
 	c.bclr = a.bclr & b.bclr;
 	return c;
 }
@@ -426,11 +423,11 @@ ic_quest_colon(integer_constraints a, in
 static integer_constraints
 ic_con(const type_t *tp, const val_t *v)
 {
-	integer_constraints c;
-
 	lint_assert(is_integer(tp->t_tspec));
 	int64_t si = v->u.integer;
 	uint64_t ui = (uint64_t)si;
+
+	integer_constraints c;
 	c.smin = si;
 	c.smax = si;
 	c.umin = ui;
@@ -451,6 +448,8 @@ ic_cvt(const type_t *ntp, const type_t *
 		return a;
 	if (nw > ow && ou)
 		return a;
+	if (nu && (~value_bits(nw) & ~a.bclr) == 0)
+		return a;
 	return ic_any(ntp);
 }
 
@@ -663,6 +662,16 @@ is_compiler_builtin(const char *name)
 	return false;
 }
 
+static bool
+str_ends_with(const char *haystack, const char *needle)
+{
+	size_t hlen = strlen(haystack);
+	size_t nlen = strlen(needle);
+
+	return nlen <= hlen &&
+	       memcmp(haystack + hlen - nlen, needle, nlen) == 0;
+}
+
 /* https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html */
 static bool
 is_gcc_bool_builtin(const char *name)
@@ -1148,9 +1157,7 @@ fold_signed_integer(op_t op, int64_t l, 
 		return l << (r & 63);
 	case SHR:
 		/* TODO: warn about out-of-bounds 'r'. */
-		if (l < 0)
-			return (int64_t)~(~(uint64_t)l >> (r & 63));
-		return (int64_t)((uint64_t)l >> (r & 63));
+		return s64_shr(l, r & 63);
 	case LT:
 		return l < r ? 1 : 0;
 	case LE:
@@ -2515,7 +2522,7 @@ typeok_shr(op_t op,
 	/* operands have integer types (checked in typeok) */
 	if (pflag && !is_uinteger(olt)) {
 		integer_constraints lc = ic_expr(ln);
-		if (!ic_maybe_signed(ln->tn_type, &lc))
+		if (lc.bclr >> 63 != 0)
 			return;
 
 		if (ln->tn_op != CON)
@@ -4215,7 +4222,7 @@ build_offsetof(const type_t *tp, designa
 			if (tp->t_tspec != ARRAY)
 				goto proceed;	/* silent error */
 			tp = tp->t_subt;
-			offset_in_bits += (unsigned) dr->dr_subscript
+			offset_in_bits += (unsigned)dr->dr_subscript
 			    * type_size_in_bits(tp);
 		} else {
 			if (!is_struct_or_union(tp->t_tspec))

Reply via email to