From d15a98b87815850ef9dd11564e896b6f19b724c3 Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Sat, 22 Feb 2020 14:03:46 +0100 Subject: [PATCH 1/2] Stabilize const for integer {to,from}_{be,le,ne}_bytes methods All of these functions can be implemented simply and naturally as const functions, e.g. u32::from_le_bytes can be implemented as (bytes[0] as u32) | (bytes[1] as u32) << 8 | (bytes[2] as u32) << 16 | (bytes[3] as u32) << 24 So stabilizing the constness will not expose that internally they are implemented using transmute which is not const in stable. --- src/libcore/lib.rs | 1 - src/libcore/num/mod.rs | 28 +++++++++++-------- .../ui/consts/const-int-conversion-rpass.rs | 2 -- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index bca96b77812..00909094cd0 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -131,7 +131,6 @@ #![feature(rtm_target_feature)] #![feature(f16c_target_feature)] #![feature(hexagon_target_feature)] -#![feature(const_int_conversion)] #![feature(const_transmute)] #![feature(structural_match)] #![feature(abi_unadjusted)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 6f55e7c8be8..22897680567 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2195,7 +2195,7 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); assert_eq!(bytes, ", $be_bytes, "); ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] #[inline] pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { self.to_be().to_ne_bytes() @@ -2215,7 +2215,7 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); assert_eq!(bytes, ", $le_bytes, "); ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] #[inline] pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { self.to_le().to_ne_bytes() @@ -2250,7 +2250,8 @@ assert_eq!( ); ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] + #[allow_internal_unstable(const_transmute)] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { // SAFETY: integers are plain old datatypes so we can always transmute them to @@ -2284,7 +2285,7 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), } ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] #[inline] pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { Self::from_be(Self::from_ne_bytes(bytes)) @@ -2317,7 +2318,7 @@ fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), } ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] #[inline] pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { Self::from_le(Self::from_ne_bytes(bytes)) @@ -2360,7 +2361,8 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), } ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] + #[allow_internal_unstable(const_transmute)] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { // SAFETY: integers are plain old datatypes so we can always transmute to them @@ -4132,7 +4134,7 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); assert_eq!(bytes, ", $be_bytes, "); ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] #[inline] pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { self.to_be().to_ne_bytes() @@ -4152,7 +4154,7 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); assert_eq!(bytes, ", $le_bytes, "); ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] #[inline] pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { self.to_le().to_ne_bytes() @@ -4187,7 +4189,8 @@ assert_eq!( ); ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] + #[allow_internal_unstable(const_transmute)] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { // SAFETY: integers are plain old datatypes so we can always transmute them to @@ -4221,7 +4224,7 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), } ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] #[inline] pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { Self::from_be(Self::from_ne_bytes(bytes)) @@ -4254,7 +4257,7 @@ fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), } ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] #[inline] pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { Self::from_le(Self::from_ne_bytes(bytes)) @@ -4297,7 +4300,8 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), } ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] + #[allow_internal_unstable(const_transmute)] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { // SAFETY: integers are plain old datatypes so we can always transmute to them diff --git a/src/test/ui/consts/const-int-conversion-rpass.rs b/src/test/ui/consts/const-int-conversion-rpass.rs index d52dbbae1e7..6484169dd9a 100644 --- a/src/test/ui/consts/const-int-conversion-rpass.rs +++ b/src/test/ui/consts/const-int-conversion-rpass.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(const_int_conversion)] - const REVERSE: u32 = 0x12345678_u32.reverse_bits(); const FROM_BE_BYTES: i32 = i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]); const FROM_LE_BYTES: i32 = i32::from_le_bytes([0x12, 0x34, 0x56, 0x78]); From 87f0dc63a864c6d9a3c34aa4052762dbcd316c91 Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Wed, 26 Feb 2020 11:59:37 +0100 Subject: [PATCH 2/2] use unions instead of transmute and add const safety comments --- src/libcore/num/mod.rs | 44 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 22897680567..b64abc31936 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2251,12 +2251,19 @@ assert_eq!( ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] - #[allow_internal_unstable(const_transmute)] + // SAFETY: const sound because integers are plain old datatypes so we can always + // transmute them to arrays of bytes + #[allow_internal_unstable(const_fn_union)] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { + #[repr(C)] + union Bytes { + val: $SelfT, + bytes: [u8; mem::size_of::<$SelfT>()], + } // SAFETY: integers are plain old datatypes so we can always transmute them to // arrays of bytes - unsafe { mem::transmute(self) } + unsafe { Bytes { val: self }.bytes } } } @@ -2362,11 +2369,18 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] - #[allow_internal_unstable(const_transmute)] + // SAFETY: const sound because integers are plain old datatypes so we can always + // transmute to them + #[allow_internal_unstable(const_fn_union)] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { + #[repr(C)] + union Bytes { + val: $SelfT, + bytes: [u8; mem::size_of::<$SelfT>()], + } // SAFETY: integers are plain old datatypes so we can always transmute to them - unsafe { mem::transmute(bytes) } + unsafe { Bytes { bytes }.val } } } } @@ -4190,12 +4204,19 @@ assert_eq!( ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] - #[allow_internal_unstable(const_transmute)] + // SAFETY: const sound because integers are plain old datatypes so we can always + // transmute them to arrays of bytes + #[allow_internal_unstable(const_fn_union)] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { + #[repr(C)] + union Bytes { + val: $SelfT, + bytes: [u8; mem::size_of::<$SelfT>()], + } // SAFETY: integers are plain old datatypes so we can always transmute them to // arrays of bytes - unsafe { mem::transmute(self) } + unsafe { Bytes { val: self }.bytes } } } @@ -4301,11 +4322,18 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] - #[allow_internal_unstable(const_transmute)] + // SAFETY: const sound because integers are plain old datatypes so we can always + // transmute to them + #[allow_internal_unstable(const_fn_union)] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { + #[repr(C)] + union Bytes { + val: $SelfT, + bytes: [u8; mem::size_of::<$SelfT>()], + } // SAFETY: integers are plain old datatypes so we can always transmute to them - unsafe { mem::transmute(bytes) } + unsafe { Bytes { bytes }.val } } } }