about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGiles Cope <gilescope@gmail.com>2022-04-04 15:53:53 +0100
committerGiles Cope <gilescope@gmail.com>2022-04-04 15:53:53 +0100
commit82e9d9ebaca06b19f5c07afd9cf8f42a8045bdbb (patch)
treed70562ea0182108a7d8c4ba6f4ff5ed90b686f1e
parent72a5e7e810cbb2ea6db7ff37a599bc3826adee35 (diff)
downloadrust-82e9d9ebaca06b19f5c07afd9cf8f42a8045bdbb.tar.gz
rust-82e9d9ebaca06b19f5c07afd9cf8f42a8045bdbb.zip
from_u32(0) can just be default()
-rw-r--r--library/core/src/num/mod.rs25
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/core/tests/num/mod.rs47
3 files changed, 57 insertions, 16 deletions
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 12ab12d7ee0..5bead39a3db 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -969,9 +969,8 @@ pub enum FpCategory {
 }
 
 #[doc(hidden)]
-trait FromStrRadixHelper: PartialOrd + Copy {
+trait FromStrRadixHelper: PartialOrd + Copy + Default {
     const MIN: Self;
-    fn from_u32(u: u32) -> Self;
     fn checked_mul(&self, other: u32) -> Option<Self>;
     fn checked_sub(&self, other: u32) -> Option<Self>;
     fn checked_add(&self, other: u32) -> Option<Self>;
@@ -997,8 +996,6 @@ macro_rules! impl_helper_for {
     ($($t:ty)*) => ($(impl FromStrRadixHelper for $t {
         const MIN: Self = Self::MIN;
         #[inline]
-        fn from_u32(u: u32) -> Self { u as Self }
-        #[inline]
         fn checked_mul(&self, other: u32) -> Option<Self> {
             Self::checked_mul(*self, other as Self)
         }
@@ -1035,8 +1032,14 @@ macro_rules! impl_helper_for {
 }
 impl_helper_for! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
 
+/// Determins if a string of text of that length of that radix could be guaranteed to be
+/// stored in the given type T.
+/// Note that if the radix is known to the compiler, it is just the check of digits.len that
+/// is done at runtime.
+#[doc(hidden)]
 #[inline(always)]
-pub(crate) fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits:&[u8]) -> bool {
+#[unstable(issue = "none", feature = "std_internals")]
+pub fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool {
     radix <= 16 && digits.len() <= mem::size_of::<T>() * 2 - is_signed_ty as usize
 }
 
@@ -1054,7 +1057,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
         return Err(PIE { kind: Empty });
     }
 
-    let is_signed_ty = T::from_u32(0) > T::MIN;
+    let is_signed_ty = T::default() > T::MIN;
 
     // all valid digits are ascii, so we will just iterate over the utf8 bytes
     // and cast them to chars. .to_digit() will safely return None for anything
@@ -1071,7 +1074,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
         _ => (true, src),
     };
 
-    let mut result = T::from_u32(0);
+    let mut result = T::default();
 
     if can_not_overflow::<T>(radix, is_signed_ty, digits) {
         // SAFETY: If the len of the str is short compared to the range of the type
@@ -1127,11 +1130,3 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
     }
     Ok(result)
 }
-
-mod tests {
-    #[test]
-    fn test_can_not_overflow() {
-        assert_eq!(can_not_overflow::<i8>(10, true, "99".as_bytes()), true);
-        assert_eq!(can_not_overflow::<i8>(10, true, "129".as_bytes()), false);
-    }
-}
\ No newline at end of file
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 5c861236e86..bc2ab7489a1 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -55,6 +55,7 @@
 #![feature(numfmt)]
 #![feature(step_trait)]
 #![feature(str_internals)]
+#![feature(std_internals)]
 #![feature(test)]
 #![feature(trusted_len)]
 #![feature(try_blocks)]
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index 4f773a824ef..0abc88f21fc 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -2,7 +2,7 @@ use core::cmp::PartialEq;
 use core::convert::{TryFrom, TryInto};
 use core::fmt::Debug;
 use core::marker::Copy;
-use core::num::{IntErrorKind, ParseIntError, TryFromIntError};
+use core::num::{can_not_overflow, IntErrorKind, ParseIntError, TryFromIntError};
 use core::ops::{Add, Div, Mul, Rem, Sub};
 use core::option::Option;
 use core::option::Option::None;
@@ -121,6 +121,51 @@ fn test_int_from_str_overflow() {
 }
 
 #[test]
+fn test_can_not_overflow() {
+    // Not currently in std lib (issue: #27728)
+    fn format_radix<T>(mut x: T, radix: T) -> String
+    where
+        T: std::ops::Rem<Output = T>,
+        T: std::ops::Div<Output = T>,
+        T: std::cmp::PartialEq,
+        T: std::default::Default,
+        T: Copy,
+        T: Default,
+        u32: TryFrom<T>,
+    {
+        let mut result = vec![];
+
+        loop {
+            let m = x % radix;
+            x = x / radix;
+            result.push(
+                std::char::from_digit(m.try_into().ok().unwrap(), radix.try_into().ok().unwrap())
+                    .unwrap(),
+            );
+            if x == T::default() {
+                break;
+            }
+        }
+        result.into_iter().rev().collect()
+    }
+
+    macro_rules! check {
+        ($($t:ty)*) => ($(
+        for base in 2..=36 {
+            let num = (<$t>::MAX as u128) + 1;
+
+           // Calcutate the string length for the smallest overflowing number:
+           let max_len_string = format_radix(num, base as u128);
+           // Ensure that that string length is deemed to potentially overflow:
+           assert_eq!(can_not_overflow::<$t>(base, <$t>::default() > <$t>::MIN, max_len_string.as_bytes()), false);
+        }
+        )*)
+    }
+
+    check! { i8 i16 i32 i64 i128 isize usize u8 u16 u32 u64 }
+}
+
+#[test]
 fn test_leading_plus() {
     test_parse::<u8>("+127", Ok(127));
     test_parse::<i64>("+9223372036854775807", Ok(9223372036854775807));