Skip to content

Commit 5cef608

Browse files
authored
Rollup merge of rust-lang#121885 - reitermarkus:generic-nonzero-inner, r=oli-obk
Move generic `NonZero` `rustc_layout_scalar_valid_range_start` attribute to inner type. Tracking issue: rust-lang#120257 r? ```@dtolnay```
2 parents ce7a19d + a58eb80 commit 5cef608

File tree

9 files changed

+140
-99
lines changed

9 files changed

+140
-99
lines changed

compiler/rustc_lint/src/types.rs

+27-17
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,14 @@ pub fn transparent_newtype_field<'a, 'tcx>(
984984
}
985985

986986
/// Is type known to be non-null?
987-
fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool {
987+
fn ty_is_known_nonnull<'tcx>(
988+
tcx: TyCtxt<'tcx>,
989+
param_env: ty::ParamEnv<'tcx>,
990+
ty: Ty<'tcx>,
991+
mode: CItemKind,
992+
) -> bool {
993+
let ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
994+
988995
match ty.kind() {
989996
ty::FnPtr(_) => true,
990997
ty::Ref(..) => true,
@@ -1004,15 +1011,21 @@ fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -
10041011
def.variants()
10051012
.iter()
10061013
.filter_map(|variant| transparent_newtype_field(tcx, variant))
1007-
.any(|field| ty_is_known_nonnull(tcx, field.ty(tcx, args), mode))
1014+
.any(|field| ty_is_known_nonnull(tcx, param_env, field.ty(tcx, args), mode))
10081015
}
10091016
_ => false,
10101017
}
10111018
}
10121019

10131020
/// Given a non-null scalar (or transparent) type `ty`, return the nullable version of that type.
10141021
/// If the type passed in was not scalar, returns None.
1015-
fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
1022+
fn get_nullable_type<'tcx>(
1023+
tcx: TyCtxt<'tcx>,
1024+
param_env: ty::ParamEnv<'tcx>,
1025+
ty: Ty<'tcx>,
1026+
) -> Option<Ty<'tcx>> {
1027+
let ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
1028+
10161029
Some(match *ty.kind() {
10171030
ty::Adt(field_def, field_args) => {
10181031
let inner_field_ty = {
@@ -1028,22 +1041,19 @@ fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>>
10281041
.expect("No non-zst fields in transparent type.")
10291042
.ty(tcx, field_args)
10301043
};
1031-
return get_nullable_type(tcx, inner_field_ty);
1044+
return get_nullable_type(tcx, param_env, inner_field_ty);
10321045
}
10331046
ty::Int(ty) => Ty::new_int(tcx, ty),
10341047
ty::Uint(ty) => Ty::new_uint(tcx, ty),
10351048
ty::RawPtr(ty_mut) => Ty::new_ptr(tcx, ty_mut),
10361049
// As these types are always non-null, the nullable equivalent of
1037-
// Option<T> of these types are their raw pointer counterparts.
1050+
// `Option<T>` of these types are their raw pointer counterparts.
10381051
ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty::TypeAndMut { ty, mutbl }),
1039-
ty::FnPtr(..) => {
1040-
// There is no nullable equivalent for Rust's function pointers -- you
1041-
// must use an Option<fn(..) -> _> to represent it.
1042-
ty
1043-
}
1044-
1045-
// We should only ever reach this case if ty_is_known_nonnull is extended
1046-
// to other types.
1052+
// There is no nullable equivalent for Rust's function pointers,
1053+
// you must use an `Option<fn(..) -> _>` to represent it.
1054+
ty::FnPtr(..) => ty,
1055+
// We should only ever reach this case if `ty_is_known_nonnull` is
1056+
// extended to other types.
10471057
ref unhandled => {
10481058
debug!(
10491059
"get_nullable_type: Unhandled scalar kind: {:?} while checking {:?}",
@@ -1056,7 +1066,7 @@ fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>>
10561066

10571067
/// Check if this enum can be safely exported based on the "nullable pointer optimization". If it
10581068
/// can, return the type that `ty` can be safely converted to, otherwise return `None`.
1059-
/// Currently restricted to function pointers, boxes, references, `core::num::NonZero*`,
1069+
/// Currently restricted to function pointers, boxes, references, `core::num::NonZero`,
10601070
/// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes.
10611071
/// FIXME: This duplicates code in codegen.
10621072
pub(crate) fn repr_nullable_ptr<'tcx>(
@@ -1075,7 +1085,7 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
10751085
_ => return None,
10761086
};
10771087

1078-
if !ty_is_known_nonnull(tcx, field_ty, ckind) {
1088+
if !ty_is_known_nonnull(tcx, param_env, field_ty, ckind) {
10791089
return None;
10801090
}
10811091

@@ -1099,10 +1109,10 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
10991109
WrappingRange { start: 0, end }
11001110
if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 =>
11011111
{
1102-
return Some(get_nullable_type(tcx, field_ty).unwrap());
1112+
return Some(get_nullable_type(tcx, param_env, field_ty).unwrap());
11031113
}
11041114
WrappingRange { start: 1, .. } => {
1105-
return Some(get_nullable_type(tcx, field_ty).unwrap());
1115+
return Some(get_nullable_type(tcx, param_env, field_ty).unwrap());
11061116
}
11071117
WrappingRange { start, end } => {
11081118
unreachable!("Unhandled start and end range: ({}, {})", start, end)

library/core/src/num/nonzero.rs

+96-50
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,13 @@ 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::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,33 @@ 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!(RefUnwindSafe);
147+
impl_nonzero_auto_trait!(unsafe Send);
148+
impl_nonzero_auto_trait!(unsafe Sync);
149+
impl_nonzero_auto_trait!(Unpin);
150+
impl_nonzero_auto_trait!(UnwindSafe);
151+
110152
#[stable(feature = "nonzero", since = "1.28.0")]
111153
impl<T> Clone for NonZero<T>
112154
where
113155
T: ZeroablePrimitive,
114156
{
115157
#[inline]
116158
fn clone(&self) -> Self {
117-
// SAFETY: The contained value is non-zero.
118-
unsafe { Self(self.0) }
159+
Self(self.0)
119160
}
120161
}
121162

@@ -188,19 +229,19 @@ where
188229
#[inline]
189230
fn max(self, other: Self) -> Self {
190231
// SAFETY: The maximum of two non-zero values is still non-zero.
191-
unsafe { Self(self.get().max(other.get())) }
232+
unsafe { Self::new_unchecked(self.get().max(other.get())) }
192233
}
193234

194235
#[inline]
195236
fn min(self, other: Self) -> Self {
196237
// SAFETY: The minimum of two non-zero values is still non-zero.
197-
unsafe { Self(self.get().min(other.get())) }
238+
unsafe { Self::new_unchecked(self.get().min(other.get())) }
198239
}
199240

200241
#[inline]
201242
fn clamp(self, min: Self, max: Self) -> Self {
202243
// 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())) }
244+
unsafe { Self::new_unchecked(self.get().clamp(min.get(), max.get())) }
204245
}
205246
}
206247

@@ -240,7 +281,7 @@ where
240281
#[inline]
241282
fn bitor(self, rhs: Self) -> Self::Output {
242283
// SAFETY: Bitwise OR of two non-zero values is still non-zero.
243-
unsafe { Self(self.get() | rhs.get()) }
284+
unsafe { Self::new_unchecked(self.get() | rhs.get()) }
244285
}
245286
}
246287

@@ -254,7 +295,7 @@ where
254295
#[inline]
255296
fn bitor(self, rhs: T) -> Self::Output {
256297
// SAFETY: Bitwise OR of a non-zero value with anything is still non-zero.
257-
unsafe { Self(self.get() | rhs) }
298+
unsafe { Self::new_unchecked(self.get() | rhs) }
258299
}
259300
}
260301

@@ -268,7 +309,7 @@ where
268309
#[inline]
269310
fn bitor(self, rhs: NonZero<T>) -> Self::Output {
270311
// SAFETY: Bitwise OR of anything with a non-zero value is still non-zero.
271-
unsafe { NonZero(self | rhs.get()) }
312+
unsafe { NonZero::new_unchecked(self | rhs.get()) }
272313
}
273314
}
274315

@@ -345,7 +386,7 @@ where
345386
pub fn from_mut(n: &mut T) -> Option<&mut Self> {
346387
// SAFETY: Memory layout optimization guarantees that `Option<NonZero<T>>` has
347388
// the same layout and size as `T`, with `0` representing `None`.
348-
let opt_n = unsafe { &mut *(n as *mut T as *mut Option<Self>) };
389+
let opt_n = unsafe { &mut *(ptr::from_mut(n).cast::<Option<Self>>()) };
349390

350391
opt_n.as_mut()
351392
}
@@ -388,12 +429,17 @@ where
388429
// memory somewhere. If the value of `self` was from by-value argument
389430
// of some not-inlined function, LLVM don't have range metadata
390431
// to understand that the value cannot be zero.
391-
match Self::new(self.0) {
392-
Some(Self(n)) => n,
432+
//
433+
// SAFETY: `Self` is guaranteed to have the same layout as `Option<Self>`.
434+
match unsafe { intrinsics::transmute_unchecked(self) } {
393435
None => {
394436
// SAFETY: `NonZero` is guaranteed to only contain non-zero values, so this is unreachable.
395437
unsafe { intrinsics::unreachable() }
396438
}
439+
Some(Self(inner)) => {
440+
// SAFETY: `T::NonZeroInner` is guaranteed to have the same layout as `T`.
441+
unsafe { intrinsics::transmute_unchecked(inner) }
442+
}
397443
}
398444
}
399445
}

src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1
1+
error: Undefined Behavior: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
22
--> $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC
33
|
44
LL | f();
5-
| ^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
5+
| ^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1
1+
error: Undefined Behavior: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
22
--> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC
33
|
44
LL | Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue())
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

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

+2-2
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) {

0 commit comments

Comments
 (0)