Skip to content

Commit 2d48a3a

Browse files
committed
Move generic NonZero rustc_layout_scalar_valid_range_start attribute to inner type.
1 parent 3521a2f commit 2d48a3a

File tree

8 files changed

+269
-86
lines changed

8 files changed

+269
-86
lines changed

library/core/src/num/nonzero.rs

Lines changed: 76 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,12 @@ use crate::hash::{Hash, Hasher};
66
use crate::intrinsics;
77
use crate::marker::StructuralPartialEq;
88
use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem};
9+
use crate::ptr;
910
use crate::str::FromStr;
1011

1112
use super::from_str_radix;
1213
use super::{IntErrorKind, ParseIntError};
1314

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-
2415
/// A marker trait for primitive types which can be zero.
2516
///
2617
/// This is an implementation detail for <code>[NonZero]\<T></code> which may disappear or be replaced at any time.
@@ -34,38 +25,70 @@ mod private {
3425
issue = "none"
3526
)]
3627
#[const_trait]
37-
pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed {}
28+
pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed {
29+
#[doc(hidden)]
30+
type NonZeroInner: Sized + Copy;
31+
}
3832

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

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);
78+
impl_zeroable_primitive!(
79+
NonZeroU8Inner(u8),
80+
NonZeroU16Inner(u16),
81+
NonZeroU32Inner(u32),
82+
NonZeroU64Inner(u64),
83+
NonZeroU128Inner(u128),
84+
NonZeroUsizeInner(usize),
85+
NonZeroI8Inner(i8),
86+
NonZeroI16Inner(i16),
87+
NonZeroI32Inner(i32),
88+
NonZeroI64Inner(i64),
89+
NonZeroI128Inner(i128),
90+
NonZeroIsizeInner(isize),
91+
);
6992

7093
/// A value that is known not to equal zero.
7194
///
@@ -80,10 +103,8 @@ impl_zeroable_primitive!(isize);
80103
/// ```
81104
#[unstable(feature = "generic_nonzero", issue = "120257")]
82105
#[repr(transparent)]
83-
#[rustc_layout_scalar_valid_range_start(1)]
84-
#[rustc_nonnull_optimization_guaranteed]
85106
#[rustc_diagnostic_item = "NonZero"]
86-
pub struct NonZero<T: ZeroablePrimitive>(T);
107+
pub struct NonZero<T: ZeroablePrimitive>(T::NonZeroInner);
87108

88109
macro_rules! impl_nonzero_fmt {
89110
($Trait:ident) => {
@@ -114,8 +135,7 @@ where
114135
{
115136
#[inline]
116137
fn clone(&self) -> Self {
117-
// SAFETY: The contained value is non-zero.
118-
unsafe { Self(self.0) }
138+
Self(self.0)
119139
}
120140
}
121141

@@ -188,19 +208,19 @@ where
188208
#[inline]
189209
fn max(self, other: Self) -> Self {
190210
// SAFETY: The maximum of two non-zero values is still non-zero.
191-
unsafe { Self(self.get().max(other.get())) }
211+
unsafe { Self::new_unchecked(self.get().max(other.get())) }
192212
}
193213

194214
#[inline]
195215
fn min(self, other: Self) -> Self {
196216
// SAFETY: The minimum of two non-zero values is still non-zero.
197-
unsafe { Self(self.get().min(other.get())) }
217+
unsafe { Self::new_unchecked(self.get().min(other.get())) }
198218
}
199219

200220
#[inline]
201221
fn clamp(self, min: Self, max: Self) -> Self {
202222
// 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())) }
223+
unsafe { Self::new_unchecked(self.get().clamp(min.get(), max.get())) }
204224
}
205225
}
206226

@@ -240,7 +260,7 @@ where
240260
#[inline]
241261
fn bitor(self, rhs: Self) -> Self::Output {
242262
// SAFETY: Bitwise OR of two non-zero values is still non-zero.
243-
unsafe { Self(self.get() | rhs.get()) }
263+
unsafe { Self::new_unchecked(self.get() | rhs.get()) }
244264
}
245265
}
246266

@@ -254,7 +274,7 @@ where
254274
#[inline]
255275
fn bitor(self, rhs: T) -> Self::Output {
256276
// SAFETY: Bitwise OR of a non-zero value with anything is still non-zero.
257-
unsafe { Self(self.get() | rhs) }
277+
unsafe { Self::new_unchecked(self.get() | rhs) }
258278
}
259279
}
260280

@@ -268,7 +288,7 @@ where
268288
#[inline]
269289
fn bitor(self, rhs: NonZero<T>) -> Self::Output {
270290
// SAFETY: Bitwise OR of anything with a non-zero value is still non-zero.
271-
unsafe { NonZero(self | rhs.get()) }
291+
unsafe { NonZero::new_unchecked(self | rhs.get()) }
272292
}
273293
}
274294

@@ -346,7 +366,7 @@ where
346366
pub fn from_mut(n: &mut T) -> Option<&mut Self> {
347367
// SAFETY: Memory layout optimization guarantees that `Option<NonZero<T>>` has
348368
// 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>) };
369+
let opt_n = unsafe { &mut *(ptr::from_mut(n).cast::<Option<Self>>()) };
350370

351371
opt_n.as_mut()
352372
}
@@ -390,12 +410,17 @@ where
390410
// memory somewhere. If the value of `self` was from by-value argument
391411
// of some not-inlined function, LLVM don't have range metadata
392412
// to understand that the value cannot be zero.
393-
match Self::new(self.0) {
394-
Some(Self(n)) => n,
413+
//
414+
// SAFETY: `Self` is guaranteed to have the same layout as `Option<Self>`.
415+
match unsafe { intrinsics::transmute_unchecked(self) } {
395416
None => {
396417
// SAFETY: `NonZero` is guaranteed to only contain non-zero values, so this is unreachable.
397418
unsafe { intrinsics::unreachable() }
398419
}
420+
Some(Self(inner)) => {
421+
// SAFETY: `T::NonZeroInner` is guaranteed to have the same layout as `T`.
422+
unsafe { intrinsics::transmute_unchecked(inner) }
423+
}
399424
}
400425
}
401426
}

tests/ui/consts/const-eval/raw-bytes.32bit.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value
6868
--> $DIR/raw-bytes.rs:59:1
6969
|
7070
LL | const NULL_U8: NonZero<u8> = unsafe { mem::transmute(0u8) };
71-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
71+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
7272
|
7373
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
7474
= note: the raw bytes of the constant (size: 1, align: 1) {
@@ -79,7 +79,7 @@ error[E0080]: it is undefined behavior to use this value
7979
--> $DIR/raw-bytes.rs:61:1
8080
|
8181
LL | const NULL_USIZE: NonZero<usize> = unsafe { mem::transmute(0usize) };
82-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
82+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
8383
|
8484
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
8585
= note: the raw bytes of the constant (size: 4, align: 4) {

tests/ui/consts/const-eval/raw-bytes.64bit.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value
6868
--> $DIR/raw-bytes.rs:59:1
6969
|
7070
LL | const NULL_U8: NonZero<u8> = unsafe { mem::transmute(0u8) };
71-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
71+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
7272
|
7373
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
7474
= note: the raw bytes of the constant (size: 1, align: 1) {
@@ -79,7 +79,7 @@ error[E0080]: it is undefined behavior to use this value
7979
--> $DIR/raw-bytes.rs:61:1
8080
|
8181
LL | const NULL_USIZE: NonZero<usize> = unsafe { mem::transmute(0usize) };
82-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
82+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
8383
|
8484
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
8585
= note: the raw bytes of the constant (size: 8, align: 8) {

tests/ui/consts/const-eval/ub-nonnull.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ error[E0080]: it is undefined behavior to use this value
1919
--> $DIR/ub-nonnull.rs:24:1
2020
|
2121
LL | const NULL_U8: NonZero<u8> = unsafe { mem::transmute(0u8) };
22-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
2323
|
2424
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
2525
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
@@ -30,7 +30,7 @@ error[E0080]: it is undefined behavior to use this value
3030
--> $DIR/ub-nonnull.rs:26:1
3131
|
3232
LL | const NULL_USIZE: NonZero<usize> = unsafe { mem::transmute(0usize) };
33-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
33+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
3434
|
3535
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
3636
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {

tests/ui/lint/clashing-extern-fn.stderr

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,31 @@
1+
warning: `extern` block uses type `Option<NonZero<usize>>`, which is not FFI-safe
2+
--> $DIR/clashing-extern-fn.rs:369:43
3+
|
4+
LL | fn option_non_zero_usize() -> Option<core::num::NonZero<usize>>;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
6+
|
7+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
8+
= note: enum has no representation hint
9+
= note: `#[warn(improper_ctypes)]` on by default
10+
11+
warning: `extern` block uses type `Option<NonZero<isize>>`, which is not FFI-safe
12+
--> $DIR/clashing-extern-fn.rs:370:43
13+
|
14+
LL | fn option_non_zero_isize() -> Option<core::num::NonZero<isize>>;
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
16+
|
17+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
18+
= note: enum has no representation hint
19+
20+
warning: `extern` block uses type `Option<Transparent>`, which is not FFI-safe
21+
--> $DIR/clashing-extern-fn.rs:428:46
22+
|
23+
LL | fn hidden_niche_transparent() -> Option<Transparent>;
24+
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
25+
|
26+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
27+
= note: enum has no representation hint
28+
129
warning: `extern` block uses type `Option<TransparentNoNiche>`, which is not FFI-safe
230
--> $DIR/clashing-extern-fn.rs:430:55
331
|
@@ -6,7 +34,6 @@ LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN
634
|
735
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
836
= note: enum has no representation hint
9-
= note: `#[warn(improper_ctypes)]` on by default
1037

1138
warning: `extern` block uses type `Option<UnsafeCell<NonZero<usize>>>`, which is not FFI-safe
1239
--> $DIR/clashing-extern-fn.rs:434:46
@@ -178,6 +205,30 @@ LL | fn non_null_ptr() -> *const usize;
178205
= note: expected `unsafe extern "C" fn() -> NonNull<usize>`
179206
found `unsafe extern "C" fn() -> *const usize`
180207

208+
warning: `option_non_zero_usize` redeclared with a different signature
209+
--> $DIR/clashing-extern-fn.rs:369:13
210+
|
211+
LL | fn option_non_zero_usize() -> usize;
212+
| ----------------------------------- `option_non_zero_usize` previously declared here
213+
...
214+
LL | fn option_non_zero_usize() -> Option<core::num::NonZero<usize>>;
215+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
216+
|
217+
= note: expected `unsafe extern "C" fn() -> usize`
218+
found `unsafe extern "C" fn() -> Option<NonZero<usize>>`
219+
220+
warning: `option_non_zero_isize` redeclared with a different signature
221+
--> $DIR/clashing-extern-fn.rs:370:13
222+
|
223+
LL | fn option_non_zero_isize() -> isize;
224+
| ----------------------------------- `option_non_zero_isize` previously declared here
225+
...
226+
LL | fn option_non_zero_isize() -> Option<core::num::NonZero<isize>>;
227+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
228+
|
229+
= note: expected `unsafe extern "C" fn() -> isize`
230+
found `unsafe extern "C" fn() -> Option<NonZero<isize>>`
231+
181232
warning: `option_non_zero_usize_incorrect` redeclared with a different signature
182233
--> $DIR/clashing-extern-fn.rs:374:13
183234
|
@@ -202,6 +253,18 @@ LL | fn option_non_null_ptr_incorrect() -> *const isize;
202253
= note: expected `unsafe extern "C" fn() -> *const usize`
203254
found `unsafe extern "C" fn() -> *const isize`
204255

256+
warning: `hidden_niche_transparent` redeclared with a different signature
257+
--> $DIR/clashing-extern-fn.rs:428:13
258+
|
259+
LL | fn hidden_niche_transparent() -> usize;
260+
| -------------------------------------- `hidden_niche_transparent` previously declared here
261+
...
262+
LL | fn hidden_niche_transparent() -> Option<Transparent>;
263+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
264+
|
265+
= note: expected `unsafe extern "C" fn() -> usize`
266+
found `unsafe extern "C" fn() -> Option<Transparent>`
267+
205268
warning: `hidden_niche_transparent_no_niche` redeclared with a different signature
206269
--> $DIR/clashing-extern-fn.rs:430:13
207270
|
@@ -226,5 +289,5 @@ LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZero<usiz
226289
= note: expected `unsafe extern "C" fn() -> usize`
227290
found `unsafe extern "C" fn() -> Option<UnsafeCell<NonZero<usize>>>`
228291

229-
warning: 19 warnings emitted
292+
warning: 25 warnings emitted
230293

0 commit comments

Comments
 (0)