From 998914f84fb0c7c967d677ae0373cbe8d3d5853a Mon Sep 17 00:00:00 2001 From: Bram van den Heuvel Date: Wed, 27 Oct 2021 09:23:08 +0200 Subject: [PATCH 1/2] Add lossless integer conversion by reference --- library/core/src/convert/num.rs | 27 ++ library/core/src/lib.rs | 1 + src/test/ui/num-from-num-ref/allowed.rs | 35 +++ src/test/ui/num-from-num-ref/illegal.rs | 22 ++ src/test/ui/num-from-num-ref/illegal.stderr | 234 ++++++++++++++++++ src/test/ui/traits/issue-77982.stderr | 2 +- .../ui/try-trait/bad-interconversion.stderr | 2 + 7 files changed, 322 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/num-from-num-ref/allowed.rs create mode 100644 src/test/ui/num-from-num-ref/illegal.rs create mode 100644 src/test/ui/num-from-num-ref/illegal.stderr diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 2b6ea90bf0430..8acebaa3f02fd 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -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")] } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 4b16a269f2d73..fcdf5a5a524e2 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -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)] diff --git a/src/test/ui/num-from-num-ref/allowed.rs b/src/test/ui/num-from-num-ref/allowed.rs new file mode 100644 index 0000000000000..ab25836bcfb2b --- /dev/null +++ b/src/test/ui/num-from-num-ref/allowed.rs @@ -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); +} diff --git a/src/test/ui/num-from-num-ref/illegal.rs b/src/test/ui/num-from-num-ref/illegal.rs new file mode 100644 index 0000000000000..26ea7ca712a55 --- /dev/null +++ b/src/test/ui/num-from-num-ref/illegal.rs @@ -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 +} diff --git a/src/test/ui/num-from-num-ref/illegal.stderr b/src/test/ui/num-from-num-ref/illegal.stderr new file mode 100644 index 0000000000000..344d044018d8f --- /dev/null +++ b/src/test/ui/num-from-num-ref/illegal.stderr @@ -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: + > + > + > + > +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: + > + > + > + > + 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: + > + > + > + > + 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: + > + > + > + > + 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: + > + > + > + > +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: + > + > + > + > + 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: + > + > + > + > + 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: + > + > + > + > + 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: + > + > + > + > +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: + > + > + > + > + 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: + > + > + > + > + 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: + > + > + > + > + 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: + > + > + > + > + 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`. diff --git a/src/test/ui/traits/issue-77982.stderr b/src/test/ui/traits/issue-77982.stderr index e868756504f19..107412a549282 100644 --- a/src/test/ui/traits/issue-77982.stderr +++ b/src/test/ui/traits/issue-77982.stderr @@ -49,7 +49,7 @@ LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect( - impl From for u32; - impl From for u32; - impl From for u32; - and 3 more + and 7 more note: required by `from` --> $SRC_DIR/core/src/convert/mod.rs:LL:COL | diff --git a/src/test/ui/try-trait/bad-interconversion.stderr b/src/test/ui/try-trait/bad-interconversion.stderr index 5cecf9128bb2c..fdd077ea216f9 100644 --- a/src/test/ui/try-trait/bad-interconversion.stderr +++ b/src/test/ui/try-trait/bad-interconversion.stderr @@ -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: + > + > > > = note: required because of the requirements on the impl of `FromResidual>` for `Result` From 02deb4c365a1f4f80e1918af74f32283d7e2de09 Mon Sep 17 00:00:00 2001 From: Bram van den Heuvel Date: Thu, 4 Nov 2021 12:25:00 +0100 Subject: [PATCH 2/2] Add lossless conversion by reference for NonZero integers --- library/core/src/convert/num.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 8acebaa3f02fd..723ee0db6dbec 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -430,6 +430,8 @@ macro_rules! nzint_impl_from { } } } + + impl_from_ref! { $Small, $Large } }; ($Small: ty, $Large: ty, #[$attr:meta]) => { nzint_impl_from!($Small, @@ -444,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