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))