From 9aa48304562d83fb1333beb729bcbedcfe9c742d Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 20 Jan 2024 15:11:53 +0100 Subject: [PATCH] Manually implement derived `NonZero` traits. --- library/core/src/num/nonzero.rs | 182 ++++++++++++++++++++++++-- tests/ui/unsafe/ranged_ints3.rs | 1 + tests/ui/unsafe/ranged_ints3_match.rs | 1 + 3 files changed, 176 insertions(+), 8 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index bda691b16d4a7..29585670a29c4 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1,6 +1,9 @@ //! Definitions of integer that is known not to equal zero. +use crate::cmp::Ordering; use crate::fmt; +use crate::hash::{Hash, Hasher}; +use crate::marker::StructuralPartialEq; use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem}; use crate::str::FromStr; @@ -31,13 +34,6 @@ pub trait ZeroablePrimitive: Sized + Copy + private::Sealed { type NonZero; } -#[unstable( - feature = "nonzero_internals", - reason = "implementation detail which may disappear or be replaced at any time", - issue = "none" -)] -pub(crate) type NonZero = ::NonZero; - macro_rules! impl_zeroable_primitive { ($NonZero:ident ( $primitive:ty )) => { #[unstable( @@ -71,6 +67,174 @@ impl_zeroable_primitive!(NonZeroI64(i64)); impl_zeroable_primitive!(NonZeroI128(i128)); impl_zeroable_primitive!(NonZeroIsize(isize)); +/// A value that is known not to equal zero. +/// +/// This enables some memory layout optimization. +/// For example, `Option>` is the same size as `u32`: +/// +/// ```rust +/// #![feature(generic_nonzero)] +/// +/// use core::mem::size_of; +/// assert_eq!(size_of::>>(), size_of::()); +/// ``` +#[unstable(feature = "generic_nonzero", issue = "82363")] +#[derive(Clone, Copy)] +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(1)] +#[rustc_nonnull_optimization_guaranteed] +#[rustc_diagnostic_item = "NonZero"] +pub struct NonZero2(T); + +#[unstable( + feature = "nonzero_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" +)] +pub(crate) type NonZero = ::NonZero; + +macro_rules! impl_nonzero_traits { + (#[$stability:meta] $Ty:ty) => { + #[$stability] + impl Clone for $Ty { + #[inline] + fn clone(&self) -> Self { + #[allow(unused_unsafe)] + // SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values. + unsafe { + Self(self.0) + } + } + } + + #[$stability] + impl PartialEq for $Ty { + #[inline] + fn eq(&self, other: &Self) -> bool { + #[allow(unused_unsafe)] + // SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values. + unsafe { + self.0 == other.0 + } + } + + #[inline] + fn ne(&self, other: &Self) -> bool { + #[allow(unused_unsafe)] + // SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values. + unsafe { + self.0 != other.0 + } + } + } + + #[$stability] + #[rustc_const_unstable(feature = "const_ops", issue = "90080")] + impl StructuralPartialEq for $Ty {} + + #[$stability] + impl PartialOrd for $Ty { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + #[allow(unused_unsafe)] + // SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values. + unsafe { + self.0.partial_cmp(&other.0) + } + } + + #[inline] + fn lt(&self, other: &Self) -> bool { + #[allow(unused_unsafe)] + // SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values. + unsafe { + self.0 < other.0 + } + } + + #[inline] + fn le(&self, other: &Self) -> bool { + #[allow(unused_unsafe)] + // SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values. + unsafe { + self.0 <= other.0 + } + } + + #[inline] + fn gt(&self, other: &Self) -> bool { + #[allow(unused_unsafe)] + // SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values. + unsafe { + self.0 > other.0 + } + } + + #[inline] + fn ge(&self, other: &Self) -> bool { + #[allow(unused_unsafe)] + // SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values. + unsafe { + self.0 >= other.0 + } + } + } + + #[$stability] + impl Ord for $Ty { + fn cmp(&self, other: &Self) -> Ordering { + #[allow(unused_unsafe)] + // SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values. + unsafe { + self.0.cmp(&other.0) + } + } + + fn max(self, other: Self) -> Self { + #[allow(unused_unsafe)] + // SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values, + // and the maximum of two non-zero values is still non-zero. + unsafe { + Self(self.0.max(other.0)) + } + } + + fn min(self, other: Self) -> Self { + #[allow(unused_unsafe)] + // SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values, + // and the minimum of two non-zero values is still non-zero. + unsafe { + Self(self.0.min(other.0)) + } + } + + fn clamp(self, min: Self, max: Self) -> Self { + #[allow(unused_unsafe)] + // SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values, and + // a non-zero value clamped between two non-zero values is still non-zero. + unsafe { + Self(self.0.clamp(min.0, max.0)) + } + } + } + + #[$stability] + impl Hash for $Ty { + #[inline] + fn hash(&self, state: &mut H) + where + H: Hasher, + { + // SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values. + #[allow(unused_unsafe)] + unsafe { + self.0.hash(state) + } + } + } + }; +} + macro_rules! impl_nonzero_fmt { ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { $( @@ -128,13 +292,15 @@ macro_rules! nonzero_integer { /// /// [null pointer optimization]: crate::option#representation #[$stability] - #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] + #[derive(Copy, Eq)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(1)] #[rustc_nonnull_optimization_guaranteed] #[rustc_diagnostic_item = stringify!($Ty)] pub struct $Ty($Int); + impl_nonzero_traits!(#[$stability] $Ty); + impl $Ty { /// Creates a non-zero without checking whether the value is non-zero. /// This results in undefined behaviour if the value is zero. diff --git a/tests/ui/unsafe/ranged_ints3.rs b/tests/ui/unsafe/ranged_ints3.rs index 47d67fac6785c..0e7a523e5c59b 100644 --- a/tests/ui/unsafe/ranged_ints3.rs +++ b/tests/ui/unsafe/ranged_ints3.rs @@ -5,6 +5,7 @@ use std::cell::Cell; #[rustc_layout_scalar_valid_range_start(1)] #[repr(transparent)] pub(crate) struct NonZero(pub(crate) T); + fn main() { let mut x = unsafe { NonZero(Cell::new(1)) }; let y = &x.0; //~ ERROR borrow of layout constrained field with interior mutability diff --git a/tests/ui/unsafe/ranged_ints3_match.rs b/tests/ui/unsafe/ranged_ints3_match.rs index de6be506d5611..8c0cefacfaed5 100644 --- a/tests/ui/unsafe/ranged_ints3_match.rs +++ b/tests/ui/unsafe/ranged_ints3_match.rs @@ -5,6 +5,7 @@ use std::cell::Cell; #[rustc_layout_scalar_valid_range_start(1)] #[repr(transparent)] pub(crate) struct NonZero(pub(crate) T); + fn main() { let mut x = unsafe { NonZero(Cell::new(1)) }; match x {