Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions library/core/src/num/mod.rs

@tgross35 tgross35 Sep 22, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the goal is to actually remove panics and keep them gone then why no codegen test?

View changes since the review

@maxdexh maxdexh Sep 22, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function can already panic from the radix check. This change just brings the loop in line with the no-overflow-check version, which is the default. Adding a test feels more like an obligation that we will keep it this way. Idk if that is what we want, but I'm open to discussion on zulip ^^

Original file line number Diff line number Diff line change
Expand Up @@ -1573,6 +1573,16 @@ pub enum FpCategory {
#[inline(always)]
#[unstable(issue = "none", feature = "std_internals")]
pub const fn can_not_overflow<T>(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::<T>() - is_signed) - 1
// == pow(2, 8 * size_of::<T>() - 4 * is_signed) - 1
// <= pow(2, 8 * size_of::<T>() - is_signed) - 1
// == T::MAX
//
// Therefore this condition is sufficient for having no overflow.
radix <= 16 && digits.len() <= size_of::<T>() * 2 - is_signed_ty as usize
}

Expand Down Expand Up @@ -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 {
Expand Down
Loading