diff --git a/library/core/src/ptr/internal_repr.rs b/library/core/src/ptr/internal_repr.rs new file mode 100644 index 0000000000000..55f84bac6b677 --- /dev/null +++ b/library/core/src/ptr/internal_repr.rs @@ -0,0 +1,74 @@ +//! This encapsulates the layout knowledge for pointers, only exporting the two +//! safe functions that can be used to interact with the metadata directly. + +use super::{NonNull, Pointee, Thin}; + +#[inline] +pub(super) const fn metadata(ptr: P) -> ::Metadata { + // SAFETY: Transmuting like this is safe since `P` and `PtrComponents` + // have the same memory layouts. Only std can make this guarantee. + unsafe { + crate::intrinsics::transmute_unchecked::< + P, + PtrComponents::Metadata>, + >(ptr) + .metadata + } +} + +/// Just like [`from_raw_parts`] and [`from_raw_parts_mut`], but more flexible +/// in terms of which types it can take, allowing smaller MIR. +// See +#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] +#[inline] +pub(crate) const fn from_raw_parts( + data_pointer: impl RawPointer, + metadata: ::Metadata, +) -> P { + // SAFETY: Transmuting like this is safe since `P` and `PtrComponents` + // have the same memory layouts. Only std can make this guarantee. + unsafe { + crate::intrinsics::transmute_unchecked::< + PtrComponents<_, ::Metadata>, + P, + >(PtrComponents { data_pointer, metadata }) + } +} + +// Intentionally private with no derives, as it's only used via transmuting. +// This layout is not stable; only std can rely on it. +// (And should only do so in the two functions in this module.) +#[repr(C)] +struct PtrComponents { + data_pointer: P, + metadata: M, +} + +/// Internal trait to avoid bad instantiations of [`PtrComponents`] +/// +/// # Safety +/// +/// Must have the same layout as `*const Self::Pointee` and be able to hold provenance. +/// +/// Every type with the same associated `Family` must be soundly transmutable +/// between each other when the metadata is the same. +pub unsafe trait RawPointer: Copy { + type Pointee: ?Sized + super::Pointee; + type Family: RawPointer; +} + +// SAFETY: `*const T` is obviously a raw pointer +unsafe impl RawPointer for *const T { + type Pointee = T; + type Family = *const (); +} +// SAFETY: `*mut T` is obviously a raw pointer +unsafe impl RawPointer for *mut T { + type Pointee = T; + type Family = *mut (); +} +// SAFETY: `NonNull` is a transparent newtype around a `*const T`. +unsafe impl RawPointer for NonNull { + type Pointee = T; + type Family = NonNull<()>; +} diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index fe19f66a31ac4..a49fddb07e344 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -2,6 +2,7 @@ use crate::fmt; use crate::hash::{Hash, Hasher}; +use crate::ptr::internal_repr; /// Provides the pointer metadata type of any pointed-to type. /// @@ -92,10 +93,7 @@ pub trait Thin = Pointee; #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[inline] pub const fn metadata(ptr: *const T) -> ::Metadata { - // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T - // and PtrComponents have the same memory layouts. Only std can make this - // guarantee. - unsafe { PtrRepr { const_ptr: ptr }.components.metadata } + internal_repr::metadata(ptr) } /// Forms a (possibly-wide) raw pointer from a data pointer and metadata. @@ -112,10 +110,7 @@ pub const fn from_raw_parts( data_pointer: *const (), metadata: ::Metadata, ) -> *const T { - // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T - // and PtrComponents have the same memory layouts. Only std can make this - // guarantee. - unsafe { PtrRepr { components: PtrComponents { data_pointer, metadata } }.const_ptr } + internal_repr::from_raw_parts(data_pointer, metadata) } /// Performs the same functionality as [`from_raw_parts`], except that a @@ -129,33 +124,7 @@ pub const fn from_raw_parts_mut( data_pointer: *mut (), metadata: ::Metadata, ) -> *mut T { - // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T - // and PtrComponents have the same memory layouts. Only std can make this - // guarantee. - unsafe { PtrRepr { components: PtrComponents { data_pointer, metadata } }.mut_ptr } -} - -#[repr(C)] -union PtrRepr { - const_ptr: *const T, - mut_ptr: *mut T, - components: PtrComponents, -} - -#[repr(C)] -struct PtrComponents { - data_pointer: *const (), - metadata: ::Metadata, -} - -// Manual impl needed to avoid `T: Copy` bound. -impl Copy for PtrComponents {} - -// Manual impl needed to avoid `T: Clone` bound. -impl Clone for PtrComponents { - fn clone(&self) -> Self { - *self - } + internal_repr::from_raw_parts(data_pointer, metadata) } /// The metadata for a `Dyn = dyn SomeTrait` trait object type. diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 56378b437e7ee..d20c13b376793 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -410,6 +410,8 @@ pub use crate::intrinsics::copy; #[doc(inline)] pub use crate::intrinsics::write_bytes; +mod internal_repr; + mod metadata; #[unstable(feature = "ptr_metadata", issue = "81513")] pub use metadata::{from_raw_parts, from_raw_parts_mut, metadata, DynMetadata, Pointee, Thin}; @@ -812,7 +814,7 @@ pub const fn from_mut(r: &mut T) -> *mut T { #[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_slice_from_raw_parts"] pub const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { - from_raw_parts(data.cast(), len) + internal_repr::from_raw_parts(data, len) } /// Forms a raw mutable slice from a pointer and a length. @@ -858,7 +860,7 @@ pub const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { #[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")] #[rustc_diagnostic_item = "ptr_slice_from_raw_parts_mut"] pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { - from_raw_parts_mut(data.cast(), len) + internal_repr::from_raw_parts(data, len) } /// Swaps the values at two mutable locations of the same type, without diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index e9488917acc14..d75a1e3976e2a 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -6,8 +6,7 @@ use crate::marker::Unsize; use crate::mem::{MaybeUninit, SizedTypeProperties}; use crate::num::NonZero; use crate::ops::{CoerceUnsized, DispatchFromDyn}; -use crate::ptr; -use crate::ptr::Unique; +use crate::ptr::{self, internal_repr, Unique}; use crate::slice::{self, SliceIndex}; use crate::ub_checks::assert_unsafe_precondition; @@ -265,10 +264,7 @@ impl NonNull { data_pointer: NonNull<()>, metadata: ::Metadata, ) -> NonNull { - // SAFETY: The result of `ptr::from::raw_parts_mut` is non-null because `data_pointer` is. - unsafe { - NonNull::new_unchecked(super::from_raw_parts_mut(data_pointer.as_ptr(), metadata)) - } + internal_repr::from_raw_parts(data_pointer, metadata) } /// Decompose a (possibly wide) pointer into its data pointer and metadata components. diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index df8d5c3836f1c..a6c0b24321702 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -3,12 +3,73 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { debug v => _1; let mut _0: &[u8]; - - bb0: { - _0 = as Deref>::deref(move _1) -> [return: bb1, unwind unreachable]; + scope 1 (inlined as Deref>::deref) { + debug self => _1; + let mut _4: *const u8; + let mut _5: usize; + scope 2 { + scope 3 (inlined Vec::::as_ptr) { + debug self => _1; + let mut _2: &alloc::raw_vec::RawVec; + scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { + debug self => _2; + let mut _3: std::ptr::NonNull; + scope 5 (inlined Unique::::as_ptr) { + debug ((self: Unique).0: std::ptr::NonNull) => _3; + debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; + scope 6 (inlined NonNull::::as_ptr) { + debug self => _3; + } + } + } + } + scope 7 (inlined std::slice::from_raw_parts::<'_, u8>) { + debug data => _4; + debug len => _5; + let _7: *const [u8]; + scope 8 { + scope 9 (inlined core::ub_checks::check_language_ub) { + scope 10 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 11 (inlined std::mem::size_of::) { + } + scope 12 (inlined align_of::) { + } + scope 13 (inlined slice_from_raw_parts::) { + debug data => _4; + debug len => _5; + scope 14 (inlined std::ptr::internal_repr::from_raw_parts::<*const [u8], *const u8>) { + debug data_pointer => _4; + debug metadata => _5; + let mut _6: std::ptr::internal_repr::PtrComponents<*const u8, usize>; + scope 15 { + } + } + } + } + } + } } - bb1: { + bb0: { + StorageLive(_4); + StorageLive(_2); + _2 = &((*_1).0: alloc::raw_vec::RawVec); + StorageLive(_3); + _3 = ((((*_1).0: alloc::raw_vec::RawVec).0: std::ptr::Unique).0: std::ptr::NonNull); + _4 = (_3.0: *const u8); + StorageDead(_3); + StorageDead(_2); + StorageLive(_5); + _5 = ((*_1).1: usize); + StorageLive(_6); + _6 = std::ptr::internal_repr::PtrComponents::<*const u8, usize> { data_pointer: _4, metadata: _5 }; + _7 = move _6 as *const [u8] (Transmute); + StorageDead(_6); + StorageDead(_5); + StorageDead(_4); + _0 = &(*_7); return; } } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index d26afef4653ec..a6c0b24321702 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -3,12 +3,73 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { debug v => _1; let mut _0: &[u8]; - - bb0: { - _0 = as Deref>::deref(move _1) -> [return: bb1, unwind continue]; + scope 1 (inlined as Deref>::deref) { + debug self => _1; + let mut _4: *const u8; + let mut _5: usize; + scope 2 { + scope 3 (inlined Vec::::as_ptr) { + debug self => _1; + let mut _2: &alloc::raw_vec::RawVec; + scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { + debug self => _2; + let mut _3: std::ptr::NonNull; + scope 5 (inlined Unique::::as_ptr) { + debug ((self: Unique).0: std::ptr::NonNull) => _3; + debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; + scope 6 (inlined NonNull::::as_ptr) { + debug self => _3; + } + } + } + } + scope 7 (inlined std::slice::from_raw_parts::<'_, u8>) { + debug data => _4; + debug len => _5; + let _7: *const [u8]; + scope 8 { + scope 9 (inlined core::ub_checks::check_language_ub) { + scope 10 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 11 (inlined std::mem::size_of::) { + } + scope 12 (inlined align_of::) { + } + scope 13 (inlined slice_from_raw_parts::) { + debug data => _4; + debug len => _5; + scope 14 (inlined std::ptr::internal_repr::from_raw_parts::<*const [u8], *const u8>) { + debug data_pointer => _4; + debug metadata => _5; + let mut _6: std::ptr::internal_repr::PtrComponents<*const u8, usize>; + scope 15 { + } + } + } + } + } + } } - bb1: { + bb0: { + StorageLive(_4); + StorageLive(_2); + _2 = &((*_1).0: alloc::raw_vec::RawVec); + StorageLive(_3); + _3 = ((((*_1).0: alloc::raw_vec::RawVec).0: std::ptr::Unique).0: std::ptr::NonNull); + _4 = (_3.0: *const u8); + StorageDead(_3); + StorageDead(_2); + StorageLive(_5); + _5 = ((*_1).1: usize); + StorageLive(_6); + _6 = std::ptr::internal_repr::PtrComponents::<*const u8, usize> { data_pointer: _4, metadata: _5 }; + _7 = move _6 as *const [u8] (Transmute); + StorageDead(_6); + StorageDead(_5); + StorageDead(_4); + _0 = &(*_7); return; } }