Skip to content

Add lossless integer conversion by reference #90551

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

Closed
Changes from all 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
37 changes: 37 additions & 0 deletions library/core/src/convert/num.rs
Original file line number Diff line number Diff line change
@@ -55,6 +55,8 @@ macro_rules! impl_from {
small as Self
}
}

impl_from_ref! { $Small, $Large }
};
($Small: ty, $Large: ty, #[$attr:meta]) => {
impl_from!($Small,
@@ -68,6 +70,21 @@ macro_rules! impl_from {
}
}

macro_rules! impl_from_ref {
($Small: ty, $Large: ty) => {
#[stable(feature = "num_from_num_ref", since = "1.60.0")]
#[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
#[doc = concat!("Converts `&", stringify!($Small), "` to `", stringify!($Large), "` losslessly.")]
#[doc = concat!("See the documentation of the `", stringify!($Small), "` to `", stringify!($Large), "` conversion.")]
impl const From<&$Small> for $Large {
#[inline]
fn from(small: &$Small) -> Self {
From::from(*small)
}
}
}
}

macro_rules! impl_from_bool {
($target: ty, #[$attr:meta]) => {
impl_from!(bool, $target, #[$attr], concat!("Converts a `bool` to a `",
@@ -98,30 +115,40 @@ impl_from_bool! { i128, #[stable(feature = "from_bool", since = "1.28.0")] }
impl_from_bool! { isize, #[stable(feature = "from_bool", since = "1.28.0")] }

// Unsigned -> Unsigned
impl_from_ref! { u8, u8 }
impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u8, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u8, u128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from! { u8, usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from_ref! { u16, u16 }
impl_from! { u16, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u16, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u16, u128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from_ref! { u32, u32 }
impl_from! { u32, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u32, u128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from_ref! { u64, u64 }
impl_from! { u64, u128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from_ref! { u128, u128 }

// Signed -> Signed
impl_from_ref! { i8, i8 }
impl_from! { i8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i8, i128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from! { i8, isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from_ref! { i16, i16 }
impl_from! { i16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i16, i128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from_ref! { i32, i32 }
impl_from! { i32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i32, i128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from_ref! { i64, i64 }
impl_from! { i64, i128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from_ref! { i128, i128 }

// Unsigned -> Signed
impl_from! { u8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
@@ -403,6 +430,8 @@ macro_rules! nzint_impl_from {
}
}
}

impl_from_ref! { $Small, $Large }
};
($Small: ty, $Large: ty, #[$attr:meta]) => {
nzint_impl_from!($Small,
@@ -417,31 +446,39 @@ macro_rules! nzint_impl_from {
}

// Non-zero Unsigned -> Non-zero Unsigned
impl_from_ref! { NonZeroU8, NonZeroU8 }
nzint_impl_from! { NonZeroU8, NonZeroU16, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU8, NonZeroU32, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU8, NonZeroU64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU8, NonZeroU128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU8, NonZeroUsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
impl_from_ref! { NonZeroU16, NonZeroU16 }
nzint_impl_from! { NonZeroU16, NonZeroU32, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU16, NonZeroU64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU16, NonZeroU128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU16, NonZeroUsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
impl_from_ref! { NonZeroU32, NonZeroU32 }
nzint_impl_from! { NonZeroU32, NonZeroU64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroU32, NonZeroU128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
impl_from_ref! { NonZeroU64, NonZeroU64 }
nzint_impl_from! { NonZeroU64, NonZeroU128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }

// Non-zero Signed -> Non-zero Signed
impl_from_ref! { NonZeroI8, NonZeroI8 }
nzint_impl_from! { NonZeroI8, NonZeroI16, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI8, NonZeroI32, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI8, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI8, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI8, NonZeroIsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
impl_from_ref! { NonZeroI16, NonZeroI16 }
nzint_impl_from! { NonZeroI16, NonZeroI32, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI16, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI16, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI16, NonZeroIsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
impl_from_ref! { NonZeroI32, NonZeroI32 }
nzint_impl_from! { NonZeroI32, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
nzint_impl_from! { NonZeroI32, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
impl_from_ref! { NonZeroI64, NonZeroI64 }
nzint_impl_from! { NonZeroI64, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }

// NonZero UnSigned -> Non-zero Signed
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -104,6 +104,7 @@
#![feature(const_bigint_helper_methods)]
#![feature(const_caller_location)]
#![feature(const_cell_into_inner)]
#![feature(const_convert)]
#![feature(const_discriminant)]
#![cfg_attr(not(bootstrap), feature(const_eval_select))]
#![feature(const_float_bits_conv)]
35 changes: 35 additions & 0 deletions src/test/ui/num-from-num-ref/allowed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// check-pass

fn main () {
// same size, signed
let _: i8 = From::from(&1_i8);
let _: i16 = From::from(&1_i16);
let _: i32 = From::from(&1_i32);
let _: i64 = From::from(&1_i64);
let _: i128 = From::from(&1_i128);

// same size, unsigned
let _: u8 = From::from(&1_u8);
let _: u16 = From::from(&1_u16);
let _: u32 = From::from(&1_u32);
let _: u64 = From::from(&1_u64);
let _: u128 = From::from(&1_u128);

// smaller, signed
let _: i16 = From::from(&1_i8);
let _: i32 = From::from(&1_i16);
let _: i64 = From::from(&1_i32);
let _: i128 = From::from(&1_i64);

// smaller, unsigned
let _: u16 = From::from(&1_u8);
let _: u32 = From::from(&1_u16);
let _: u64 = From::from(&1_u32);
let _: u128 = From::from(&1_u64);

// mixed signs
let _: i16 = From::from(&1_u8);
let _: i32 = From::from(&1_u16);
let _: i64 = From::from(&1_u32);
let _: i128 = From::from(&1_u64);
}
22 changes: 22 additions & 0 deletions src/test/ui/num-from-num-ref/illegal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Check that conversions by reference which are not lossless are not implemented.

fn main () {
// larger, signed
let _: i8 = From::from(&1_i16); //~ ERROR
let _: i16 = From::from(&1_i32); //~ ERROR
let _: i32 = From::from(&1_i64); //~ ERROR
let _: i64 = From::from(&1_i128); //~ ERROR

// larger, unsigned
let _: u8 = From::from(&1_u16); //~ ERROR
let _: u16 = From::from(&1_u32); //~ ERROR
let _: u32 = From::from(&1_u64); //~ ERROR
let _: u64 = From::from(&1_u128); //~ ERROR

// mixed signs
let _: i8 = From::from(&1_u8); //~ ERROR
let _: u16 = From::from(&1_i8); //~ ERROR
let _: i32 = From::from(&1_u32); //~ ERROR
let _: u64 = From::from(&1_i32); //~ ERROR
let _: i128 = From::from(&1_u128); //~ ERROR
}
234 changes: 234 additions & 0 deletions src/test/ui/num-from-num-ref/illegal.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
error[E0277]: the trait bound `i8: From<&i16>` is not satisfied
--> $DIR/illegal.rs:5:17
|
LL | let _: i8 = From::from(&1_i16);
| ^^^^^^^^^^ the trait `From<&i16>` is not implemented for `i8`
|
= help: the following implementations were found:
<i8 as From<&bool>>
<i8 as From<&i8>>
<i8 as From<NonZeroI8>>
<i8 as From<bool>>
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `i16: From<&i32>` is not satisfied
--> $DIR/illegal.rs:6:18
|
LL | let _: i16 = From::from(&1_i32);
| ^^^^^^^^^^ the trait `From<&i32>` is not implemented for `i16`
|
= help: the following implementations were found:
<i16 as From<&bool>>
<i16 as From<&i16>>
<i16 as From<&i8>>
<i16 as From<&u8>>
and 4 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `i32: From<&i64>` is not satisfied
--> $DIR/illegal.rs:7:18
|
LL | let _: i32 = From::from(&1_i64);
| ^^^^^^^^^^ the trait `From<&i64>` is not implemented for `i32`
|
= help: the following implementations were found:
<i32 as From<&bool>>
<i32 as From<&i16>>
<i32 as From<&i32>>
<i32 as From<&i8>>
and 8 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `i64: From<&i128>` is not satisfied
--> $DIR/illegal.rs:8:18
|
LL | let _: i64 = From::from(&1_i128);
| ^^^^^^^^^^ the trait `From<&i128>` is not implemented for `i64`
|
= help: the following implementations were found:
<i64 as From<&bool>>
<i64 as From<&i16>>
<i64 as From<&i32>>
<i64 as From<&i64>>
and 12 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `u8: From<&u16>` is not satisfied
--> $DIR/illegal.rs:11:17
|
LL | let _: u8 = From::from(&1_u16);
| ^^^^^^^^^^ the trait `From<&u16>` is not implemented for `u8`
|
= help: the following implementations were found:
<u8 as From<&bool>>
<u8 as From<&u8>>
<u8 as From<NonZeroU8>>
<u8 as From<bool>>
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `u16: From<&u32>` is not satisfied
--> $DIR/illegal.rs:12:18
|
LL | let _: u16 = From::from(&1_u32);
| ^^^^^^^^^^ the trait `From<&u32>` is not implemented for `u16`
|
= help: the following implementations were found:
<u16 as From<&bool>>
<u16 as From<&u16>>
<u16 as From<&u8>>
<u16 as From<NonZeroU16>>
and 2 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `u32: From<&u64>` is not satisfied
--> $DIR/illegal.rs:13:18
|
LL | let _: u32 = From::from(&1_u64);
| ^^^^^^^^^^ the trait `From<&u64>` is not implemented for `u32`
|
= help: the following implementations were found:
<u32 as From<&bool>>
<u32 as From<&u16>>
<u32 as From<&u32>>
<u32 as From<&u8>>
and 6 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `u64: From<&u128>` is not satisfied
--> $DIR/illegal.rs:14:18
|
LL | let _: u64 = From::from(&1_u128);
| ^^^^^^^^^^ the trait `From<&u128>` is not implemented for `u64`
|
= help: the following implementations were found:
<u64 as From<&bool>>
<u64 as From<&u16>>
<u64 as From<&u32>>
<u64 as From<&u64>>
and 7 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `i8: From<&u8>` is not satisfied
--> $DIR/illegal.rs:17:17
|
LL | let _: i8 = From::from(&1_u8);
| ^^^^^^^^^^ the trait `From<&u8>` is not implemented for `i8`
|
= help: the following implementations were found:
<i8 as From<&bool>>
<i8 as From<&i8>>
<i8 as From<NonZeroI8>>
<i8 as From<bool>>
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `u16: From<&i8>` is not satisfied
--> $DIR/illegal.rs:18:18
|
LL | let _: u16 = From::from(&1_i8);
| ^^^^^^^^^^ the trait `From<&i8>` is not implemented for `u16`
|
= help: the following implementations were found:
<u16 as From<&bool>>
<u16 as From<&u16>>
<u16 as From<&u8>>
<u16 as From<NonZeroU16>>
and 2 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `i32: From<&u32>` is not satisfied
--> $DIR/illegal.rs:19:18
|
LL | let _: i32 = From::from(&1_u32);
| ^^^^^^^^^^ the trait `From<&u32>` is not implemented for `i32`
|
= help: the following implementations were found:
<i32 as From<&bool>>
<i32 as From<&i16>>
<i32 as From<&i32>>
<i32 as From<&i8>>
and 8 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `u64: From<&i32>` is not satisfied
--> $DIR/illegal.rs:20:18
|
LL | let _: u64 = From::from(&1_i32);
| ^^^^^^^^^^ the trait `From<&i32>` is not implemented for `u64`
|
= help: the following implementations were found:
<u64 as From<&bool>>
<u64 as From<&u16>>
<u64 as From<&u32>>
<u64 as From<&u64>>
and 7 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `i128: From<&u128>` is not satisfied
--> $DIR/illegal.rs:21:19
|
LL | let _: i128 = From::from(&1_u128);
| ^^^^^^^^^^ the trait `From<&u128>` is not implemented for `i128`
|
= help: the following implementations were found:
<i128 as From<&bool>>
<i128 as From<&i128>>
<i128 as From<&i16>>
<i128 as From<&i32>>
and 16 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 13 previous errors

For more information about this error, try `rustc --explain E0277`.
2 changes: 1 addition & 1 deletion src/test/ui/traits/issue-77982.stderr
Original file line number Diff line number Diff line change
@@ -49,7 +49,7 @@ LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect(
- impl From<NonZeroU32> for u32;
- impl From<bool> for u32;
- impl From<char> for u32;
and 3 more
and 7 more
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
2 changes: 2 additions & 0 deletions src/test/ui/try-trait/bad-interconversion.stderr
Original file line number Diff line number Diff line change
@@ -8,6 +8,8 @@ LL | Ok(Err(123_i32)?)
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following implementations were found:
<u8 as From<&bool>>
<u8 as From<&u8>>
<u8 as From<NonZeroU8>>
<u8 as From<bool>>
= note: required because of the requirements on the impl of `FromResidual<Result<Infallible, i32>>` for `Result<u64, u8>`