From 84a341bb5cf6e6e371b0b1ecf80521f5408b5ac7 Mon Sep 17 00:00:00 2001 From: Max Dexheimer Date: Mon, 21 Sep 2026 11:16:47 +0200 Subject: [PATCH] Use wrapping arithmetic in `from_str_radix` --- library/core/src/num/mod.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index db41d23770477..c2b21701645a0 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1573,6 +1573,16 @@ pub enum FpCategory { #[inline(always)] #[unstable(issue = "none", feature = "std_internals")] pub const fn can_not_overflow(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool { + // Assume that `digits` represents a whole number N in base `radix`. + // Then in infinite precision arithmetic (on whole numbers), we have: + // + // |N| <= pow(radix, digits.len()) - 1 + // <= pow(16, 2 * size_of::() - is_signed) - 1 + // == pow(2, 8 * size_of::() - 4 * is_signed) - 1 + // <= pow(2, 8 * size_of::() - is_signed) - 1 + // == T::MAX + // + // Therefore this condition is sufficient for having no overflow. radix <= 16 && digits.len() <= size_of::() * 2 - is_signed_ty as usize } @@ -1816,20 +1826,23 @@ macro_rules! from_str_int_impl { // Consider radix 16 as it has the highest information density per digit and will thus overflow the earliest: // `u8::MAX` is `ff` - any str of len 2 is guaranteed to not overflow. // `i8::MAX` is `7f` - only a str of len 1 is guaranteed to not overflow. - macro_rules! run_unchecked_loop { - ($unchecked_additive_op:tt) => {{ + // + // NOTE: We could use unchecked arithmetic here, but we don't, based on the observation + // that it produces the same assembly as wrapping ones. See #163099. + macro_rules! run_no_check_loop { + ($additive_op:ident) => {{ while let [c, rest @ ..] = digits { - result = result * (radix as $int_ty); + result = <$int_ty>::wrapping_mul(result, radix as _); let x = unwrap_or_PIE!((*c as char).to_digit(radix), InvalidDigit); - result = result $unchecked_additive_op (x as $int_ty); + result = result.$additive_op(x as $int_ty); digits = rest; } }}; } if is_positive { - run_unchecked_loop!(+) + run_no_check_loop!(wrapping_add) } else { - run_unchecked_loop!(-) + run_no_check_loop!(wrapping_sub) }; } else { macro_rules! run_checked_loop {