diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 5d36a8b3d0e9c..500efefbb1198 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -984,7 +984,14 @@ pub fn transparent_newtype_field<'a, 'tcx>( } /// Is type known to be non-null? -fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool { +fn ty_is_known_nonnull<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + mode: CItemKind, +) -> bool { + let ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty); + match ty.kind() { ty::FnPtr(_) => true, ty::Ref(..) => true, @@ -1004,7 +1011,7 @@ fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) - def.variants() .iter() .filter_map(|variant| transparent_newtype_field(tcx, variant)) - .any(|field| ty_is_known_nonnull(tcx, field.ty(tcx, args), mode)) + .any(|field| ty_is_known_nonnull(tcx, param_env, field.ty(tcx, args), mode)) } _ => false, } @@ -1012,7 +1019,13 @@ fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) - /// Given a non-null scalar (or transparent) type `ty`, return the nullable version of that type. /// If the type passed in was not scalar, returns None. -fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option> { +fn get_nullable_type<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, +) -> Option> { + let ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty); + Some(match *ty.kind() { ty::Adt(field_def, field_args) => { let inner_field_ty = { @@ -1028,22 +1041,19 @@ fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option> .expect("No non-zst fields in transparent type.") .ty(tcx, field_args) }; - return get_nullable_type(tcx, inner_field_ty); + return get_nullable_type(tcx, param_env, inner_field_ty); } ty::Int(ty) => Ty::new_int(tcx, ty), ty::Uint(ty) => Ty::new_uint(tcx, ty), ty::RawPtr(ty_mut) => Ty::new_ptr(tcx, ty_mut), // As these types are always non-null, the nullable equivalent of - // Option of these types are their raw pointer counterparts. + // `Option` of these types are their raw pointer counterparts. ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty::TypeAndMut { ty, mutbl }), - ty::FnPtr(..) => { - // There is no nullable equivalent for Rust's function pointers -- you - // must use an Option _> to represent it. - ty - } - - // We should only ever reach this case if ty_is_known_nonnull is extended - // to other types. + // There is no nullable equivalent for Rust's function pointers, + // you must use an `Option _>` to represent it. + ty::FnPtr(..) => ty, + // We should only ever reach this case if `ty_is_known_nonnull` is + // extended to other types. ref unhandled => { debug!( "get_nullable_type: Unhandled scalar kind: {:?} while checking {:?}", @@ -1056,7 +1066,7 @@ fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option> /// Check if this enum can be safely exported based on the "nullable pointer optimization". If it /// can, return the type that `ty` can be safely converted to, otherwise return `None`. -/// Currently restricted to function pointers, boxes, references, `core::num::NonZero*`, +/// Currently restricted to function pointers, boxes, references, `core::num::NonZero`, /// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes. /// FIXME: This duplicates code in codegen. pub(crate) fn repr_nullable_ptr<'tcx>( @@ -1075,7 +1085,7 @@ pub(crate) fn repr_nullable_ptr<'tcx>( _ => return None, }; - if !ty_is_known_nonnull(tcx, field_ty, ckind) { + if !ty_is_known_nonnull(tcx, param_env, field_ty, ckind) { return None; } @@ -1099,10 +1109,10 @@ pub(crate) fn repr_nullable_ptr<'tcx>( WrappingRange { start: 0, end } if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 => { - return Some(get_nullable_type(tcx, field_ty).unwrap()); + return Some(get_nullable_type(tcx, param_env, field_ty).unwrap()); } WrappingRange { start: 1, .. } => { - return Some(get_nullable_type(tcx, field_ty).unwrap()); + return Some(get_nullable_type(tcx, param_env, field_ty).unwrap()); } WrappingRange { start, end } => { unreachable!("Unhandled start and end range: ({}, {})", start, end) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 9e34c0d240dc2..5605c871281b8 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -6,21 +6,13 @@ use crate::hash::{Hash, Hasher}; use crate::intrinsics; use crate::marker::StructuralPartialEq; use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem}; +use crate::panic::{RefUnwindSafe, UnwindSafe}; +use crate::ptr; use crate::str::FromStr; use super::from_str_radix; use super::{IntErrorKind, ParseIntError}; -mod private { - #[unstable( - feature = "nonzero_internals", - reason = "implementation detail which may disappear or be replaced at any time", - issue = "none" - )] - #[const_trait] - pub trait Sealed {} -} - /// A marker trait for primitive types which can be zero. /// /// This is an implementation detail for [NonZero]\ which may disappear or be replaced at any time. @@ -34,38 +26,70 @@ mod private { issue = "none" )] #[const_trait] -pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed {} +pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed { + #[doc(hidden)] + type NonZeroInner: Sized + Copy; +} macro_rules! impl_zeroable_primitive { - ($primitive:ty) => { - #[unstable( - feature = "nonzero_internals", - reason = "implementation detail which may disappear or be replaced at any time", - issue = "none" - )] - impl const private::Sealed for $primitive {} - - #[unstable( - feature = "nonzero_internals", - reason = "implementation detail which may disappear or be replaced at any time", - issue = "none" - )] - unsafe impl const ZeroablePrimitive for $primitive {} + ($($NonZeroInner:ident ( $primitive:ty )),+ $(,)?) => { + mod private { + #[unstable( + feature = "nonzero_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" + )] + #[const_trait] + pub trait Sealed {} + + $( + #[derive(Debug, Clone, Copy, PartialEq)] + #[repr(transparent)] + #[rustc_layout_scalar_valid_range_start(1)] + #[rustc_nonnull_optimization_guaranteed] + #[unstable( + feature = "nonzero_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" + )] + pub struct $NonZeroInner($primitive); + )+ + } + + $( + #[unstable( + feature = "nonzero_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" + )] + impl const private::Sealed for $primitive {} + + #[unstable( + feature = "nonzero_internals", + reason = "implementation detail which may disappear or be replaced at any time", + issue = "none" + )] + unsafe impl const ZeroablePrimitive for $primitive { + type NonZeroInner = private::$NonZeroInner; + } + )+ }; } -impl_zeroable_primitive!(u8); -impl_zeroable_primitive!(u16); -impl_zeroable_primitive!(u32); -impl_zeroable_primitive!(u64); -impl_zeroable_primitive!(u128); -impl_zeroable_primitive!(usize); -impl_zeroable_primitive!(i8); -impl_zeroable_primitive!(i16); -impl_zeroable_primitive!(i32); -impl_zeroable_primitive!(i64); -impl_zeroable_primitive!(i128); -impl_zeroable_primitive!(isize); +impl_zeroable_primitive!( + NonZeroU8Inner(u8), + NonZeroU16Inner(u16), + NonZeroU32Inner(u32), + NonZeroU64Inner(u64), + NonZeroU128Inner(u128), + NonZeroUsizeInner(usize), + NonZeroI8Inner(i8), + NonZeroI16Inner(i16), + NonZeroI32Inner(i32), + NonZeroI64Inner(i64), + NonZeroI128Inner(i128), + NonZeroIsizeInner(isize), +); /// A value that is known not to equal zero. /// @@ -80,10 +104,9 @@ impl_zeroable_primitive!(isize); /// ``` #[unstable(feature = "generic_nonzero", issue = "120257")] #[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(1)] #[rustc_nonnull_optimization_guaranteed] #[rustc_diagnostic_item = "NonZero"] -pub struct NonZero(T); +pub struct NonZero(T::NonZeroInner); macro_rules! impl_nonzero_fmt { ($Trait:ident) => { @@ -107,6 +130,25 @@ impl_nonzero_fmt!(Octal); impl_nonzero_fmt!(LowerHex); impl_nonzero_fmt!(UpperHex); +macro_rules! impl_nonzero_auto_trait { + (unsafe $Trait:ident) => { + #[stable(feature = "nonzero", since = "1.28.0")] + unsafe impl $Trait for NonZero where T: ZeroablePrimitive + $Trait {} + }; + ($Trait:ident) => { + #[stable(feature = "nonzero", since = "1.28.0")] + impl $Trait for NonZero where T: ZeroablePrimitive + $Trait {} + }; +} + +// Implement auto-traits manually based on `T` to avoid docs exposing +// the `ZeroablePrimitive::NonZeroInner` implementation detail. +impl_nonzero_auto_trait!(RefUnwindSafe); +impl_nonzero_auto_trait!(unsafe Send); +impl_nonzero_auto_trait!(unsafe Sync); +impl_nonzero_auto_trait!(Unpin); +impl_nonzero_auto_trait!(UnwindSafe); + #[stable(feature = "nonzero", since = "1.28.0")] impl Clone for NonZero where @@ -114,8 +156,7 @@ where { #[inline] fn clone(&self) -> Self { - // SAFETY: The contained value is non-zero. - unsafe { Self(self.0) } + Self(self.0) } } @@ -188,19 +229,19 @@ where #[inline] fn max(self, other: Self) -> Self { // SAFETY: The maximum of two non-zero values is still non-zero. - unsafe { Self(self.get().max(other.get())) } + unsafe { Self::new_unchecked(self.get().max(other.get())) } } #[inline] fn min(self, other: Self) -> Self { // SAFETY: The minimum of two non-zero values is still non-zero. - unsafe { Self(self.get().min(other.get())) } + unsafe { Self::new_unchecked(self.get().min(other.get())) } } #[inline] fn clamp(self, min: Self, max: Self) -> Self { // SAFETY: A non-zero value clamped between two non-zero values is still non-zero. - unsafe { Self(self.get().clamp(min.get(), max.get())) } + unsafe { Self::new_unchecked(self.get().clamp(min.get(), max.get())) } } } @@ -240,7 +281,7 @@ where #[inline] fn bitor(self, rhs: Self) -> Self::Output { // SAFETY: Bitwise OR of two non-zero values is still non-zero. - unsafe { Self(self.get() | rhs.get()) } + unsafe { Self::new_unchecked(self.get() | rhs.get()) } } } @@ -254,7 +295,7 @@ where #[inline] fn bitor(self, rhs: T) -> Self::Output { // SAFETY: Bitwise OR of a non-zero value with anything is still non-zero. - unsafe { Self(self.get() | rhs) } + unsafe { Self::new_unchecked(self.get() | rhs) } } } @@ -268,7 +309,7 @@ where #[inline] fn bitor(self, rhs: NonZero) -> Self::Output { // SAFETY: Bitwise OR of anything with a non-zero value is still non-zero. - unsafe { NonZero(self | rhs.get()) } + unsafe { NonZero::new_unchecked(self | rhs.get()) } } } @@ -345,7 +386,7 @@ where pub fn from_mut(n: &mut T) -> Option<&mut Self> { // SAFETY: Memory layout optimization guarantees that `Option>` has // the same layout and size as `T`, with `0` representing `None`. - let opt_n = unsafe { &mut *(n as *mut T as *mut Option) }; + let opt_n = unsafe { &mut *(ptr::from_mut(n).cast::>()) }; opt_n.as_mut() } @@ -388,12 +429,17 @@ where // memory somewhere. If the value of `self` was from by-value argument // of some not-inlined function, LLVM don't have range metadata // to understand that the value cannot be zero. - match Self::new(self.0) { - Some(Self(n)) => n, + // + // SAFETY: `Self` is guaranteed to have the same layout as `Option`. + match unsafe { intrinsics::transmute_unchecked(self) } { None => { // SAFETY: `NonZero` is guaranteed to only contain non-zero values, so this is unreachable. unsafe { intrinsics::unreachable() } } + Some(Self(inner)) => { + // SAFETY: `T::NonZeroInner` is guaranteed to have the same layout as `T`. + unsafe { intrinsics::transmute_unchecked(inner) } + } } } } diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr index 7d481940acec9..35de453522257 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 +error: Undefined Behavior: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 --> $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC | LL | f(); - | ^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr index b1a2bd2c79a40..81d775f6d7f5f 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 +error: Undefined Behavior: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC | LL | Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr index c06c30741164a..c1748c2e23769 100644 --- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr @@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:59:1 | LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = 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. = 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 --> $DIR/raw-bytes.rs:61:1 | LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = 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. = note: the raw bytes of the constant (size: 4, align: 4) { diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr index 0589280524cab..eb97eab9db756 100644 --- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr @@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:59:1 | LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = 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. = 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 --> $DIR/raw-bytes.rs:61:1 | LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = 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. = note: the raw bytes of the constant (size: 8, align: 8) { diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index 70b961fe1cd4f..ab0fb2abdb309 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -19,7 +19,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:24:1 | LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = 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. = 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 --> $DIR/ub-nonnull.rs:26:1 | LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 | = 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. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { diff --git a/tests/ui/lint/invalid_value.stderr b/tests/ui/lint/invalid_value.stderr index 955d01bd5d904..e45d061a1f051 100644 --- a/tests/ui/lint/invalid_value.stderr +++ b/tests/ui/lint/invalid_value.stderr @@ -320,10 +320,7 @@ error: the type `(NonZero, i32)` does not permit zero-initialization --> $DIR/invalid_value.rs:94:41 | LL | let _val: (NonZero, i32) = mem::zeroed(); - | ^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | ^^^^^^^^^^^^^ this code causes undefined behavior when executed | = note: `std::num::NonZero` must be non-null @@ -331,13 +328,9 @@ error: the type `(NonZero, i32)` does not permit being left uninitialized --> $DIR/invalid_value.rs:95:41 | LL | let _val: (NonZero, i32) = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | ^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed | = note: `std::num::NonZero` must be non-null - = note: integers must be initialized error: the type `*const dyn Send` does not permit zero-initialization --> $DIR/invalid_value.rs:97:37 @@ -411,10 +404,7 @@ error: the type `OneFruitNonZero` does not permit zero-initialization --> $DIR/invalid_value.rs:106:37 | LL | let _val: OneFruitNonZero = mem::zeroed(); - | ^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | ^^^^^^^^^^^^^ this code causes undefined behavior when executed | = note: `OneFruitNonZero` must be non-null note: because `std::num::NonZero` must be non-null (in this field of the only potentially inhabited enum variant) @@ -427,10 +417,7 @@ error: the type `OneFruitNonZero` does not permit being left uninitialized --> $DIR/invalid_value.rs:107:37 | LL | let _val: OneFruitNonZero = mem::uninitialized(); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | ^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed | = note: `OneFruitNonZero` must be non-null note: because `std::num::NonZero` must be non-null (in this field of the only potentially inhabited enum variant) @@ -438,7 +425,6 @@ note: because `std::num::NonZero` must be non-null (in this field of the on | LL | Banana(NonZero), | ^^^^^^^^^^^^ - = note: integers must be initialized error: the type `bool` does not permit being left uninitialized --> $DIR/invalid_value.rs:111:26 @@ -607,10 +593,7 @@ error: the type `NonZero` does not permit zero-initialization --> $DIR/invalid_value.rs:153:34 | LL | let _val: NonZero = mem::transmute(0); - | ^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | ^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed | = note: `std::num::NonZero` must be non-null diff --git a/tests/ui/print_type_sizes/niche-filling.stdout b/tests/ui/print_type_sizes/niche-filling.stdout index 53a58ccc4eef8..eeb5de5324121 100644 --- a/tests/ui/print_type_sizes/niche-filling.stdout +++ b/tests/ui/print_type_sizes/niche-filling.stdout @@ -68,6 +68,8 @@ print-type-size type: `Union2, u32>`: 4 bytes, alignment: print-type-size variant `Union2`: 4 bytes print-type-size field `.a`: 4 bytes print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes +print-type-size type: `core::num::nonzero::private::NonZeroU32Inner`: 4 bytes, alignment: 4 bytes +print-type-size field `.0`: 4 bytes print-type-size type: `std::num::NonZero`: 4 bytes, alignment: 4 bytes print-type-size field `.0`: 4 bytes print-type-size type: `std::option::Option>`: 4 bytes, alignment: 4 bytes