@@ -1035,6 +1035,11 @@ macro_rules! impl_helper_for {
10351035}
10361036impl_helper_for ! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
10371037
1038+ #[ inline( always) ]
1039+ pub ( crate ) fn can_not_overflow < T > ( radix : u32 , is_signed_ty : bool , digits : & [ u8 ] ) -> bool {
1040+ radix <= 16 && digits. len ( ) <= mem:: size_of :: < T > ( ) * 2 - is_signed_ty as usize
1041+ }
1042+
10381043fn from_str_radix < T : FromStrRadixHelper > ( src : & str , radix : u32 ) -> Result < T , ParseIntError > {
10391044 use self :: IntErrorKind :: * ;
10401045 use self :: ParseIntError as PIE ;
@@ -1068,7 +1073,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
10681073
10691074 let mut result = T :: from_u32 ( 0 ) ;
10701075
1071- if radix <= 16 && digits . len ( ) <= mem :: size_of :: < T > ( ) * 2 - is_signed_ty as usize {
1076+ if can_not_overflow :: < T > ( radix , is_signed_ty, digits ) {
10721077 // SAFETY: If the len of the str is short compared to the range of the type
10731078 // we are parsing into, then we can be certain that an overflow will not occur.
10741079 // This bound is when `radix.pow(digits.len()) - 1 <= T::MAX` but the condition
@@ -1093,9 +1098,9 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
10931098 run_unchecked_loop ! ( unchecked_sub)
10941099 } ;
10951100 }
1096- } else {
1101+ } else {
10971102 macro_rules! run_checked_loop {
1098- ( $checked_additive_op: ident, $overflow_err: ident ) => {
1103+ ( $checked_additive_op: ident, $overflow_err: expr ) => {
10991104 for & c in digits {
11001105 // When `radix` is passed in as a literal, rather than doing a slow `imul`
11011106 // the compiler can use shifts if `radix` can be expressed as a
@@ -1110,17 +1115,23 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
11101115 let mul = result. checked_mul( radix) ;
11111116 let x = ( c as char ) . to_digit( radix) . ok_or( PIE { kind: InvalidDigit } ) ?;
11121117 result = mul. ok_or_else( $overflow_err) ?;
1113- result = T :: $checked_additive_op( & result, x) . ok_or_else( $overflow_err) ?;
1118+ result = T :: $checked_additive_op( & result, x) . ok_or_else( $overflow_err) ?;
11141119 }
1115- }
1120+ } ;
11161121 }
11171122 if is_positive {
1118- let overflow_err = || PIE { kind : PosOverflow } ;
1119- run_checked_loop ! ( checked_add, overflow_err)
1123+ run_checked_loop ! ( checked_add, || PIE { kind: PosOverflow } )
11201124 } else {
1121- let overflow_err = || PIE { kind : NegOverflow } ;
1122- run_checked_loop ! ( checked_sub, overflow_err)
1125+ run_checked_loop ! ( checked_sub, || PIE { kind: NegOverflow } )
11231126 } ;
11241127 }
11251128 Ok ( result)
11261129}
1130+
1131+ mod tests {
1132+ #[ test]
1133+ fn test_can_not_overflow ( ) {
1134+ assert_eq ! ( can_not_overflow:: <i8 >( 10 , true , "99" . as_bytes( ) ) , true ) ;
1135+ assert_eq ! ( can_not_overflow:: <i8 >( 10 , true , "129" . as_bytes( ) ) , false ) ;
1136+ }
1137+ }
0 commit comments