From 68a6fe9284211b2df3b49f3b6b3fadde8710e7ce Mon Sep 17 00:00:00 2001 From: oyvindln Date: Wed, 12 Jul 2017 22:32:54 +0200 Subject: [PATCH 1/4] Add inline annotations and avoid 128-bit where it's not needed in TryFrom Avoid using i/u128 except for converting between 128-bit types. Use the smallest needed type instead for most types (except u/isize) Add inline annotations to try_from implementations. Before doing this the functions did not get inlined. Avoid using the FromStrRadixHelper trait in the try_from implementations. This wasn't needed for anything. Add some simpler implementations for conversions that don't need as many checks. --- src/libcore/num/mod.rs | 143 ++++++++++++++++++++++++++++++++--------- 1 file changed, 113 insertions(+), 30 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index cbd59ed371377..907dbbbfc44c1 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2510,9 +2510,10 @@ macro_rules! same_sign_try_from_int_impl { impl TryFrom<$source> for $target { type Error = TryFromIntError; + #[inline] fn try_from(u: $source) -> Result<$target, TryFromIntError> { - let min = <$target as FromStrRadixHelper>::min_value() as $storage; - let max = <$target as FromStrRadixHelper>::max_value() as $storage; + let min = <$target>::min_value() as $storage; + let max = <$target>::max_value() as $storage; if u as $storage < min || u as $storage > max { Err(TryFromIntError(())) } else { @@ -2523,42 +2524,91 @@ macro_rules! same_sign_try_from_int_impl { )*} } -same_sign_try_from_int_impl!(u128, u8, u8, u16, u32, u64, u128, usize); -same_sign_try_from_int_impl!(i128, i8, i8, i16, i32, i64, i128, isize); -same_sign_try_from_int_impl!(u128, u16, u8, u16, u32, u64, u128, usize); -same_sign_try_from_int_impl!(i128, i16, i8, i16, i32, i64, i128, isize); -same_sign_try_from_int_impl!(u128, u32, u8, u16, u32, u64, u128, usize); -same_sign_try_from_int_impl!(i128, i32, i8, i16, i32, i64, i128, isize); -same_sign_try_from_int_impl!(u128, u64, u8, u16, u32, u64, u128, usize); -same_sign_try_from_int_impl!(i128, i64, i8, i16, i32, i64, i128, isize); -same_sign_try_from_int_impl!(u128, u128, u8, u16, u32, u64, u128, usize); -same_sign_try_from_int_impl!(i128, i128, i8, i16, i32, i64, i128, isize); -same_sign_try_from_int_impl!(u128, usize, u8, u16, u32, u64, u128, usize); -same_sign_try_from_int_impl!(i128, isize, i8, i16, i32, i64, i128, isize); - -macro_rules! cross_sign_from_int_impl { - ($unsigned:ty, $($signed:ty),*) => {$( +macro_rules! same_sign_try_from_wider_impl { + ($target:ty, $($source:ty),*) => {$( #[unstable(feature = "try_from", issue = "33417")] - impl TryFrom<$unsigned> for $signed { + impl TryFrom<$source> for $target { type Error = TryFromIntError; - fn try_from(u: $unsigned) -> Result<$signed, TryFromIntError> { - let max = <$signed as FromStrRadixHelper>::max_value() as u128; - if u as u128 > max { + #[inline] + fn try_from(u: $source) -> Result<$target, TryFromIntError> { + let min = <$target>::min_value() as $source; + let max = <$target>::max_value() as $source; + if u as $source < min || u as $source > max { Err(TryFromIntError(())) } else { - Ok(u as $signed) + Ok(u as $target) } } } + )*} +} + +/// TryFrom on types where the conversion will always succeed. +macro_rules! trivial_try_from_impl { + ($source:ty, $($target:ty),*) => {$( + #[unstable(feature = "try_from", issue = "33417")] + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + #[inline] + fn try_from(u: $source) -> Result<$target, TryFromIntError> { + // Using into as an extra check on the macro arguments. + Ok(u as $target) + } + } + )*} +} +// The current implementations assume that usize/isize <= 64 bits wide. +// (source, $(target)) +trivial_try_from_impl!(u8, u8, u16, i16, u32, i32, u64, i64, u128, i128, usize); +trivial_try_from_impl!(u16, u16, u32, i32, u64, i64, u128, i128); +trivial_try_from_impl!(u32, u32, u64, i64, u128, i128); +trivial_try_from_impl!(u64, u64, u128, i128); +trivial_try_from_impl!(u128, u128); +trivial_try_from_impl!(usize, usize, u128, i128); + +trivial_try_from_impl!(i8, i8, i16, i32, i64, i128, isize); +trivial_try_from_impl!(i16, i16, i32, i64, i128); +trivial_try_from_impl!(i32, i32, i64, i128); +trivial_try_from_impl!(i64, i64, i128); +trivial_try_from_impl!(i128, i128); +trivial_try_from_impl!(isize, isize, i128); +trivial_try_from_impl!(usize, u64); +trivial_try_from_impl!(isize, i64); + +// (target, $(source)) +same_sign_try_from_wider_impl!(u8, u16, u32, u64, u128, usize); +same_sign_try_from_wider_impl!(i8, i16, i32, i64, i128, isize); +same_sign_try_from_wider_impl!(u16, u32, u64, u128); +same_sign_try_from_wider_impl!(i16, i32, i64, i128); +same_sign_try_from_wider_impl!(u32, u64, u128); +same_sign_try_from_wider_impl!(i32, i64, i128); +same_sign_try_from_wider_impl!(u64, u128); +same_sign_try_from_wider_impl!(i64, i128); + +// Need to make sure the storage component is large enough for these. +// (storage, target, $(source)) +same_sign_try_from_int_impl!(u64, usize, u64, u32, u16); +same_sign_try_from_int_impl!(i64, isize, i64, i32, i16); +same_sign_try_from_int_impl!(u64, u16, usize); +same_sign_try_from_int_impl!(i64, i16, isize); +same_sign_try_from_int_impl!(u64, u32, usize); +same_sign_try_from_int_impl!(i64, i32, isize); +same_sign_try_from_int_impl!(u128, usize, u128); +same_sign_try_from_int_impl!(i128, isize, i128); + +macro_rules! unsigned_from_signed_impl { + ($unsigned:ty, $($signed:ty, $storage:ty),*) => {$( #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$signed> for $unsigned { type Error = TryFromIntError; + #[inline] fn try_from(u: $signed) -> Result<$unsigned, TryFromIntError> { - let max = <$unsigned as FromStrRadixHelper>::max_value() as u128; - if u < 0 || u as u128 > max { + let max: $storage = <$unsigned>::max_value().into(); + if u < 0 || u as $storage > max { Err(TryFromIntError(())) } else { Ok(u as $unsigned) @@ -2568,12 +2618,39 @@ macro_rules! cross_sign_from_int_impl { )*} } -cross_sign_from_int_impl!(u8, i8, i16, i32, i64, i128, isize); -cross_sign_from_int_impl!(u16, i8, i16, i32, i64, i128, isize); -cross_sign_from_int_impl!(u32, i8, i16, i32, i64, i128, isize); -cross_sign_from_int_impl!(u64, i8, i16, i32, i64, i128, isize); -cross_sign_from_int_impl!(u128, i8, i16, i32, i64, i128, isize); -cross_sign_from_int_impl!(usize, i8, i16, i32, i64, i128, isize); +macro_rules! signed_from_unsigned_impl { + ($signed:ty, $($unsigned:ty, $storage:ty),*) => {$( + #[unstable(feature = "try_from", issue = "33417")] + impl TryFrom<$unsigned> for $signed { + type Error = TryFromIntError; + + #[inline] + fn try_from(u: $unsigned) -> Result<$signed, TryFromIntError> { + let max = <$signed>::max_value() as $storage; + if u as $storage > max { + Err(TryFromIntError(())) + } else { + Ok(u as $signed) + } + } + } + )*} +} + +// (unsigned type, $(signed type, storage)) +unsigned_from_signed_impl!(u8, i8, u8, i16, i16, i32, i32, i64, i64, i128, i128, isize, u64); +unsigned_from_signed_impl!(u16, i8, u16, i16, u16, i32, u32, i64, u64, i128, i128, isize, u64); +unsigned_from_signed_impl!(u32, i8, u32, i16, u32, i32, u32, i64, u64, i128, i128, isize, u64); +unsigned_from_signed_impl!(u64, i8, u64, i16, u64, i32, u64, i64, u64, i128, i128, isize, u64); +unsigned_from_signed_impl!(u128, i8, u128, i16, u128, i32, u128, i64, u128, i128, u128, isize, + u128); + +// (signed type, $(unsigned type, storage)) +signed_from_unsigned_impl!(i8, u8, u8, u16, u16, u32, u32, u64, u64, u128, u128, usize, usize); +signed_from_unsigned_impl!(i16, u16, u16, u32, u32, u64, u64, u128, u128, usize, usize); +signed_from_unsigned_impl!(i32, u32, u32, u64, u64, u128, u128, usize, usize); +signed_from_unsigned_impl!(i64, u64, u64, u128, u128, usize, usize); +signed_from_unsigned_impl!(i128, u128, u128); #[doc(hidden)] trait FromStrRadixHelper: PartialOrd + Copy { @@ -2587,15 +2664,21 @@ trait FromStrRadixHelper: PartialOrd + Copy { macro_rules! doit { ($($t:ty)*) => ($(impl FromStrRadixHelper for $t { + #[inline] fn min_value() -> Self { Self::min_value() } + #[inline] fn max_value() -> Self { Self::max_value() } + #[inline] fn from_u32(u: u32) -> Self { u as Self } + #[inline] fn checked_mul(&self, other: u32) -> Option { Self::checked_mul(*self, other as Self) } + #[inline] fn checked_sub(&self, other: u32) -> Option { Self::checked_sub(*self, other as Self) } + #[inline] fn checked_add(&self, other: u32) -> Option { Self::checked_add(*self, other as Self) } From a9097fd5a35c3076a8969cf8df53bced607d7e44 Mon Sep 17 00:00:00 2001 From: oyvindln Date: Thu, 13 Jul 2017 22:34:14 +0200 Subject: [PATCH 2/4] Add bit width specific impls, add check for unknown bit width + Moved u64-usize macro call to the logical place --- src/libcore/num/mod.rs | 99 +++++++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 35 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 907dbbbfc44c1..ae8dc099481fb 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2504,26 +2504,6 @@ impl fmt::Display for TryFromIntError { } } -macro_rules! same_sign_try_from_int_impl { - ($storage:ty, $target:ty, $($source:ty),*) => {$( - #[unstable(feature = "try_from", issue = "33417")] - impl TryFrom<$source> for $target { - type Error = TryFromIntError; - - #[inline] - fn try_from(u: $source) -> Result<$target, TryFromIntError> { - let min = <$target>::min_value() as $storage; - let max = <$target>::max_value() as $storage; - if u as $storage < min || u as $storage > max { - Err(TryFromIntError(())) - } else { - Ok(u as $target) - } - } - } - )*} -} - macro_rules! same_sign_try_from_wider_impl { ($target:ty, $($source:ty),*) => {$( #[unstable(feature = "try_from", issue = "33417")] @@ -2553,29 +2533,31 @@ macro_rules! trivial_try_from_impl { #[inline] fn try_from(u: $source) -> Result<$target, TryFromIntError> { - // Using into as an extra check on the macro arguments. Ok(u as $target) } } )*} } -// The current implementations assume that usize/isize <= 64 bits wide. +#[cfg(not(any( + target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64")))] +compile_error!("The current implementations of try_from on usize/isize assumes that \ + the pointer width is either 16, 32, or 64"); // (source, $(target)) trivial_try_from_impl!(u8, u8, u16, i16, u32, i32, u64, i64, u128, i128, usize); -trivial_try_from_impl!(u16, u16, u32, i32, u64, i64, u128, i128); +trivial_try_from_impl!(u16, u16, u32, i32, u64, i64, u128, i128, usize); trivial_try_from_impl!(u32, u32, u64, i64, u128, i128); trivial_try_from_impl!(u64, u64, u128, i128); trivial_try_from_impl!(u128, u128); trivial_try_from_impl!(usize, usize, u128, i128); +trivial_try_from_impl!(usize, u64); trivial_try_from_impl!(i8, i8, i16, i32, i64, i128, isize); -trivial_try_from_impl!(i16, i16, i32, i64, i128); +trivial_try_from_impl!(i16, i16, i32, i64, i128, isize); trivial_try_from_impl!(i32, i32, i64, i128); trivial_try_from_impl!(i64, i64, i128); trivial_try_from_impl!(i128, i128); trivial_try_from_impl!(isize, isize, i128); -trivial_try_from_impl!(usize, u64); trivial_try_from_impl!(isize, i64); // (target, $(source)) @@ -2587,17 +2569,64 @@ same_sign_try_from_wider_impl!(u32, u64, u128); same_sign_try_from_wider_impl!(i32, i64, i128); same_sign_try_from_wider_impl!(u64, u128); same_sign_try_from_wider_impl!(i64, i128); +same_sign_try_from_wider_impl!(usize, u128); +same_sign_try_from_wider_impl!(isize, u128); + +macro_rules! cfg_block { + ($(#[$attr:meta]{$($it:item)*})*) => {$($( + #[$attr] + $it + )*)*} +} + -// Need to make sure the storage component is large enough for these. -// (storage, target, $(source)) -same_sign_try_from_int_impl!(u64, usize, u64, u32, u16); -same_sign_try_from_int_impl!(i64, isize, i64, i32, i16); -same_sign_try_from_int_impl!(u64, u16, usize); -same_sign_try_from_int_impl!(i64, i16, isize); -same_sign_try_from_int_impl!(u64, u32, usize); -same_sign_try_from_int_impl!(i64, i32, isize); -same_sign_try_from_int_impl!(u128, usize, u128); -same_sign_try_from_int_impl!(i128, isize, i128); +cfg_block!( + // Platform specific impls for conversions with the same sign: + // xsize -> x32 + // xsize -> x16 + // x32 -> xsize + // x64 -> xsize + + // 16-bit. + #[cfg(target_pointer_width = "16")] { + // x32 -> xsize + same_sign_try_from_wider_impl!(usize, u32); + same_sign_try_from_wider_impl!(isize, i32); + // xsize -> x16 + trivial_try_from_impl!(usize, u16); + trivial_try_from_impl!(isize, i16); + } + + // Same for 16 and 32-bit platforms. + #[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))] { + // xsize -> x32 + trivial_try_from_impl!(usize, u32); + trivial_try_from_impl!(isize, i32); + // x64 -> xsize + same_sign_try_from_wider_impl!(usize, u64); + same_sign_try_from_wider_impl!(isize, u64); + } + + // Same for 32 and 64-bit platforms. + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] { + // xsize -> x16 + same_sign_try_from_wider_impl!(u16, usize); + same_sign_try_from_wider_impl!(i16, isize); + // x32 -> xsize + trivial_try_from_impl!(u32, usize); + trivial_try_from_impl!(i32, isize); + } + + // 64-bit. + #[cfg(target_pointer_width = "64")] { + // xsize -> x32 + same_sign_try_from_wider_impl!(u32, usize); + same_sign_try_from_wider_impl!(i32, isize); + // x64 -> xsize + trivial_try_from_impl!(u64, usize); + trivial_try_from_impl!(i64, isize); + } +); macro_rules! unsigned_from_signed_impl { ($unsigned:ty, $($signed:ty, $storage:ty),*) => {$( From 95156e3b65cf102bfa7c5fdce1afc285f26dc8ce Mon Sep 17 00:00:00 2001 From: oyvindln Date: Fri, 14 Jul 2017 16:14:42 +0200 Subject: [PATCH 3/4] Enable compile error feature --- src/libcore/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index e8e31ffea0b98..0bfe2e71447d2 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -94,6 +94,10 @@ #![feature(unwind_attributes)] #![cfg_attr(stage0, feature(associated_consts))] +#![cfg_attr( + not(any(target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64")), + feature(compile_error) +)] #[prelude_import] #[allow(unused)] From 4cfeca4452dc1e7761845f9f2d698d0283b0001f Mon Sep 17 00:00:00 2001 From: oyvindln Date: Sat, 15 Jul 2017 18:02:21 +0200 Subject: [PATCH 4/4] Add tryfrom tests for xsize/x128, add some missed impls, slightly more readable Adds tests for the TryFrom impelemtatnions for xsize and x128 values together with the existing tests for this trait. Fix a few impls that had the wrong values, and add some that had been missed in the last commits. Make TryFrom impl macros match on "into/from" to make them a bit more readable, and group the arguments on the macros that use a storage value. --- src/libcore/num/mod.rs | 237 +++++++++++++++++++++-------------- src/libcore/tests/num/mod.rs | 214 +++++++++++++++++++++++++++++++ 2 files changed, 359 insertions(+), 92 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index ae8dc099481fb..902063c26a72a 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2504,8 +2504,9 @@ impl fmt::Display for TryFromIntError { } } +/// TryFrom on an integer type from a wider integer type of the same sign. macro_rules! same_sign_try_from_wider_impl { - ($target:ty, $($source:ty),*) => {$( + ($target:ident from $($source:ty),*) => {$( #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -2526,7 +2527,7 @@ macro_rules! same_sign_try_from_wider_impl { /// TryFrom on types where the conversion will always succeed. macro_rules! trivial_try_from_impl { - ($source:ty, $($target:ty),*) => {$( + ($source:ident into $($target:ty),*) => {$( #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -2539,39 +2540,18 @@ macro_rules! trivial_try_from_impl { )*} } -#[cfg(not(any( - target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64")))] -compile_error!("The current implementations of try_from on usize/isize assumes that \ - the pointer width is either 16, 32, or 64"); -// (source, $(target)) -trivial_try_from_impl!(u8, u8, u16, i16, u32, i32, u64, i64, u128, i128, usize); -trivial_try_from_impl!(u16, u16, u32, i32, u64, i64, u128, i128, usize); -trivial_try_from_impl!(u32, u32, u64, i64, u128, i128); -trivial_try_from_impl!(u64, u64, u128, i128); -trivial_try_from_impl!(u128, u128); -trivial_try_from_impl!(usize, usize, u128, i128); -trivial_try_from_impl!(usize, u64); - -trivial_try_from_impl!(i8, i8, i16, i32, i64, i128, isize); -trivial_try_from_impl!(i16, i16, i32, i64, i128, isize); -trivial_try_from_impl!(i32, i32, i64, i128); -trivial_try_from_impl!(i64, i64, i128); -trivial_try_from_impl!(i128, i128); -trivial_try_from_impl!(isize, isize, i128); -trivial_try_from_impl!(isize, i64); - -// (target, $(source)) -same_sign_try_from_wider_impl!(u8, u16, u32, u64, u128, usize); -same_sign_try_from_wider_impl!(i8, i16, i32, i64, i128, isize); -same_sign_try_from_wider_impl!(u16, u32, u64, u128); -same_sign_try_from_wider_impl!(i16, i32, i64, i128); -same_sign_try_from_wider_impl!(u32, u64, u128); -same_sign_try_from_wider_impl!(i32, i64, i128); -same_sign_try_from_wider_impl!(u64, u128); -same_sign_try_from_wider_impl!(i64, i128); -same_sign_try_from_wider_impl!(usize, u128); -same_sign_try_from_wider_impl!(isize, u128); +/// Groups items that assume the pointer width is either 16/32/64, and has to be altered if +/// support for larger/smaller pointer widths are added in the future. +macro_rules! assume_ptr_width { + {$($it:item)*} => {#[cfg(not(any( + target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64")))] + compile_error!("The current tests of try_from on usize/isize assume that \ + the pointer width is either 16, 32, or 64"); + $($it)* + } +} +/// Adds the attribute to all items in the block. macro_rules! cfg_block { ($(#[$attr:meta]{$($it:item)*})*) => {$($( #[$attr] @@ -2580,63 +2560,118 @@ macro_rules! cfg_block { } -cfg_block!( - // Platform specific impls for conversions with the same sign: - // xsize -> x32 - // xsize -> x16 - // x32 -> xsize - // x64 -> xsize +trivial_try_from_impl!(u8 into u8, u16, i16, u32, i32, u64, i64, u128, i128, usize); +trivial_try_from_impl!(u16 into u16, u32, i32, u64, i64, u128, i128); +trivial_try_from_impl!(u32 into u32, u64, i64, u128, i128); +trivial_try_from_impl!(u64 into u64, u128, i128); +trivial_try_from_impl!(u128 into u128); +trivial_try_from_impl!(usize into usize); - // 16-bit. - #[cfg(target_pointer_width = "16")] { - // x32 -> xsize - same_sign_try_from_wider_impl!(usize, u32); - same_sign_try_from_wider_impl!(isize, i32); - // xsize -> x16 - trivial_try_from_impl!(usize, u16); - trivial_try_from_impl!(isize, i16); - } +assume_ptr_width! { + trivial_try_from_impl!(usize into u64, u128, i128); + trivial_try_from_impl!(u16 into usize); +} - // Same for 16 and 32-bit platforms. - #[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))] { - // xsize -> x32 - trivial_try_from_impl!(usize, u32); - trivial_try_from_impl!(isize, i32); - // x64 -> xsize - same_sign_try_from_wider_impl!(usize, u64); - same_sign_try_from_wider_impl!(isize, u64); - } +trivial_try_from_impl!(i8 into i8, i16, i32, i64, i128, isize); +trivial_try_from_impl!(i16 into i16, i32, i64, i128); +trivial_try_from_impl!(i32 into i32, i64, i128); +trivial_try_from_impl!(i64 into i64, i128); +trivial_try_from_impl!(i128 into i128); +trivial_try_from_impl!(isize into isize); +assume_ptr_width! { + trivial_try_from_impl!(isize into i64, i128); + trivial_try_from_impl!(i16 into isize); +} - // Same for 32 and 64-bit platforms. - #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] { +same_sign_try_from_wider_impl!(u8 from u16, u32, u64, u128, usize); +same_sign_try_from_wider_impl!(i8 from i16, i32, i64, i128, isize); +same_sign_try_from_wider_impl!(u16 from u32, u64, u128); +same_sign_try_from_wider_impl!(i16 from i32, i64, i128); +same_sign_try_from_wider_impl!(u32 from u64, u128); +same_sign_try_from_wider_impl!(i32 from i64, i128); +same_sign_try_from_wider_impl!(u64 from u128); +same_sign_try_from_wider_impl!(i64 from i128); + +assume_ptr_width! { + same_sign_try_from_wider_impl!(usize from u128); + same_sign_try_from_wider_impl!(isize from i128); + + cfg_block!( + // Platform specific impls for conversions with the same sign: + // xsize -> x32 // xsize -> x16 - same_sign_try_from_wider_impl!(u16, usize); - same_sign_try_from_wider_impl!(i16, isize); // x32 -> xsize - trivial_try_from_impl!(u32, usize); - trivial_try_from_impl!(i32, isize); - } - - // 64-bit. - #[cfg(target_pointer_width = "64")] { - // xsize -> x32 - same_sign_try_from_wider_impl!(u32, usize); - same_sign_try_from_wider_impl!(i32, isize); // x64 -> xsize - trivial_try_from_impl!(u64, usize); - trivial_try_from_impl!(i64, isize); - } -); + + // 16-bit. + #[cfg(target_pointer_width = "16")] { + // xsize -> x16 + trivial_try_from_impl!(usize into u16); + trivial_try_from_impl!(isize into i16); + + // xsize -> x32 + trivial_try_from_impl!(usize into u32); + trivial_try_from_impl!(isize into i32); + + // x32 -> xsize + same_sign_try_from_wider_impl!(usize from u32); + same_sign_try_from_wider_impl!(isize from i32); + + // x64 -> xsize + same_sign_try_from_wider_impl!(usize from u64); + same_sign_try_from_wider_impl!(isize from i64); + } + + // Same for 32-bit platforms. + #[cfg(target_pointer_width = "32")] { + // xsize -> x16 + same_sign_try_from_wider_impl!(u16 from usize); + same_sign_try_from_wider_impl!(i16 from isize); + + // xsize -> x32 + trivial_try_from_impl!(usize into u32); + trivial_try_from_impl!(isize into i32); + + // x32 -> xsize + trivial_try_from_impl!(u32 into usize); + trivial_try_from_impl!(i32 into isize); + + // x64 -> xsize + same_sign_try_from_wider_impl!(usize from u64); + same_sign_try_from_wider_impl!(isize from i64); + } + + // 64-bit. + #[cfg(target_pointer_width = "64")] { + // xsize -> x16 + same_sign_try_from_wider_impl!(u16 from usize); + same_sign_try_from_wider_impl!(i16 from isize); + + // xsize -> x32 + same_sign_try_from_wider_impl!(u32 from usize); + same_sign_try_from_wider_impl!(i32 from isize); + + // x32 -> xsize + trivial_try_from_impl!(u32 into usize); + trivial_try_from_impl!(i32 into isize); + + // x64 -> xsize + trivial_try_from_impl!(u64 into usize); + trivial_try_from_impl!(i64 into isize); + } + ); + +} macro_rules! unsigned_from_signed_impl { - ($unsigned:ty, $($signed:ty, $storage:ty),*) => {$( + ($unsigned:ident from $(($signed:ty, $storage:ty)),*) => {$( #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$signed> for $unsigned { type Error = TryFromIntError; #[inline] fn try_from(u: $signed) -> Result<$unsigned, TryFromIntError> { - let max: $storage = <$unsigned>::max_value().into(); + let max: $storage = <$unsigned>::max_value() as $storage; if u < 0 || u as $storage > max { Err(TryFromIntError(())) } else { @@ -2648,7 +2683,7 @@ macro_rules! unsigned_from_signed_impl { } macro_rules! signed_from_unsigned_impl { - ($signed:ty, $($unsigned:ty, $storage:ty),*) => {$( + ($signed:ident from $(($unsigned:ty, $storage:ty)),*) => {$( #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$unsigned> for $signed { type Error = TryFromIntError; @@ -2666,20 +2701,38 @@ macro_rules! signed_from_unsigned_impl { )*} } -// (unsigned type, $(signed type, storage)) -unsigned_from_signed_impl!(u8, i8, u8, i16, i16, i32, i32, i64, i64, i128, i128, isize, u64); -unsigned_from_signed_impl!(u16, i8, u16, i16, u16, i32, u32, i64, u64, i128, i128, isize, u64); -unsigned_from_signed_impl!(u32, i8, u32, i16, u32, i32, u32, i64, u64, i128, i128, isize, u64); -unsigned_from_signed_impl!(u64, i8, u64, i16, u64, i32, u64, i64, u64, i128, i128, isize, u64); -unsigned_from_signed_impl!(u128, i8, u128, i16, u128, i32, u128, i64, u128, i128, u128, isize, - u128); - -// (signed type, $(unsigned type, storage)) -signed_from_unsigned_impl!(i8, u8, u8, u16, u16, u32, u32, u64, u64, u128, u128, usize, usize); -signed_from_unsigned_impl!(i16, u16, u16, u32, u32, u64, u64, u128, u128, usize, usize); -signed_from_unsigned_impl!(i32, u32, u32, u64, u64, u128, u128, usize, usize); -signed_from_unsigned_impl!(i64, u64, u64, u128, u128, usize, usize); -signed_from_unsigned_impl!(i128, u128, u128); +// (unsigned type from $(signed type, storage)) +assume_ptr_width!{ + unsigned_from_signed_impl!(u8 from (i8, u8), (i16, i16), (i32, i32), (i64, i64), + (i128, i128), (isize, usize)); + unsigned_from_signed_impl!(u16 from (i8, u16), (i16, u16), (i32, u32), (i64, u64), + (i128, i128), (isize, usize)); + unsigned_from_signed_impl!(u32 from (i8, u32), (i16, u32), (i32, u32), (i64, u64), + (i128, i128), (isize, u64)); + unsigned_from_signed_impl!(u64 from (i8, u64), (i16, u64), (i32, u64), (i64, u64), + (i128, i128), (isize, u64)); + unsigned_from_signed_impl!(usize from (isize, usize), (i8, usize), (i16, u64), (i32, u64), + (i64, u64), (i128, u128)); + +} + +unsigned_from_signed_impl!(u128 from (i8, u128), (i16, u128), (i32, u128), (i64, u128), + (i128, u128), (isize, u128)); + +// (signed type from $(unsigned type, storage)) +assume_ptr_width! { + signed_from_unsigned_impl!(i8 from (u8, u8), (u16, u16), (u32, u32), (u64, u64), (u128, u128), + (usize, usize)); + signed_from_unsigned_impl!(i16 from (u16, u16), (u32, u32), (u64, u64), (u128, u128), + (usize, usize)); + signed_from_unsigned_impl!(i32 from (u32, u32), (u64, u64), (u128, u128), (usize, usize)); + signed_from_unsigned_impl!(i64 from (u64, u64), (u128, u128), (usize, usize)); + signed_from_unsigned_impl!(isize from (usize, usize), (u8, usize), (u16, usize), (u32, u32), + (u64, u64), (u128, u128)); + +} + +signed_from_unsigned_impl!(i128 from (u128, u128)); #[doc(hidden)] trait FromStrRadixHelper: PartialOrd + Copy { diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index f233b649a8f3c..3e872b34e433d 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -36,6 +36,26 @@ mod flt2dec; mod dec2flt; mod bignum; + +/// Adds the attribute to all items in the block. +macro_rules! cfg_block { + ($(#[$attr:meta]{$($it:item)*})*) => {$($( + #[$attr] + $it + )*)*} +} + +/// Groups items that assume the pointer width is either 16/32/64, and has to be altered if +/// support for larger/smaller pointer widths are added in the future. +macro_rules! assume_usize_width { + {$($it:item)*} => {#[cfg(not(any( + target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64")))] + compile_error!("The current tests of try_from on usize/isize assume that \ + the pointer width is either 16, 32, or 64"); + $($it)* + } +} + /// Helper function for testing numeric operations pub fn test_num(ten: T, two: T) where T: PartialEq @@ -212,6 +232,8 @@ fn test_f32f64() { assert!(nan.is_nan()); } + +/// Conversions where the full width of $source can be represented as $target macro_rules! test_impl_try_from_always_ok { ($fn_name:ident, $source:ty, $target: ty) => { #[test] @@ -233,36 +255,89 @@ test_impl_try_from_always_ok! { test_try_u8u8, u8, u8 } test_impl_try_from_always_ok! { test_try_u8u16, u8, u16 } test_impl_try_from_always_ok! { test_try_u8u32, u8, u32 } test_impl_try_from_always_ok! { test_try_u8u64, u8, u64 } +test_impl_try_from_always_ok! { test_try_u8u128, u8, u128 } test_impl_try_from_always_ok! { test_try_u8i16, u8, i16 } test_impl_try_from_always_ok! { test_try_u8i32, u8, i32 } test_impl_try_from_always_ok! { test_try_u8i64, u8, i64 } +test_impl_try_from_always_ok! { test_try_u8i128, u8, i128 } test_impl_try_from_always_ok! { test_try_u16u16, u16, u16 } test_impl_try_from_always_ok! { test_try_u16u32, u16, u32 } test_impl_try_from_always_ok! { test_try_u16u64, u16, u64 } +test_impl_try_from_always_ok! { test_try_u16u128, u16, u128 } test_impl_try_from_always_ok! { test_try_u16i32, u16, i32 } test_impl_try_from_always_ok! { test_try_u16i64, u16, i64 } +test_impl_try_from_always_ok! { test_try_u16i128, u16, i128 } test_impl_try_from_always_ok! { test_try_u32u32, u32, u32 } test_impl_try_from_always_ok! { test_try_u32u64, u32, u64 } +test_impl_try_from_always_ok! { test_try_u32u128, u32, u128 } test_impl_try_from_always_ok! { test_try_u32i64, u32, i64 } +test_impl_try_from_always_ok! { test_try_u32i128, u32, i128 } test_impl_try_from_always_ok! { test_try_u64u64, u64, u64 } +test_impl_try_from_always_ok! { test_try_u64u128, u64, u128 } +test_impl_try_from_always_ok! { test_try_u64i128, u64, i128 } + +test_impl_try_from_always_ok! { test_try_u128, u128, u128 } test_impl_try_from_always_ok! { test_try_i8i8, i8, i8 } test_impl_try_from_always_ok! { test_try_i8i16, i8, i16 } test_impl_try_from_always_ok! { test_try_i8i32, i8, i32 } test_impl_try_from_always_ok! { test_try_i8i64, i8, i64 } +test_impl_try_from_always_ok! { test_try_i8i128, i8, i128 } test_impl_try_from_always_ok! { test_try_i16i16, i16, i16 } test_impl_try_from_always_ok! { test_try_i16i32, i16, i32 } test_impl_try_from_always_ok! { test_try_i16i64, i16, i64 } +test_impl_try_from_always_ok! { test_try_i16i128, i16, i128 } test_impl_try_from_always_ok! { test_try_i32i32, i32, i32 } test_impl_try_from_always_ok! { test_try_i32i64, i32, i64 } +test_impl_try_from_always_ok! { test_try_i32i128, i32, i128 } test_impl_try_from_always_ok! { test_try_i64i64, i64, i64 } +test_impl_try_from_always_ok! { test_try_i64i128, i64, i128 } + +test_impl_try_from_always_ok! { test_try_i128i128, i128, i128 } + +assume_usize_width! { + test_impl_try_from_always_ok! { test_try_u8usize, u8, usize } + test_impl_try_from_always_ok! { test_try_i8isize, i8, isize } + + test_impl_try_from_always_ok! { test_try_u16usize, u16, usize } + test_impl_try_from_always_ok! { test_try_i16isize, i16, isize } + + test_impl_try_from_always_ok! { test_try_usizeu64, usize, u64 } + test_impl_try_from_always_ok! { test_try_usizeu128, usize, u128 } + test_impl_try_from_always_ok! { test_try_usizei128, usize, i128 } + + test_impl_try_from_always_ok! { test_try_isizei64, isize, i64 } + test_impl_try_from_always_ok! { test_try_isizei128, isize, i128 } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_always_ok! { test_try_u16usize, u16, usize } + test_impl_try_from_always_ok! { test_try_i16isize, i16, isize } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } + test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } + test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } + test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } + test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } + test_impl_try_from_always_ok! { test_try_u64usize, u64, usize } + test_impl_try_from_always_ok! { test_try_i64isize, i64, isize } + } + ); +} +/// Conversions where max of $source can be represented as $target, macro_rules! test_impl_try_from_signed_to_unsigned_upper_ok { ($fn_name:ident, $source:ty, $target:ty) => { #[test] @@ -285,16 +360,51 @@ test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u8, i8, u8 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u16, i8, u16 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u32, i8, u32 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u64, i8, u64 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u128, i8, u128 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u16, i16, u16 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u32, i16, u32 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u64, i16, u64 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u128, i16, u128 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32u32, i32, u32 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32u64, i32, u64 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32u128, i32, u128 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64u64, i64, u64 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64u128, i64, u128 } + +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i128u128, i128, u128 } + +assume_usize_width! { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8usize, i8, usize } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16usize, i16, usize } + + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu64, isize, u64 } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu128, isize, u128 } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeusize, isize, usize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu16, isize, u16 } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } + + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } + } + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64usize, i64, usize } + } + ); +} + +/// Conversions where max of $source can not be represented as $target, +/// but min can. macro_rules! test_impl_try_from_unsigned_to_signed_upper_err { ($fn_name:ident, $source:ty, $target:ty) => { #[test] @@ -325,6 +435,39 @@ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i16, u64, i16 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i32, u64, i32 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i64, u64, i64 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i8, u128, i8 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i16, u128, i16 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i32, u128, i32 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i64, u128, i64 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i128, u128, i128 } + +assume_usize_width! { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64isize, u64, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128isize, u128, isize } + + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei8, usize, i8 } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei16, usize, i16 } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizeisize, usize, isize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u64, isize } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei64, usize, i64 } + } + ); +} + +/// Conversions where min/max of $source can not be represented as $target. macro_rules! test_impl_try_from_same_sign_err { ($fn_name:ident, $source:ty, $target:ty) => { #[test] @@ -359,7 +502,13 @@ test_impl_try_from_same_sign_err! { test_try_u64u8, u64, u8 } test_impl_try_from_same_sign_err! { test_try_u64u16, u64, u16 } test_impl_try_from_same_sign_err! { test_try_u64u32, u64, u32 } +test_impl_try_from_same_sign_err! { test_try_u128u8, u128, u8 } +test_impl_try_from_same_sign_err! { test_try_u128u16, u128, u16 } +test_impl_try_from_same_sign_err! { test_try_u128u32, u128, u32 } +test_impl_try_from_same_sign_err! { test_try_u128u64, u128, u64 } + test_impl_try_from_same_sign_err! { test_try_i16i8, i16, i8 } +test_impl_try_from_same_sign_err! { test_try_isizei8, isize, i8 } test_impl_try_from_same_sign_err! { test_try_i32i8, i32, i8 } test_impl_try_from_same_sign_err! { test_try_i32i16, i32, i16 } @@ -368,6 +517,45 @@ test_impl_try_from_same_sign_err! { test_try_i64i8, i64, i8 } test_impl_try_from_same_sign_err! { test_try_i64i16, i64, i16 } test_impl_try_from_same_sign_err! { test_try_i64i32, i64, i32 } +test_impl_try_from_same_sign_err! { test_try_i128i8, i128, i8 } +test_impl_try_from_same_sign_err! { test_try_i128i16, i128, i16 } +test_impl_try_from_same_sign_err! { test_try_i128i32, i128, i32 } +test_impl_try_from_same_sign_err! { test_try_i128i64, i128, i64 } + +assume_usize_width! { + test_impl_try_from_same_sign_err! { test_try_usizeu8, usize, u8 } + test_impl_try_from_same_sign_err! { test_try_u128usize, u128, usize } + test_impl_try_from_same_sign_err! { test_try_i128isize, i128, isize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_same_sign_err! { test_try_u32usize, u32, usize } + test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } + + test_impl_try_from_same_sign_err! { test_try_i32isize, i32, isize } + test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } + test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } + + test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } + test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } + test_impl_try_from_same_sign_err! { test_try_usizeu32, usize, u32 } + + test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } + test_impl_try_from_same_sign_err! { test_try_isizei32, isize, i32 } + } + ); +} + +/// Conversinos where neither the min nor the max of $source can be represented by +/// $target, but max/min of the target can be represented by the source. macro_rules! test_impl_try_from_signed_to_unsigned_err { ($fn_name:ident, $source:ty, $target:ty) => { #[test] @@ -400,6 +588,32 @@ test_impl_try_from_signed_to_unsigned_err! { test_try_i64u8, i64, u8 } test_impl_try_from_signed_to_unsigned_err! { test_try_i64u16, i64, u16 } test_impl_try_from_signed_to_unsigned_err! { test_try_i64u32, i64, u32 } +test_impl_try_from_signed_to_unsigned_err! { test_try_i128u8, i128, u8 } +test_impl_try_from_signed_to_unsigned_err! { test_try_i128u16, i128, u16 } +test_impl_try_from_signed_to_unsigned_err! { test_try_i128u32, i128, u32 } +test_impl_try_from_signed_to_unsigned_err! { test_try_i128u64, i128, u64 } + +assume_usize_width! { + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu8, isize, u8 } + test_impl_try_from_signed_to_unsigned_err! { test_try_i128usize, i128, usize } + + cfg_block! { + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_i32usize, i32, usize } + test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } + } + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } + + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } + } + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu32, isize, u32 } + } + } +} + macro_rules! test_float { ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr) => { mod $modname { use core::num::Float;