Skip to content

Commit 0002b8c

Browse files
authored
Rollup merge of rust-lang#120521 - reitermarkus:generic-nonzero-constructors, r=dtolnay,oli-obk
Make `NonZero` constructors generic. This makes `NonZero` constructors generic, so that `NonZero::new` can be used without turbofish syntax. Tracking issue: rust-lang#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`
2 parents 5efee4a + aa3f1a2 commit 0002b8c

File tree

2 files changed

+140
-84
lines changed

2 files changed

+140
-84
lines changed

library/core/src/num/nonzero.rs

+97-84
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ mod private {
3535
pub trait ZeroablePrimitive: Sized + Copy + private::Sealed {}
3636

3737
macro_rules! impl_zeroable_primitive {
38-
($NonZero:ident ( $primitive:ty )) => {
38+
($primitive:ty) => {
3939
#[unstable(
4040
feature = "nonzero_internals",
4141
reason = "implementation detail which may disappear or be replaced at any time",
@@ -52,18 +52,18 @@ macro_rules! impl_zeroable_primitive {
5252
};
5353
}
5454

55-
impl_zeroable_primitive!(NonZeroU8(u8));
56-
impl_zeroable_primitive!(NonZeroU16(u16));
57-
impl_zeroable_primitive!(NonZeroU32(u32));
58-
impl_zeroable_primitive!(NonZeroU64(u64));
59-
impl_zeroable_primitive!(NonZeroU128(u128));
60-
impl_zeroable_primitive!(NonZeroUsize(usize));
61-
impl_zeroable_primitive!(NonZeroI8(i8));
62-
impl_zeroable_primitive!(NonZeroI16(i16));
63-
impl_zeroable_primitive!(NonZeroI32(i32));
64-
impl_zeroable_primitive!(NonZeroI64(i64));
65-
impl_zeroable_primitive!(NonZeroI128(i128));
66-
impl_zeroable_primitive!(NonZeroIsize(isize));
55+
impl_zeroable_primitive!(u8);
56+
impl_zeroable_primitive!(u16);
57+
impl_zeroable_primitive!(u32);
58+
impl_zeroable_primitive!(u64);
59+
impl_zeroable_primitive!(u128);
60+
impl_zeroable_primitive!(usize);
61+
impl_zeroable_primitive!(i8);
62+
impl_zeroable_primitive!(i16);
63+
impl_zeroable_primitive!(i32);
64+
impl_zeroable_primitive!(i64);
65+
impl_zeroable_primitive!(i128);
66+
impl_zeroable_primitive!(isize);
6767

6868
/// A value that is known not to equal zero.
6969
///
@@ -83,6 +83,90 @@ impl_zeroable_primitive!(NonZeroIsize(isize));
8383
#[rustc_diagnostic_item = "NonZero"]
8484
pub struct NonZero<T: ZeroablePrimitive>(T);
8585

86+
impl<T> NonZero<T>
87+
where
88+
T: ZeroablePrimitive,
89+
{
90+
/// Creates a non-zero if the given value is not zero.
91+
#[stable(feature = "nonzero", since = "1.28.0")]
92+
#[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")]
93+
#[rustc_allow_const_fn_unstable(const_refs_to_cell)]
94+
#[must_use]
95+
#[inline]
96+
pub const fn new(n: T) -> Option<Self> {
97+
// SAFETY: Memory layout optimization guarantees that `Option<NonZero<T>>` has
98+
// the same layout and size as `T`, with `0` representing `None`.
99+
unsafe { crate::mem::transmute_copy(&n) }
100+
}
101+
102+
/// Creates a non-zero without checking whether the value is non-zero.
103+
/// This results in undefined behaviour if the value is zero.
104+
///
105+
/// # Safety
106+
///
107+
/// The value must not be zero.
108+
#[stable(feature = "nonzero", since = "1.28.0")]
109+
#[rustc_const_stable(feature = "nonzero", since = "1.28.0")]
110+
#[must_use]
111+
#[inline]
112+
pub const unsafe fn new_unchecked(n: T) -> Self {
113+
match Self::new(n) {
114+
Some(n) => n,
115+
None => {
116+
// SAFETY: The caller guarantees that `n` is non-zero, so this is unreachable.
117+
unsafe {
118+
crate::intrinsics::assert_unsafe_precondition!(
119+
"NonZero::new_unchecked requires the argument to be non-zero",
120+
() => false
121+
);
122+
123+
crate::hint::unreachable_unchecked()
124+
}
125+
}
126+
}
127+
}
128+
129+
/// Converts a reference to a non-zero mutable reference
130+
/// if the referenced value is not zero.
131+
#[unstable(feature = "nonzero_from_mut", issue = "106290")]
132+
#[must_use]
133+
#[inline]
134+
pub fn from_mut(n: &mut T) -> Option<&mut Self> {
135+
// SAFETY: Memory layout optimization guarantees that `Option<NonZero<T>>` has
136+
// the same layout and size as `T`, with `0` representing `None`.
137+
let opt_n = unsafe { &mut *(n as *mut T as *mut Option<Self>) };
138+
139+
opt_n.as_mut()
140+
}
141+
142+
/// Converts a mutable reference to a non-zero mutable reference
143+
/// without checking whether the referenced value is non-zero.
144+
/// This results in undefined behavior if the referenced value is zero.
145+
///
146+
/// # Safety
147+
///
148+
/// The referenced value must not be zero.
149+
#[unstable(feature = "nonzero_from_mut", issue = "106290")]
150+
#[must_use]
151+
#[inline]
152+
pub unsafe fn from_mut_unchecked(n: &mut T) -> &mut Self {
153+
match Self::from_mut(n) {
154+
Some(n) => n,
155+
None => {
156+
// SAFETY: The caller guarantees that `n` references a value that is non-zero, so this is unreachable.
157+
unsafe {
158+
crate::intrinsics::assert_unsafe_precondition!(
159+
"NonZero::from_mut_unchecked requires the argument to dereference as non-zero",
160+
() => false
161+
);
162+
163+
crate::hint::unreachable_unchecked()
164+
}
165+
}
166+
}
167+
}
168+
}
169+
86170
macro_rules! impl_nonzero_fmt {
87171
( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
88172
$(
@@ -100,7 +184,6 @@ macro_rules! impl_nonzero_fmt {
100184
macro_rules! nonzero_integer {
101185
(
102186
#[$stability:meta]
103-
#[$const_new_unchecked_stability:meta]
104187
Self = $Ty:ident,
105188
Primitive = $signedness:ident $Int:ident,
106189
$(UnsignedNonZero = $UnsignedNonZero:ident,)?
@@ -143,74 +226,6 @@ macro_rules! nonzero_integer {
143226
pub type $Ty = NonZero<$Int>;
144227

145228
impl $Ty {
146-
/// Creates a non-zero without checking whether the value is non-zero.
147-
/// This results in undefined behaviour if the value is zero.
148-
///
149-
/// # Safety
150-
///
151-
/// The value must not be zero.
152-
#[$stability]
153-
#[$const_new_unchecked_stability]
154-
#[must_use]
155-
#[inline]
156-
pub const unsafe fn new_unchecked(n: $Int) -> Self {
157-
crate::panic::debug_assert_nounwind!(
158-
n != 0,
159-
concat!(stringify!($Ty), "::new_unchecked requires a non-zero argument")
160-
);
161-
// SAFETY: this is guaranteed to be safe by the caller.
162-
unsafe {
163-
Self(n)
164-
}
165-
}
166-
167-
/// Creates a non-zero if the given value is not zero.
168-
#[$stability]
169-
#[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")]
170-
#[must_use]
171-
#[inline]
172-
pub const fn new(n: $Int) -> Option<Self> {
173-
if n != 0 {
174-
// SAFETY: we just checked that there's no `0`
175-
Some(unsafe { Self(n) })
176-
} else {
177-
None
178-
}
179-
}
180-
181-
/// Converts a primitive mutable reference to a non-zero mutable reference
182-
/// without checking whether the referenced value is non-zero.
183-
/// This results in undefined behavior if `*n` is zero.
184-
///
185-
/// # Safety
186-
/// The referenced value must not be currently zero.
187-
#[unstable(feature = "nonzero_from_mut", issue = "106290")]
188-
#[must_use]
189-
#[inline]
190-
pub unsafe fn from_mut_unchecked(n: &mut $Int) -> &mut Self {
191-
// SAFETY: Self is repr(transparent), and the value is assumed to be non-zero.
192-
unsafe {
193-
let n_alias = &mut *n;
194-
core::intrinsics::assert_unsafe_precondition!(
195-
concat!(stringify!($Ty), "::from_mut_unchecked requires the argument to dereference as non-zero"),
196-
(n_alias: &mut $Int) => *n_alias != 0
197-
);
198-
&mut *(n as *mut $Int as *mut Self)
199-
}
200-
}
201-
202-
/// Converts a primitive mutable reference to a non-zero mutable reference
203-
/// if the referenced integer is not zero.
204-
#[unstable(feature = "nonzero_from_mut", issue = "106290")]
205-
#[must_use]
206-
#[inline]
207-
pub fn from_mut(n: &mut $Int) -> Option<&mut Self> {
208-
// SAFETY: Self is repr(transparent), and the value is non-zero.
209-
// As long as the returned reference is alive,
210-
// the user cannot `*n = 0` directly.
211-
(*n != 0).then(|| unsafe { &mut *(n as *mut $Int as *mut Self) })
212-
}
213-
214229
/// Returns the value as a primitive type.
215230
#[$stability]
216231
#[inline]
@@ -724,7 +739,6 @@ macro_rules! nonzero_integer {
724739
(Self = $Ty:ident, Primitive = unsigned $Int:ident $(,)?) => {
725740
nonzero_integer! {
726741
#[stable(feature = "nonzero", since = "1.28.0")]
727-
#[rustc_const_stable(feature = "nonzero", since = "1.28.0")]
728742
Self = $Ty,
729743
Primitive = unsigned $Int,
730744
UnsignedPrimitive = $Int,
@@ -735,7 +749,6 @@ macro_rules! nonzero_integer {
735749
(Self = $Ty:ident, Primitive = signed $Int:ident, $($rest:tt)*) => {
736750
nonzero_integer! {
737751
#[stable(feature = "signed_nonzero", since = "1.34.0")]
738-
#[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")]
739752
Self = $Ty,
740753
Primitive = signed $Int,
741754
$($rest)*

tests/ui/print_type_sizes/niche-filling.stdout

+43
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,30 @@
1+
print-type-size type: `core::fmt::rt::Placeholder`: 56 bytes, alignment: 8 bytes
2+
print-type-size field `.precision`: 16 bytes
3+
print-type-size field `.width`: 16 bytes
4+
print-type-size field `.position`: 8 bytes
5+
print-type-size field `.fill`: 4 bytes
6+
print-type-size field `.flags`: 4 bytes
7+
print-type-size field `.align`: 1 bytes
8+
print-type-size end padding: 7 bytes
9+
print-type-size type: `std::fmt::Arguments<'_>`: 48 bytes, alignment: 8 bytes
10+
print-type-size field `.pieces`: 16 bytes
11+
print-type-size field `.args`: 16 bytes
12+
print-type-size field `.fmt`: 16 bytes
13+
print-type-size type: `std::panic::Location<'_>`: 24 bytes, alignment: 8 bytes
14+
print-type-size field `.file`: 16 bytes
15+
print-type-size field `.line`: 4 bytes
16+
print-type-size field `.col`: 4 bytes
17+
print-type-size type: `core::fmt::rt::Count`: 16 bytes, alignment: 8 bytes
18+
print-type-size discriminant: 8 bytes
19+
print-type-size variant `Is`: 8 bytes
20+
print-type-size field `.0`: 8 bytes
21+
print-type-size variant `Param`: 8 bytes
22+
print-type-size field `.0`: 8 bytes
23+
print-type-size variant `Implied`: 0 bytes
24+
print-type-size type: `std::option::Option<&[core::fmt::rt::Placeholder]>`: 16 bytes, alignment: 8 bytes
25+
print-type-size variant `Some`: 16 bytes
26+
print-type-size field `.0`: 16 bytes
27+
print-type-size variant `None`: 0 bytes
128
print-type-size type: `IndirectNonZero`: 12 bytes, alignment: 4 bytes
229
print-type-size field `.nested`: 8 bytes
330
print-type-size field `.post`: 2 bytes
@@ -68,8 +95,18 @@ print-type-size type: `Union2<std::num::NonZero<u32>, u32>`: 4 bytes, alignment:
6895
print-type-size variant `Union2`: 4 bytes
6996
print-type-size field `.a`: 4 bytes
7097
print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes
98+
print-type-size type: `std::mem::ManuallyDrop<std::option::Option<std::num::NonZero<u32>>>`: 4 bytes, alignment: 4 bytes
99+
print-type-size field `.value`: 4 bytes
100+
print-type-size type: `std::mem::MaybeUninit<std::option::Option<std::num::NonZero<u32>>>`: 4 bytes, alignment: 4 bytes
101+
print-type-size variant `MaybeUninit`: 4 bytes
102+
print-type-size field `.uninit`: 0 bytes
103+
print-type-size field `.value`: 4 bytes
71104
print-type-size type: `std::num::NonZero<u32>`: 4 bytes, alignment: 4 bytes
72105
print-type-size field `.0`: 4 bytes
106+
print-type-size type: `std::option::Option<std::num::NonZero<u32>>`: 4 bytes, alignment: 4 bytes
107+
print-type-size variant `Some`: 4 bytes
108+
print-type-size field `.0`: 4 bytes
109+
print-type-size variant `None`: 0 bytes
73110
print-type-size type: `Enum4<(), (), (), MyOption<u8>>`: 2 bytes, alignment: 1 bytes
74111
print-type-size variant `Four`: 2 bytes
75112
print-type-size field `.0`: 2 bytes
@@ -105,6 +142,12 @@ print-type-size type: `MyOption<std::cmp::Ordering>`: 1 bytes, alignment: 1 byte
105142
print-type-size variant `Some`: 1 bytes
106143
print-type-size field `.0`: 1 bytes
107144
print-type-size variant `None`: 0 bytes
145+
print-type-size type: `core::fmt::rt::Alignment`: 1 bytes, alignment: 1 bytes
146+
print-type-size discriminant: 1 bytes
147+
print-type-size variant `Left`: 0 bytes
148+
print-type-size variant `Right`: 0 bytes
149+
print-type-size variant `Center`: 0 bytes
150+
print-type-size variant `Unknown`: 0 bytes
108151
print-type-size type: `std::cmp::Ordering`: 1 bytes, alignment: 1 bytes
109152
print-type-size discriminant: 1 bytes
110153
print-type-size variant `Less`: 0 bytes

0 commit comments

Comments
 (0)