Skip to content

Commit a615cea

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 c8813dd + e4b27a2 commit a615cea

File tree

110 files changed

+1843
-1818
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

110 files changed

+1843
-1818
lines changed

compiler/rustc_lint/src/builtin.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2468,6 +2468,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
24682468
ty: Ty<'tcx>,
24692469
init: InitKind,
24702470
) -> Option<InitError> {
2471+
let ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty);
2472+
24712473
use rustc_type_ir::TyKind::*;
24722474
match ty.kind() {
24732475
// Primitive types that don't like 0 as a value.

compiler/rustc_lint/src/types.rs

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

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

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

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

1079-
if !ty_is_known_nonnull(tcx, field_ty, ckind) {
1089+
if !ty_is_known_nonnull(tcx, param_env, field_ty, ckind) {
10801090
return None;
10811091
}
10821092

@@ -1100,10 +1110,10 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
11001110
WrappingRange { start: 0, end }
11011111
if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 =>
11021112
{
1103-
return Some(get_nullable_type(tcx, field_ty).unwrap());
1113+
return Some(get_nullable_type(tcx, param_env, field_ty).unwrap());
11041114
}
11051115
WrappingRange { start: 1, .. } => {
1106-
return Some(get_nullable_type(tcx, field_ty).unwrap());
1116+
return Some(get_nullable_type(tcx, param_env, field_ty).unwrap());
11071117
}
11081118
WrappingRange { start, end } => {
11091119
unreachable!("Unhandled start and end range: ({}, {})", start, end)

library/core/src/num/nonzero.rs

+98-51
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
}

src/etc/gdb_providers.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,14 @@ def __init__(self, valobj):
245245
fields = valobj.type.fields()
246246
assert len(fields) == 1
247247
field = list(fields)[0]
248-
self._value = str(valobj[field.name])
248+
249+
inner_valobj = valobj[field.name]
250+
251+
inner_fields = inner_valobj.type.fields()
252+
assert len(inner_fields) == 1
253+
inner_field = list(inner_fields)[0]
254+
255+
self._value = str(inner_valobj[inner_field.name])
249256

250257
def to_string(self):
251258
return self._value

src/etc/lldb_commands

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)C
1515
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust
1616
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust
1717
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust
18-
type summary add -F lldb_lookup.summary_lookup -e -x -h "^core::num::([a-z_]+::)*NonZero.+$" --category Rust
18+
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)NonZero<.+>$" --category Rust
1919
type category enable Rust

0 commit comments

Comments
 (0)