From 58d70d6805565ec2208a88f2d8d414fc940beed6 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Wed, 31 Jan 2024 06:06:50 +0100 Subject: [PATCH 1/5] Simplify `impl_zeroable_primitive` macro. --- library/core/src/num/nonzero.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 1124719fc8df1..ea922970b92d8 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -35,7 +35,7 @@ mod private { pub trait ZeroablePrimitive: Sized + Copy + private::Sealed {} macro_rules! impl_zeroable_primitive { - ($NonZero:ident ( $primitive:ty )) => { + ($primitive:ty) => { #[unstable( feature = "nonzero_internals", reason = "implementation detail which may disappear or be replaced at any time", @@ -52,18 +52,18 @@ macro_rules! impl_zeroable_primitive { }; } -impl_zeroable_primitive!(NonZeroU8(u8)); -impl_zeroable_primitive!(NonZeroU16(u16)); -impl_zeroable_primitive!(NonZeroU32(u32)); -impl_zeroable_primitive!(NonZeroU64(u64)); -impl_zeroable_primitive!(NonZeroU128(u128)); -impl_zeroable_primitive!(NonZeroUsize(usize)); -impl_zeroable_primitive!(NonZeroI8(i8)); -impl_zeroable_primitive!(NonZeroI16(i16)); -impl_zeroable_primitive!(NonZeroI32(i32)); -impl_zeroable_primitive!(NonZeroI64(i64)); -impl_zeroable_primitive!(NonZeroI128(i128)); -impl_zeroable_primitive!(NonZeroIsize(isize)); +impl_zeroable_primitive!(u8); +impl_zeroable_primitive!(u16); +impl_zeroable_primitive!(u32); +impl_zeroable_primitive!(u64); +impl_zeroable_primitive!(u128); +impl_zeroable_primitive!(usize); +impl_zeroable_primitive!(i8); +impl_zeroable_primitive!(i16); +impl_zeroable_primitive!(i32); +impl_zeroable_primitive!(i64); +impl_zeroable_primitive!(i128); +impl_zeroable_primitive!(isize); /// A value that is known not to equal zero. /// From a67b72c74e8b59eb0eeb48767cb37e6c1a139329 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Mon, 22 Jan 2024 18:04:05 +0100 Subject: [PATCH 2/5] Make `NonZero` constructors generic. --- library/core/src/num/nonzero.rs | 155 +++++++++++++++++--------------- 1 file changed, 84 insertions(+), 71 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index ea922970b92d8..8cbbc2aa1a24c 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -83,6 +83,90 @@ impl_zeroable_primitive!(isize); #[rustc_diagnostic_item = "NonZero"] pub struct NonZero(T); +impl NonZero +where + T: ZeroablePrimitive, +{ + /// Creates a non-zero if the given value is not zero. + #[stable(feature = "nonzero", since = "1.28.0")] + #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")] + #[rustc_allow_const_fn_unstable(const_refs_to_cell)] + #[must_use] + #[inline] + pub const fn new(n: T) -> Option { + // SAFETY: Memory layout optimization guarantees that `Option>` has + // the same layout and size as `T`, with `0` representing `None`. + unsafe { crate::mem::transmute_copy(&n) } + } + + /// Creates a non-zero without checking whether the value is non-zero. + /// This results in undefined behaviour if the value is zero. + /// + /// # Safety + /// + /// The value must not be zero. + #[stable(feature = "nonzero", since = "1.28.0")] + #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] + #[must_use] + #[inline] + pub const unsafe fn new_unchecked(n: T) -> Self { + match Self::new(n) { + Some(n) => n, + None => { + // SAFETY: The caller guarantees that `n` is non-zero, so this is unreachable. + unsafe { + crate::intrinsics::assert_unsafe_precondition!( + "NonZero::new_unchecked requires the argument to be non-zero", + () => false + ); + + crate::hint::unreachable_unchecked() + } + } + } + } + + /// Converts a reference to a non-zero mutable reference + /// if the referenced value is not zero. + #[unstable(feature = "nonzero_from_mut", issue = "106290")] + #[must_use] + #[inline] + pub fn from_mut(n: &mut T) -> Option<&mut Self> { + // SAFETY: Memory layout optimization guarantees that `Option>` has + // the same layout and size as `T`, with `0` representing `None`. + let opt_n = unsafe { &mut *(n as *mut T as *mut Option) }; + + opt_n.as_mut() + } + + /// Converts a mutable reference to a non-zero mutable reference + /// without checking whether the referenced value is non-zero. + /// This results in undefined behavior if the referenced value is zero. + /// + /// # Safety + /// + /// The referenced value must not be zero. + #[unstable(feature = "nonzero_from_mut", issue = "106290")] + #[must_use] + #[inline] + pub unsafe fn from_mut_unchecked(n: &mut T) -> &mut Self { + match Self::from_mut(n) { + Some(n) => n, + None => { + // SAFETY: The caller guarantees that `n` references a value that is non-zero, so this is unreachable. + unsafe { + crate::intrinsics::assert_unsafe_precondition!( + "NonZero::from_mut_unchecked requires the argument to dereference as non-zero", + () => false + ); + + crate::hint::unreachable_unchecked() + } + } + } + } +} + macro_rules! impl_nonzero_fmt { ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { $( @@ -100,7 +184,6 @@ macro_rules! impl_nonzero_fmt { macro_rules! nonzero_integer { ( #[$stability:meta] - #[$const_new_unchecked_stability:meta] Self = $Ty:ident, Primitive = $signedness:ident $Int:ident, $(UnsignedNonZero = $UnsignedNonZero:ident,)? @@ -143,74 +226,6 @@ macro_rules! nonzero_integer { pub type $Ty = NonZero<$Int>; impl $Ty { - /// Creates a non-zero without checking whether the value is non-zero. - /// This results in undefined behaviour if the value is zero. - /// - /// # Safety - /// - /// The value must not be zero. - #[$stability] - #[$const_new_unchecked_stability] - #[must_use] - #[inline] - pub const unsafe fn new_unchecked(n: $Int) -> Self { - crate::panic::debug_assert_nounwind!( - n != 0, - concat!(stringify!($Ty), "::new_unchecked requires a non-zero argument") - ); - // SAFETY: this is guaranteed to be safe by the caller. - unsafe { - Self(n) - } - } - - /// Creates a non-zero if the given value is not zero. - #[$stability] - #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")] - #[must_use] - #[inline] - pub const fn new(n: $Int) -> Option { - if n != 0 { - // SAFETY: we just checked that there's no `0` - Some(unsafe { Self(n) }) - } else { - None - } - } - - /// Converts a primitive mutable reference to a non-zero mutable reference - /// without checking whether the referenced value is non-zero. - /// This results in undefined behavior if `*n` is zero. - /// - /// # Safety - /// The referenced value must not be currently zero. - #[unstable(feature = "nonzero_from_mut", issue = "106290")] - #[must_use] - #[inline] - pub unsafe fn from_mut_unchecked(n: &mut $Int) -> &mut Self { - // SAFETY: Self is repr(transparent), and the value is assumed to be non-zero. - unsafe { - let n_alias = &mut *n; - core::intrinsics::assert_unsafe_precondition!( - concat!(stringify!($Ty), "::from_mut_unchecked requires the argument to dereference as non-zero"), - (n_alias: &mut $Int) => *n_alias != 0 - ); - &mut *(n as *mut $Int as *mut Self) - } - } - - /// Converts a primitive mutable reference to a non-zero mutable reference - /// if the referenced integer is not zero. - #[unstable(feature = "nonzero_from_mut", issue = "106290")] - #[must_use] - #[inline] - pub fn from_mut(n: &mut $Int) -> Option<&mut Self> { - // SAFETY: Self is repr(transparent), and the value is non-zero. - // As long as the returned reference is alive, - // the user cannot `*n = 0` directly. - (*n != 0).then(|| unsafe { &mut *(n as *mut $Int as *mut Self) }) - } - /// Returns the value as a primitive type. #[$stability] #[inline] @@ -724,7 +739,6 @@ macro_rules! nonzero_integer { (Self = $Ty:ident, Primitive = unsigned $Int:ident $(,)?) => { nonzero_integer! { #[stable(feature = "nonzero", since = "1.28.0")] - #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] Self = $Ty, Primitive = unsigned $Int, UnsignedPrimitive = $Int, @@ -735,7 +749,6 @@ macro_rules! nonzero_integer { (Self = $Ty:ident, Primitive = signed $Int:ident, $($rest:tt)*) => { nonzero_integer! { #[stable(feature = "signed_nonzero", since = "1.34.0")] - #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] Self = $Ty, Primitive = signed $Int, $($rest)* From af48cf63ee9b03801446ea9f14bdcba85b8035d5 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Wed, 7 Feb 2024 16:00:12 +0100 Subject: [PATCH 3/5] Don't use `assert_unsafe_precondition` twice. --- library/core/src/num/nonzero.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 8cbbc2aa1a24c..3d930c0831837 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -3,6 +3,7 @@ use crate::cmp::Ordering; use crate::fmt; use crate::hash::{Hash, Hasher}; +use crate::intrinsics; #[cfg(bootstrap)] use crate::marker::StructuralEq; use crate::marker::StructuralPartialEq; @@ -11,7 +12,6 @@ use crate::str::FromStr; use super::from_str_radix; use super::{IntErrorKind, ParseIntError}; -use crate::intrinsics; mod private { #[unstable( @@ -115,12 +115,11 @@ where None => { // SAFETY: The caller guarantees that `n` is non-zero, so this is unreachable. unsafe { - crate::intrinsics::assert_unsafe_precondition!( - "NonZero::new_unchecked requires the argument to be non-zero", - () => false + intrinsics::assert_unsafe_precondition!( + "NonZero::new_unchecked requires the argument to be non-zero", + () => false, ); - - crate::hint::unreachable_unchecked() + intrinsics::unreachable() } } } @@ -155,12 +154,11 @@ where None => { // SAFETY: The caller guarantees that `n` references a value that is non-zero, so this is unreachable. unsafe { - crate::intrinsics::assert_unsafe_precondition!( + intrinsics::assert_unsafe_precondition!( "NonZero::from_mut_unchecked requires the argument to dereference as non-zero", - () => false + () => false, ); - - crate::hint::unreachable_unchecked() + intrinsics::unreachable() } } } @@ -770,7 +768,7 @@ macro_rules! nonzero_integer_signedness_dependent_impls { fn div(self, other: $Ty) -> $Int { // SAFETY: div by zero is checked because `other` is a nonzero, // and MIN/-1 is checked because `self` is an unsigned int. - unsafe { crate::intrinsics::unchecked_div(self, other.get()) } + unsafe { intrinsics::unchecked_div(self, other.get()) } } } @@ -783,7 +781,7 @@ macro_rules! nonzero_integer_signedness_dependent_impls { fn rem(self, other: $Ty) -> $Int { // SAFETY: rem by zero is checked because `other` is a nonzero, // and MIN/-1 is checked because `self` is an unsigned int. - unsafe { crate::intrinsics::unchecked_rem(self, other.get()) } + unsafe { intrinsics::unchecked_rem(self, other.get()) } } } }; From 5d65418e737584e303d70a49270326822bcd2a8f Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Wed, 7 Feb 2024 16:00:48 +0100 Subject: [PATCH 4/5] Replace `transmute_copy` with `ptr::read`. --- library/core/src/num/nonzero.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 3d930c0831837..193f2fa8731af 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -8,6 +8,7 @@ use crate::intrinsics; use crate::marker::StructuralEq; use crate::marker::StructuralPartialEq; use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem}; +use crate::ptr; use crate::str::FromStr; use super::from_str_radix; @@ -96,7 +97,7 @@ where pub const fn new(n: T) -> Option { // SAFETY: Memory layout optimization guarantees that `Option>` has // the same layout and size as `T`, with `0` representing `None`. - unsafe { crate::mem::transmute_copy(&n) } + unsafe { ptr::read(ptr::addr_of!(n).cast()) } } /// Creates a non-zero without checking whether the value is non-zero. From 42298756c740e217058c4fedebf2063192246ae0 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Tue, 6 Feb 2024 09:04:19 +0100 Subject: [PATCH 5/5] Update test output. --- tests/ui/print_type_sizes/niche-filling.rs | 4 ++-- tests/ui/print_type_sizes/niche-filling.stdout | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/ui/print_type_sizes/niche-filling.rs b/tests/ui/print_type_sizes/niche-filling.rs index 5ee5085ddc8e1..feb9643850d05 100644 --- a/tests/ui/print_type_sizes/niche-filling.rs +++ b/tests/ui/print_type_sizes/niche-filling.rs @@ -1,5 +1,5 @@ -// compile-flags: -Z print-type-sizes --crate-type=lib -// ignore-debug debug assertions will print more types +// compile-flags: -Z print-type-sizes --crate-type lib +// ignore-debug: debug assertions will print more types // build-pass // ignore-pass // ^-- needed because `--pass check` does not emit the output needed. diff --git a/tests/ui/print_type_sizes/niche-filling.stdout b/tests/ui/print_type_sizes/niche-filling.stdout index b53b893660321..53a58ccc4eef8 100644 --- a/tests/ui/print_type_sizes/niche-filling.stdout +++ b/tests/ui/print_type_sizes/niche-filling.stdout @@ -70,6 +70,10 @@ print-type-size field `.a`: 4 bytes print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes print-type-size type: `std::num::NonZero`: 4 bytes, alignment: 4 bytes print-type-size field `.0`: 4 bytes +print-type-size type: `std::option::Option>`: 4 bytes, alignment: 4 bytes +print-type-size variant `Some`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size variant `None`: 0 bytes print-type-size type: `Enum4<(), (), (), MyOption>`: 2 bytes, alignment: 1 bytes print-type-size variant `Four`: 2 bytes print-type-size field `.0`: 2 bytes