From 0f55e1b117cab62b9216a0636dadffd14ae77f38 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Wed, 31 Jan 2024 06:06:50 +0100 Subject: [PATCH 1/3] 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 a5042de74199af0ff162b5581ad40e61de0ccd15 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Mon, 22 Jan 2024 18:04:05 +0100 Subject: [PATCH 2/3] 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 aa3f1a290d0f7e6884339ef047cdd49fde3b21f2 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Tue, 6 Feb 2024 09:04:19 +0100 Subject: [PATCH 3/3] Update test output. --- .../ui/print_type_sizes/niche-filling.stdout | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tests/ui/print_type_sizes/niche-filling.stdout b/tests/ui/print_type_sizes/niche-filling.stdout index b53b893660321..44a6835df5152 100644 --- a/tests/ui/print_type_sizes/niche-filling.stdout +++ b/tests/ui/print_type_sizes/niche-filling.stdout @@ -1,3 +1,30 @@ +print-type-size type: `core::fmt::rt::Placeholder`: 56 bytes, alignment: 8 bytes +print-type-size field `.precision`: 16 bytes +print-type-size field `.width`: 16 bytes +print-type-size field `.position`: 8 bytes +print-type-size field `.fill`: 4 bytes +print-type-size field `.flags`: 4 bytes +print-type-size field `.align`: 1 bytes +print-type-size end padding: 7 bytes +print-type-size type: `std::fmt::Arguments<'_>`: 48 bytes, alignment: 8 bytes +print-type-size field `.pieces`: 16 bytes +print-type-size field `.args`: 16 bytes +print-type-size field `.fmt`: 16 bytes +print-type-size type: `std::panic::Location<'_>`: 24 bytes, alignment: 8 bytes +print-type-size field `.file`: 16 bytes +print-type-size field `.line`: 4 bytes +print-type-size field `.col`: 4 bytes +print-type-size type: `core::fmt::rt::Count`: 16 bytes, alignment: 8 bytes +print-type-size discriminant: 8 bytes +print-type-size variant `Is`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `Param`: 8 bytes +print-type-size field `.0`: 8 bytes +print-type-size variant `Implied`: 0 bytes +print-type-size type: `std::option::Option<&[core::fmt::rt::Placeholder]>`: 16 bytes, alignment: 8 bytes +print-type-size variant `Some`: 16 bytes +print-type-size field `.0`: 16 bytes +print-type-size variant `None`: 0 bytes print-type-size type: `IndirectNonZero`: 12 bytes, alignment: 4 bytes print-type-size field `.nested`: 8 bytes print-type-size field `.post`: 2 bytes @@ -68,8 +95,18 @@ print-type-size type: `Union2, u32>`: 4 bytes, alignment: print-type-size variant `Union2`: 4 bytes 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::mem::ManuallyDrop>>`: 4 bytes, alignment: 4 bytes +print-type-size field `.value`: 4 bytes +print-type-size type: `std::mem::MaybeUninit>>`: 4 bytes, alignment: 4 bytes +print-type-size variant `MaybeUninit`: 4 bytes +print-type-size field `.uninit`: 0 bytes +print-type-size field `.value`: 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 @@ -105,6 +142,12 @@ print-type-size type: `MyOption`: 1 bytes, alignment: 1 byte print-type-size variant `Some`: 1 bytes print-type-size field `.0`: 1 bytes print-type-size variant `None`: 0 bytes +print-type-size type: `core::fmt::rt::Alignment`: 1 bytes, alignment: 1 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `Left`: 0 bytes +print-type-size variant `Right`: 0 bytes +print-type-size variant `Center`: 0 bytes +print-type-size variant `Unknown`: 0 bytes print-type-size type: `std::cmp::Ordering`: 1 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Less`: 0 bytes