Skip to content

Commit 19443a7

Browse files
committed
Auto merge of rust-lang#121885 - reitermarkus:generic-nonzero-inner, r=oli-obk,wesleywiser
Move generic `NonZero` `rustc_layout_scalar_valid_range_start` attribute to inner type. Tracking issue: rust-lang#120257 r? `@dtolnay`
2 parents 13ea67e + 50ef240 commit 19443a7

File tree

1 file changed

+98
-51
lines changed

1 file changed

+98
-51
lines changed

core/src/num/nonzero.rs

Lines changed: 98 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,15 @@ use crate::cmp::Ordering;
44
use crate::fmt;
55
use crate::hash::{Hash, Hasher};
66
use crate::intrinsics;
7-
use crate::marker::StructuralPartialEq;
7+
use crate::marker::{Freeze, StructuralPartialEq};
88
use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem};
9+
use crate::panic::{RefUnwindSafe, UnwindSafe};
10+
use crate::ptr;
911
use crate::str::FromStr;
1012

1113
use super::from_str_radix;
1214
use super::{IntErrorKind, ParseIntError};
1315

14-
mod private {
15-
#[unstable(
16-
feature = "nonzero_internals",
17-
reason = "implementation detail which may disappear or be replaced at any time",
18-
issue = "none"
19-
)]
20-
#[const_trait]
21-
pub trait Sealed {}
22-
}
23-
2416
/// A marker trait for primitive types which can be zero.
2517
///
2618
/// This is an implementation detail for <code>[NonZero]\<T></code> which may disappear or be replaced at any time.
@@ -34,38 +26,70 @@ mod private {
3426
issue = "none"
3527
)]
3628
#[const_trait]
37-
pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed {}
29+
pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed {
30+
#[doc(hidden)]
31+
type NonZeroInner: Sized + Copy;
32+
}
3833

3934
macro_rules! impl_zeroable_primitive {
40-
($primitive:ty) => {
41-
#[unstable(
42-
feature = "nonzero_internals",
43-
reason = "implementation detail which may disappear or be replaced at any time",
44-
issue = "none"
45-
)]
46-
impl const private::Sealed for $primitive {}
47-
48-
#[unstable(
49-
feature = "nonzero_internals",
50-
reason = "implementation detail which may disappear or be replaced at any time",
51-
issue = "none"
52-
)]
53-
unsafe impl const ZeroablePrimitive for $primitive {}
35+
($($NonZeroInner:ident ( $primitive:ty )),+ $(,)?) => {
36+
mod private {
37+
#[unstable(
38+
feature = "nonzero_internals",
39+
reason = "implementation detail which may disappear or be replaced at any time",
40+
issue = "none"
41+
)]
42+
#[const_trait]
43+
pub trait Sealed {}
44+
45+
$(
46+
#[derive(Debug, Clone, Copy, PartialEq)]
47+
#[repr(transparent)]
48+
#[rustc_layout_scalar_valid_range_start(1)]
49+
#[rustc_nonnull_optimization_guaranteed]
50+
#[unstable(
51+
feature = "nonzero_internals",
52+
reason = "implementation detail which may disappear or be replaced at any time",
53+
issue = "none"
54+
)]
55+
pub struct $NonZeroInner($primitive);
56+
)+
57+
}
58+
59+
$(
60+
#[unstable(
61+
feature = "nonzero_internals",
62+
reason = "implementation detail which may disappear or be replaced at any time",
63+
issue = "none"
64+
)]
65+
impl const private::Sealed for $primitive {}
66+
67+
#[unstable(
68+
feature = "nonzero_internals",
69+
reason = "implementation detail which may disappear or be replaced at any time",
70+
issue = "none"
71+
)]
72+
unsafe impl const ZeroablePrimitive for $primitive {
73+
type NonZeroInner = private::$NonZeroInner;
74+
}
75+
)+
5476
};
5577
}
5678

57-
impl_zeroable_primitive!(u8);
58-
impl_zeroable_primitive!(u16);
59-
impl_zeroable_primitive!(u32);
60-
impl_zeroable_primitive!(u64);
61-
impl_zeroable_primitive!(u128);
62-
impl_zeroable_primitive!(usize);
63-
impl_zeroable_primitive!(i8);
64-
impl_zeroable_primitive!(i16);
65-
impl_zeroable_primitive!(i32);
66-
impl_zeroable_primitive!(i64);
67-
impl_zeroable_primitive!(i128);
68-
impl_zeroable_primitive!(isize);
79+
impl_zeroable_primitive!(
80+
NonZeroU8Inner(u8),
81+
NonZeroU16Inner(u16),
82+
NonZeroU32Inner(u32),
83+
NonZeroU64Inner(u64),
84+
NonZeroU128Inner(u128),
85+
NonZeroUsizeInner(usize),
86+
NonZeroI8Inner(i8),
87+
NonZeroI16Inner(i16),
88+
NonZeroI32Inner(i32),
89+
NonZeroI64Inner(i64),
90+
NonZeroI128Inner(i128),
91+
NonZeroIsizeInner(isize),
92+
);
6993

7094
/// A value that is known not to equal zero.
7195
///
@@ -80,10 +104,9 @@ impl_zeroable_primitive!(isize);
80104
/// ```
81105
#[unstable(feature = "generic_nonzero", issue = "120257")]
82106
#[repr(transparent)]
83-
#[rustc_layout_scalar_valid_range_start(1)]
84107
#[rustc_nonnull_optimization_guaranteed]
85108
#[rustc_diagnostic_item = "NonZero"]
86-
pub struct NonZero<T: ZeroablePrimitive>(T);
109+
pub struct NonZero<T: ZeroablePrimitive>(T::NonZeroInner);
87110

88111
macro_rules! impl_nonzero_fmt {
89112
($Trait:ident) => {
@@ -107,15 +130,34 @@ impl_nonzero_fmt!(Octal);
107130
impl_nonzero_fmt!(LowerHex);
108131
impl_nonzero_fmt!(UpperHex);
109132

133+
macro_rules! impl_nonzero_auto_trait {
134+
(unsafe $Trait:ident) => {
135+
#[stable(feature = "nonzero", since = "1.28.0")]
136+
unsafe impl<T> $Trait for NonZero<T> where T: ZeroablePrimitive + $Trait {}
137+
};
138+
($Trait:ident) => {
139+
#[stable(feature = "nonzero", since = "1.28.0")]
140+
impl<T> $Trait for NonZero<T> where T: ZeroablePrimitive + $Trait {}
141+
};
142+
}
143+
144+
// Implement auto-traits manually based on `T` to avoid docs exposing
145+
// the `ZeroablePrimitive::NonZeroInner` implementation detail.
146+
impl_nonzero_auto_trait!(unsafe Freeze);
147+
impl_nonzero_auto_trait!(RefUnwindSafe);
148+
impl_nonzero_auto_trait!(unsafe Send);
149+
impl_nonzero_auto_trait!(unsafe Sync);
150+
impl_nonzero_auto_trait!(Unpin);
151+
impl_nonzero_auto_trait!(UnwindSafe);
152+
110153
#[stable(feature = "nonzero", since = "1.28.0")]
111154
impl<T> Clone for NonZero<T>
112155
where
113156
T: ZeroablePrimitive,
114157
{
115158
#[inline]
116159
fn clone(&self) -> Self {
117-
// SAFETY: The contained value is non-zero.
118-
unsafe { Self(self.0) }
160+
Self(self.0)
119161
}
120162
}
121163

@@ -188,19 +230,19 @@ where
188230
#[inline]
189231
fn max(self, other: Self) -> Self {
190232
// SAFETY: The maximum of two non-zero values is still non-zero.
191-
unsafe { Self(self.get().max(other.get())) }
233+
unsafe { Self::new_unchecked(self.get().max(other.get())) }
192234
}
193235

194236
#[inline]
195237
fn min(self, other: Self) -> Self {
196238
// SAFETY: The minimum of two non-zero values is still non-zero.
197-
unsafe { Self(self.get().min(other.get())) }
239+
unsafe { Self::new_unchecked(self.get().min(other.get())) }
198240
}
199241

200242
#[inline]
201243
fn clamp(self, min: Self, max: Self) -> Self {
202244
// SAFETY: A non-zero value clamped between two non-zero values is still non-zero.
203-
unsafe { Self(self.get().clamp(min.get(), max.get())) }
245+
unsafe { Self::new_unchecked(self.get().clamp(min.get(), max.get())) }
204246
}
205247
}
206248

@@ -240,7 +282,7 @@ where
240282
#[inline]
241283
fn bitor(self, rhs: Self) -> Self::Output {
242284
// SAFETY: Bitwise OR of two non-zero values is still non-zero.
243-
unsafe { Self(self.get() | rhs.get()) }
285+
unsafe { Self::new_unchecked(self.get() | rhs.get()) }
244286
}
245287
}
246288

@@ -254,7 +296,7 @@ where
254296
#[inline]
255297
fn bitor(self, rhs: T) -> Self::Output {
256298
// SAFETY: Bitwise OR of a non-zero value with anything is still non-zero.
257-
unsafe { Self(self.get() | rhs) }
299+
unsafe { Self::new_unchecked(self.get() | rhs) }
258300
}
259301
}
260302

@@ -268,7 +310,7 @@ where
268310
#[inline]
269311
fn bitor(self, rhs: NonZero<T>) -> Self::Output {
270312
// SAFETY: Bitwise OR of anything with a non-zero value is still non-zero.
271-
unsafe { NonZero(self | rhs.get()) }
313+
unsafe { NonZero::new_unchecked(self | rhs.get()) }
272314
}
273315
}
274316

@@ -346,7 +388,7 @@ where
346388
pub fn from_mut(n: &mut T) -> Option<&mut Self> {
347389
// SAFETY: Memory layout optimization guarantees that `Option<NonZero<T>>` has
348390
// the same layout and size as `T`, with `0` representing `None`.
349-
let opt_n = unsafe { &mut *(n as *mut T as *mut Option<Self>) };
391+
let opt_n = unsafe { &mut *(ptr::from_mut(n).cast::<Option<Self>>()) };
350392

351393
opt_n.as_mut()
352394
}
@@ -390,12 +432,17 @@ where
390432
// memory somewhere. If the value of `self` was from by-value argument
391433
// of some not-inlined function, LLVM don't have range metadata
392434
// to understand that the value cannot be zero.
393-
match Self::new(self.0) {
394-
Some(Self(n)) => n,
435+
//
436+
// SAFETY: `Self` is guaranteed to have the same layout as `Option<Self>`.
437+
match unsafe { intrinsics::transmute_unchecked(self) } {
395438
None => {
396439
// SAFETY: `NonZero` is guaranteed to only contain non-zero values, so this is unreachable.
397440
unsafe { intrinsics::unreachable() }
398441
}
442+
Some(Self(inner)) => {
443+
// SAFETY: `T::NonZeroInner` is guaranteed to have the same layout as `T`.
444+
unsafe { intrinsics::transmute_unchecked(inner) }
445+
}
399446
}
400447
}
401448
}

0 commit comments

Comments
 (0)