Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add inline annotations and avoid 128-bit where it's not needed in TryFrom + tests for xsize/x128 #43194

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 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
4 changes: 4 additions & 0 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
184 changes: 148 additions & 36 deletions src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2504,16 +2504,17 @@ impl fmt::Display for TryFromIntError {
}
}

macro_rules! same_sign_try_from_int_impl {
($storage:ty, $target:ty, $($source:ty),*) => {$(
macro_rules! same_sign_try_from_wider_impl {
($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 as FromStrRadixHelper>::min_value() as $storage;
let max = <$target as FromStrRadixHelper>::max_value() as $storage;
if u as $storage < min || u as $storage > max {
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 $target)
Expand All @@ -2523,42 +2524,120 @@ 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),*) => {$(
/// 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<$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 {
Err(TryFromIntError(()))
} else {
Ok(u as $signed)
}
#[inline]
fn try_from(u: $source) -> Result<$target, TryFromIntError> {
Ok(u as $target)
}
}
)*}
}

#[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);
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn’t this be isize, i128?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed


macro_rules! cfg_block {
($(#[$attr:meta]{$($it:item)*})*) => {$($(
#[$attr]
$it
)*)*}
}


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);
Copy link
Member

Choose a reason for hiding this comment

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

A cross-sign conversion again.

I think this code would be easier follow if it was only split into blocks for each target_pointer_width.

Something like:

#[cfg(target_pointer_width = "16")] { 
     trivial_try_from_impl!(usize, u16, u32);
     trivial_try_from_impl!(isize, i16, i32);
     same_sign_try_from_wider_impl!(usize, u32, u64);
     same_sign_try_from_wider_impl!(isize, i32, i64);
}

// and so forth.

Copy link
Member

@nagisa nagisa Jul 14, 2017

Choose a reason for hiding this comment

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

Also, I believe the argument order is swapped for same_sign_try_from_wider_impl here and in the block above? Was looking at the wrong macro.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It make make it more readable yeah.

}

// 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),*) => {$(
#[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)
Expand All @@ -2568,12 +2647,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 {
Expand All @@ -2587,15 +2693,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> {
Self::checked_mul(*self, other as Self)
}
#[inline]
fn checked_sub(&self, other: u32) -> Option<Self> {
Self::checked_sub(*self, other as Self)
}
#[inline]
fn checked_add(&self, other: u32) -> Option<Self> {
Self::checked_add(*self, other as Self)
}
Expand Down