Auto merge of #120521 - reitermarkus:generic-nonzero-constructors, r=dtolnay
Make `NonZero` constructors generic. This makes `NonZero` constructors generic, so that `NonZero::new` can be used without turbofish syntax. Tracking issue: https://github.com/rust-lang/rust/issues/120257 ~~I cannot figure out how to make this work with `const` traits. Not sure if I'm using it wrong or whether there's a bug:~~ ```rust 101 | if n == T::ZERO { | ^^^^^^^^^^^^ expected `host`, found `true` | = note: expected constant `host` found constant `true` ``` r? `@dtolnay`
This commit is contained in:
commit
384b02c082
@ -3,15 +3,16 @@
|
||||
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;
|
||||
use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem};
|
||||
use crate::ptr;
|
||||
use crate::str::FromStr;
|
||||
|
||||
use super::from_str_radix;
|
||||
use super::{IntErrorKind, ParseIntError};
|
||||
use crate::intrinsics;
|
||||
|
||||
mod private {
|
||||
#[unstable(
|
||||
@ -35,7 +36,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 +53,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.
|
||||
///
|
||||
@ -83,6 +84,88 @@ impl_zeroable_primitive!(NonZeroIsize(isize));
|
||||
#[rustc_diagnostic_item = "NonZero"]
|
||||
pub struct NonZero<T: ZeroablePrimitive>(T);
|
||||
|
||||
impl<T> NonZero<T>
|
||||
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<Self> {
|
||||
// SAFETY: Memory layout optimization guarantees that `Option<NonZero<T>>` has
|
||||
// the same layout and size as `T`, with `0` representing `None`.
|
||||
unsafe { ptr::read(ptr::addr_of!(n).cast()) }
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
intrinsics::assert_unsafe_precondition!(
|
||||
"NonZero::new_unchecked requires the argument to be non-zero",
|
||||
() => false,
|
||||
);
|
||||
intrinsics::unreachable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<NonZero<T>>` has
|
||||
// the same layout and size as `T`, with `0` representing `None`.
|
||||
let opt_n = unsafe { &mut *(n as *mut T as *mut Option<Self>) };
|
||||
|
||||
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 {
|
||||
intrinsics::assert_unsafe_precondition!(
|
||||
"NonZero::from_mut_unchecked requires the argument to dereference as non-zero",
|
||||
() => false,
|
||||
);
|
||||
intrinsics::unreachable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_nonzero_fmt {
|
||||
( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
|
||||
$(
|
||||
@ -100,7 +183,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 +225,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<Self> {
|
||||
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 +738,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 +748,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)*
|
||||
@ -757,7 +769,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()) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -770,7 +782,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()) }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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.
|
||||
|
@ -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<u32>`: 4 bytes, alignment: 4 bytes
|
||||
print-type-size field `.0`: 4 bytes
|
||||
print-type-size type: `std::option::Option<std::num::NonZero<u32>>`: 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<u8>>`: 2 bytes, alignment: 1 bytes
|
||||
print-type-size variant `Four`: 2 bytes
|
||||
print-type-size field `.0`: 2 bytes
|
||||
|
Loading…
x
Reference in New Issue
Block a user