Skip to content

Commit 1ce044b

Browse files
committed
Add ilog10 result range hints
1 parent 5934b06 commit 1ce044b

File tree

3 files changed

+231
-2
lines changed

3 files changed

+231
-2
lines changed

library/core/src/num/int_macros.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3520,8 +3520,16 @@ macro_rules! int_impl {
35203520
without modifying the original"]
35213521
#[inline]
35223522
pub const fn checked_ilog10(self) -> Option<u32> {
3523+
const MAX_RESULT: u32 = int_log10::$ActualT(<$SelfT>::MAX as $ActualT);
3524+
35233525
if self > 0 {
3524-
Some(int_log10::$ActualT(self as $ActualT))
3526+
let result = int_log10::$ActualT(self as $ActualT);
3527+
3528+
// SAFETY: `ilog10` is a monotonically nondecreasing function, so the result for
3529+
// positive inputs is always in the range [0, `MAX_RESULT`].
3530+
unsafe { crate::hint::assert_unchecked(result <= MAX_RESULT) };
3531+
3532+
Some(result)
35253533
} else {
35263534
None
35273535
}

library/core/src/num/nonzero.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1657,7 +1657,15 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
16571657
without modifying the original"]
16581658
#[inline]
16591659
pub const fn ilog10(self) -> u32 {
1660-
super::int_log10::$Int(self.get())
1660+
const MAX_RESULT: u32 = super::int_log10::$Int(<$Int>::MAX);
1661+
1662+
let result = super::int_log10::$Int(self.get());
1663+
1664+
// SAFETY: `ilog10` is a monotonically nondecreasing function, so the result for
1665+
// positive inputs is always in the range [0, `MAX_RESULT`].
1666+
unsafe { crate::hint::assert_unchecked(result <= MAX_RESULT) };
1667+
1668+
result
16611669
}
16621670

16631671
/// Calculates the midpoint (average) between `self` and `rhs`.
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
//! Make sure the compiler knows the result range of `ilog10`.
2+
3+
//@ compile-flags: -O -Z merge-functions=disabled
4+
5+
#![crate_type = "lib"]
6+
7+
use std::num::NonZero;
8+
9+
// Signed integers.
10+
11+
#[no_mangle]
12+
fn i8_ilog10_range(value: i8) {
13+
const MAX_RESULT: u32 = i8::MAX.ilog10();
14+
15+
// CHECK-LABEL: @i8_ilog10_range(
16+
// CHECK-NOT: panic
17+
// CHECK: ret void
18+
// CHECK-NEXT: }
19+
assert!(value <= 0 || value.ilog10() <= MAX_RESULT);
20+
assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT));
21+
}
22+
23+
#[no_mangle]
24+
fn i16_ilog10_range(value: i16) {
25+
const MAX_RESULT: u32 = i16::MAX.ilog10();
26+
27+
// CHECK-LABEL: @i16_ilog10_range(
28+
// CHECK-NOT: panic
29+
// CHECK: ret void
30+
// CHECK-NEXT: }
31+
assert!(value <= 0 || value.ilog10() <= MAX_RESULT);
32+
assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT));
33+
}
34+
35+
#[no_mangle]
36+
fn i32_ilog10_range(value: i32) {
37+
const MAX_RESULT: u32 = i32::MAX.ilog10();
38+
39+
// CHECK-LABEL: @i32_ilog10_range(
40+
// CHECK-NOT: panic
41+
// CHECK: ret void
42+
// CHECK-NEXT: }
43+
assert!(value <= 0 || value.ilog10() <= MAX_RESULT);
44+
assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT));
45+
}
46+
47+
#[no_mangle]
48+
fn i64_ilog10_range(value: i64) {
49+
const MAX_RESULT: u32 = i64::MAX.ilog10();
50+
51+
// CHECK-LABEL: @i64_ilog10_range(
52+
// CHECK-NOT: panic
53+
// CHECK: ret void
54+
// CHECK-NEXT: }
55+
assert!(value <= 0 || value.ilog10() <= MAX_RESULT);
56+
assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT));
57+
}
58+
59+
#[no_mangle]
60+
fn i128_ilog10_range(value: i128) {
61+
const MAX_RESULT: u32 = i128::MAX.ilog10();
62+
63+
// CHECK-LABEL: @i128_ilog10_range(
64+
// CHECK-NOT: panic
65+
// CHECK: ret void
66+
// CHECK-NEXT: }
67+
assert!(value <= 0 || value.ilog10() <= MAX_RESULT);
68+
assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT));
69+
}
70+
71+
#[no_mangle]
72+
fn isize_ilog10_range(value: isize) {
73+
const MAX_RESULT: u32 = isize::MAX.ilog10();
74+
75+
// CHECK-LABEL: @isize_ilog10_range(
76+
// CHECK-NOT: panic
77+
// CHECK: ret void
78+
// CHECK-NEXT: }
79+
assert!(value <= 0 || value.ilog10() <= MAX_RESULT);
80+
assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT));
81+
}
82+
83+
// Unsigned integer types.
84+
85+
#[no_mangle]
86+
fn u8_ilog10_range(value: u8) {
87+
const MAX_RESULT: u32 = u8::MAX.ilog10();
88+
89+
// CHECK-LABEL: @u8_ilog10_range(
90+
// CHECK-NOT: panic
91+
// CHECK: ret void
92+
// CHECK-NEXT: }
93+
assert!(value == 0 || value.ilog10() <= MAX_RESULT);
94+
assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT));
95+
}
96+
97+
#[no_mangle]
98+
fn u16_ilog10_range(value: u16) {
99+
const MAX_RESULT: u32 = u16::MAX.ilog10();
100+
101+
// CHECK-LABEL: @u16_ilog10_range(
102+
// CHECK-NOT: panic
103+
// CHECK: ret void
104+
// CHECK-NEXT: }
105+
assert!(value == 0 || value.ilog10() <= MAX_RESULT);
106+
assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT));
107+
}
108+
109+
#[no_mangle]
110+
fn u32_ilog10_range(value: u32) {
111+
const MAX_RESULT: u32 = u32::MAX.ilog10();
112+
113+
// CHECK-LABEL: @u32_ilog10_range(
114+
// CHECK-NOT: panic
115+
// CHECK: ret void
116+
// CHECK-NEXT: }
117+
assert!(value == 0 || value.ilog10() <= MAX_RESULT);
118+
assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT));
119+
}
120+
121+
#[no_mangle]
122+
fn u64_ilog10_range(value: u64) {
123+
const MAX_RESULT: u32 = u64::MAX.ilog10();
124+
125+
// CHECK-LABEL: @u64_ilog10_range(
126+
// CHECK-NOT: panic
127+
// CHECK: ret void
128+
// CHECK-NEXT: }
129+
assert!(value == 0 || value.ilog10() <= MAX_RESULT);
130+
assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT));
131+
}
132+
133+
#[no_mangle]
134+
fn u128_ilog10_range(value: u128) {
135+
const MAX_RESULT: u32 = u128::MAX.ilog10();
136+
137+
// CHECK-LABEL: @u128_ilog10_range(
138+
// CHECK-NOT: panic
139+
// CHECK: ret void
140+
// CHECK-NEXT: }
141+
assert!(value == 0 || value.ilog10() <= MAX_RESULT);
142+
assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT));
143+
}
144+
145+
#[no_mangle]
146+
fn usize_ilog10_range(value: usize) {
147+
const MAX_RESULT: u32 = usize::MAX.ilog10();
148+
149+
// CHECK-LABEL: @usize_ilog10_range(
150+
// CHECK-NOT: panic
151+
// CHECK: ret void
152+
// CHECK-NEXT: }
153+
assert!(value == 0 || value.ilog10() <= MAX_RESULT);
154+
assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT));
155+
}
156+
157+
// Signed non-zero integers do not have `ilog10` methods.
158+
159+
// Unsigned non-zero integers.
160+
161+
#[no_mangle]
162+
fn non_zero_u8_ilog10_range(value: NonZero<u8>) {
163+
// CHECK-LABEL: @non_zero_u8_ilog10_range(
164+
// CHECK-NOT: panic
165+
// CHECK: ret void
166+
// CHECK-NEXT: }
167+
assert!(value.ilog10() <= const { u8::MAX.ilog10() });
168+
}
169+
170+
#[no_mangle]
171+
fn non_zero_u16_ilog10_range(value: NonZero<u16>) {
172+
// CHECK-LABEL: @non_zero_u16_ilog10_range(
173+
// CHECK-NOT: panic
174+
// CHECK: ret void
175+
// CHECK-NEXT: }
176+
assert!(value.ilog10() <= const { u16::MAX.ilog10() });
177+
}
178+
179+
#[no_mangle]
180+
fn non_zero_u32_ilog10_range(value: NonZero<u32>) {
181+
// CHECK-LABEL: @non_zero_u32_ilog10_range(
182+
// CHECK-NOT: panic
183+
// CHECK: ret void
184+
// CHECK-NEXT: }
185+
assert!(value.ilog10() <= const { u32::MAX.ilog10() });
186+
}
187+
188+
#[no_mangle]
189+
fn non_zero_u64_ilog10_range(value: NonZero<u64>) {
190+
// CHECK-LABEL: @non_zero_u64_ilog10_range(
191+
// CHECK-NOT: panic
192+
// CHECK: ret void
193+
// CHECK-NEXT: }
194+
assert!(value.ilog10() <= const { u64::MAX.ilog10() });
195+
}
196+
197+
#[no_mangle]
198+
fn non_zero_u128_ilog10_range(value: NonZero<u128>) {
199+
// CHECK-LABEL: @non_zero_u128_ilog10_range(
200+
// CHECK-NOT: panic
201+
// CHECK: ret void
202+
// CHECK-NEXT: }
203+
assert!(value.ilog10() <= const { u128::MAX.ilog10() });
204+
}
205+
206+
#[no_mangle]
207+
fn non_zero_usize_ilog10_range(value: NonZero<usize>) {
208+
// CHECK-LABEL: @non_zero_usize_ilog10_range(
209+
// CHECK-NOT: panic
210+
// CHECK: ret void
211+
// CHECK-NEXT: }
212+
assert!(value.ilog10() <= const { usize::MAX.ilog10() });
213+
}

0 commit comments

Comments
 (0)