Skip to content

Commit a3bb26f

Browse files
committed
Shrink from_raw_parts's MIR so that Vec::deref MIR-inlines again
1 parent 556216a commit a3bb26f

6 files changed

+214
-51
lines changed

library/core/src/ptr/internal_repr.rs

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//! This encapsulates the layout knowledge for pointers, only exporting the two
2+
//! safe functions that can be used to interact with the metadata directly.
3+
4+
use super::{NonNull, Pointee, Thin};
5+
6+
#[inline]
7+
pub(super) const fn metadata<P: RawPointer>(ptr: P) -> <P::Pointee as Pointee>::Metadata {
8+
// SAFETY: Transmuting like this is safe since `P` and `PtrComponents<P, _>`
9+
// have the same memory layouts. Only std can make this guarantee.
10+
unsafe {
11+
crate::intrinsics::transmute_unchecked::<
12+
P,
13+
PtrComponents<P::Family, <P::Pointee as Pointee>::Metadata>,
14+
>(ptr)
15+
.metadata
16+
}
17+
}
18+
19+
/// Just like [`from_raw_parts`] and [`from_raw_parts_mut`], but more flexible
20+
/// in terms of which types it can take, allowing smaller MIR.
21+
// See <https://github.com./rust-lang/rust/issues/123174>
22+
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
23+
#[inline]
24+
pub(crate) const fn from_raw_parts<P: RawPointer>(
25+
data_pointer: impl RawPointer<Pointee: Thin, Family = P::Family>,
26+
metadata: <P::Pointee as Pointee>::Metadata,
27+
) -> P {
28+
// SAFETY: Transmuting like this is safe since `P` and `PtrComponents<P, _>`
29+
// have the same memory layouts. Only std can make this guarantee.
30+
unsafe {
31+
crate::intrinsics::transmute_unchecked::<
32+
PtrComponents<_, <P::Pointee as Pointee>::Metadata>,
33+
P,
34+
>(PtrComponents { data_pointer, metadata })
35+
}
36+
}
37+
38+
// Intentionally private with no derives, as it's only used via transmuting.
39+
// This layout is not stable; only std can rely on it.
40+
// (And should only do so in the two functions in this module.)
41+
#[repr(C)]
42+
struct PtrComponents<P, M = ()> {
43+
data_pointer: P,
44+
metadata: M,
45+
}
46+
47+
/// Internal trait to avoid bad instantiations of [`PtrComponents`]
48+
///
49+
/// # Safety
50+
///
51+
/// Must have the same layout as `*const Self::Pointee` and be able to hold provenance.
52+
///
53+
/// Every type with the same associated `Family` must be soundly transmutable
54+
/// between each other when the metadata is the same.
55+
pub unsafe trait RawPointer: Copy {
56+
type Pointee: ?Sized + super::Pointee;
57+
type Family: RawPointer<Pointee = (), Family = Self::Family>;
58+
}
59+
60+
// SAFETY: `*const T` is obviously a raw pointer
61+
unsafe impl<T: ?Sized> RawPointer for *const T {
62+
type Pointee = T;
63+
type Family = *const ();
64+
}
65+
// SAFETY: `*mut T` is obviously a raw pointer
66+
unsafe impl<T: ?Sized> RawPointer for *mut T {
67+
type Pointee = T;
68+
type Family = *mut ();
69+
}
70+
// SAFETY: `NonNull<T>` is a transparent newtype around a `*const T`.
71+
unsafe impl<T: ?Sized> RawPointer for NonNull<T> {
72+
type Pointee = T;
73+
type Family = NonNull<()>;
74+
}

library/core/src/ptr/metadata.rs

+4-35
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use crate::fmt;
44
use crate::hash::{Hash, Hasher};
5+
use crate::ptr::internal_repr;
56

67
/// Provides the pointer metadata type of any pointed-to type.
78
///
@@ -92,10 +93,7 @@ pub trait Thin = Pointee<Metadata = ()>;
9293
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
9394
#[inline]
9495
pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
95-
// SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
96-
// and PtrComponents<T> have the same memory layouts. Only std can make this
97-
// guarantee.
98-
unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
96+
internal_repr::metadata(ptr)
9997
}
10098

10199
/// Forms a (possibly-wide) raw pointer from a data pointer and metadata.
@@ -112,10 +110,7 @@ pub const fn from_raw_parts<T: ?Sized>(
112110
data_pointer: *const (),
113111
metadata: <T as Pointee>::Metadata,
114112
) -> *const T {
115-
// SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
116-
// and PtrComponents<T> have the same memory layouts. Only std can make this
117-
// guarantee.
118-
unsafe { PtrRepr { components: PtrComponents { data_pointer, metadata } }.const_ptr }
113+
internal_repr::from_raw_parts(data_pointer, metadata)
119114
}
120115

121116
/// Performs the same functionality as [`from_raw_parts`], except that a
@@ -129,33 +124,7 @@ pub const fn from_raw_parts_mut<T: ?Sized>(
129124
data_pointer: *mut (),
130125
metadata: <T as Pointee>::Metadata,
131126
) -> *mut T {
132-
// SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
133-
// and PtrComponents<T> have the same memory layouts. Only std can make this
134-
// guarantee.
135-
unsafe { PtrRepr { components: PtrComponents { data_pointer, metadata } }.mut_ptr }
136-
}
137-
138-
#[repr(C)]
139-
union PtrRepr<T: ?Sized> {
140-
const_ptr: *const T,
141-
mut_ptr: *mut T,
142-
components: PtrComponents<T>,
143-
}
144-
145-
#[repr(C)]
146-
struct PtrComponents<T: ?Sized> {
147-
data_pointer: *const (),
148-
metadata: <T as Pointee>::Metadata,
149-
}
150-
151-
// Manual impl needed to avoid `T: Copy` bound.
152-
impl<T: ?Sized> Copy for PtrComponents<T> {}
153-
154-
// Manual impl needed to avoid `T: Clone` bound.
155-
impl<T: ?Sized> Clone for PtrComponents<T> {
156-
fn clone(&self) -> Self {
157-
*self
158-
}
127+
internal_repr::from_raw_parts(data_pointer, metadata)
159128
}
160129

161130
/// The metadata for a `Dyn = dyn SomeTrait` trait object type.

library/core/src/ptr/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,8 @@ pub use crate::intrinsics::copy;
410410
#[doc(inline)]
411411
pub use crate::intrinsics::write_bytes;
412412

413+
mod internal_repr;
414+
413415
mod metadata;
414416
#[unstable(feature = "ptr_metadata", issue = "81513")]
415417
pub use metadata::{from_raw_parts, from_raw_parts_mut, metadata, DynMetadata, Pointee, Thin};
@@ -812,7 +814,7 @@ pub const fn from_mut<T: ?Sized>(r: &mut T) -> *mut T {
812814
#[rustc_allow_const_fn_unstable(ptr_metadata)]
813815
#[rustc_diagnostic_item = "ptr_slice_from_raw_parts"]
814816
pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
815-
from_raw_parts(data.cast(), len)
817+
internal_repr::from_raw_parts(data, len)
816818
}
817819

818820
/// Forms a raw mutable slice from a pointer and a length.
@@ -858,7 +860,7 @@ pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
858860
#[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")]
859861
#[rustc_diagnostic_item = "ptr_slice_from_raw_parts_mut"]
860862
pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
861-
from_raw_parts_mut(data.cast(), len)
863+
internal_repr::from_raw_parts(data, len)
862864
}
863865

864866
/// Swaps the values at two mutable locations of the same type, without

library/core/src/ptr/non_null.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ use crate::marker::Unsize;
66
use crate::mem::{MaybeUninit, SizedTypeProperties};
77
use crate::num::NonZero;
88
use crate::ops::{CoerceUnsized, DispatchFromDyn};
9-
use crate::ptr;
10-
use crate::ptr::Unique;
9+
use crate::ptr::{self, internal_repr, Unique};
1110
use crate::slice::{self, SliceIndex};
1211
use crate::ub_checks::assert_unsafe_precondition;
1312

@@ -265,10 +264,7 @@ impl<T: ?Sized> NonNull<T> {
265264
data_pointer: NonNull<()>,
266265
metadata: <T as super::Pointee>::Metadata,
267266
) -> NonNull<T> {
268-
// SAFETY: The result of `ptr::from::raw_parts_mut` is non-null because `data_pointer` is.
269-
unsafe {
270-
NonNull::new_unchecked(super::from_raw_parts_mut(data_pointer.as_ptr(), metadata))
271-
}
267+
internal_repr::from_raw_parts(data_pointer, metadata)
272268
}
273269

274270
/// Decompose a (possibly wide) pointer into its data pointer and metadata components.

tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir

+65-4
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,73 @@
33
fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] {
44
debug v => _1;
55
let mut _0: &[u8];
6-
7-
bb0: {
8-
_0 = <Vec<u8> as Deref>::deref(move _1) -> [return: bb1, unwind unreachable];
6+
scope 1 (inlined <Vec<u8> as Deref>::deref) {
7+
debug self => _1;
8+
let mut _4: *const u8;
9+
let mut _5: usize;
10+
scope 2 {
11+
scope 3 (inlined Vec::<u8>::as_ptr) {
12+
debug self => _1;
13+
let mut _2: &alloc::raw_vec::RawVec<u8>;
14+
scope 4 (inlined alloc::raw_vec::RawVec::<u8>::ptr) {
15+
debug self => _2;
16+
let mut _3: std::ptr::NonNull<u8>;
17+
scope 5 (inlined Unique::<u8>::as_ptr) {
18+
debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _3;
19+
debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
20+
scope 6 (inlined NonNull::<u8>::as_ptr) {
21+
debug self => _3;
22+
}
23+
}
24+
}
25+
}
26+
scope 7 (inlined std::slice::from_raw_parts::<'_, u8>) {
27+
debug data => _4;
28+
debug len => _5;
29+
let _7: *const [u8];
30+
scope 8 {
31+
scope 9 (inlined core::ub_checks::check_language_ub) {
32+
scope 10 (inlined core::ub_checks::check_language_ub::runtime) {
33+
}
34+
}
35+
scope 11 (inlined std::mem::size_of::<u8>) {
36+
}
37+
scope 12 (inlined align_of::<u8>) {
38+
}
39+
scope 13 (inlined slice_from_raw_parts::<u8>) {
40+
debug data => _4;
41+
debug len => _5;
42+
scope 14 (inlined std::ptr::internal_repr::from_raw_parts::<*const [u8], *const u8>) {
43+
debug data_pointer => _4;
44+
debug metadata => _5;
45+
let mut _6: std::ptr::internal_repr::PtrComponents<*const u8, usize>;
46+
scope 15 {
47+
}
48+
}
49+
}
50+
}
51+
}
52+
}
953
}
1054

11-
bb1: {
55+
bb0: {
56+
StorageLive(_4);
57+
StorageLive(_2);
58+
_2 = &((*_1).0: alloc::raw_vec::RawVec<u8>);
59+
StorageLive(_3);
60+
_3 = ((((*_1).0: alloc::raw_vec::RawVec<u8>).0: std::ptr::Unique<u8>).0: std::ptr::NonNull<u8>);
61+
_4 = (_3.0: *const u8);
62+
StorageDead(_3);
63+
StorageDead(_2);
64+
StorageLive(_5);
65+
_5 = ((*_1).1: usize);
66+
StorageLive(_6);
67+
_6 = std::ptr::internal_repr::PtrComponents::<*const u8, usize> { data_pointer: _4, metadata: _5 };
68+
_7 = move _6 as *const [u8] (Transmute);
69+
StorageDead(_6);
70+
StorageDead(_5);
71+
StorageDead(_4);
72+
_0 = &(*_7);
1273
return;
1374
}
1475
}

tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir

+65-4
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,73 @@
33
fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] {
44
debug v => _1;
55
let mut _0: &[u8];
6-
7-
bb0: {
8-
_0 = <Vec<u8> as Deref>::deref(move _1) -> [return: bb1, unwind continue];
6+
scope 1 (inlined <Vec<u8> as Deref>::deref) {
7+
debug self => _1;
8+
let mut _4: *const u8;
9+
let mut _5: usize;
10+
scope 2 {
11+
scope 3 (inlined Vec::<u8>::as_ptr) {
12+
debug self => _1;
13+
let mut _2: &alloc::raw_vec::RawVec<u8>;
14+
scope 4 (inlined alloc::raw_vec::RawVec::<u8>::ptr) {
15+
debug self => _2;
16+
let mut _3: std::ptr::NonNull<u8>;
17+
scope 5 (inlined Unique::<u8>::as_ptr) {
18+
debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _3;
19+
debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
20+
scope 6 (inlined NonNull::<u8>::as_ptr) {
21+
debug self => _3;
22+
}
23+
}
24+
}
25+
}
26+
scope 7 (inlined std::slice::from_raw_parts::<'_, u8>) {
27+
debug data => _4;
28+
debug len => _5;
29+
let _7: *const [u8];
30+
scope 8 {
31+
scope 9 (inlined core::ub_checks::check_language_ub) {
32+
scope 10 (inlined core::ub_checks::check_language_ub::runtime) {
33+
}
34+
}
35+
scope 11 (inlined std::mem::size_of::<u8>) {
36+
}
37+
scope 12 (inlined align_of::<u8>) {
38+
}
39+
scope 13 (inlined slice_from_raw_parts::<u8>) {
40+
debug data => _4;
41+
debug len => _5;
42+
scope 14 (inlined std::ptr::internal_repr::from_raw_parts::<*const [u8], *const u8>) {
43+
debug data_pointer => _4;
44+
debug metadata => _5;
45+
let mut _6: std::ptr::internal_repr::PtrComponents<*const u8, usize>;
46+
scope 15 {
47+
}
48+
}
49+
}
50+
}
51+
}
52+
}
953
}
1054

11-
bb1: {
55+
bb0: {
56+
StorageLive(_4);
57+
StorageLive(_2);
58+
_2 = &((*_1).0: alloc::raw_vec::RawVec<u8>);
59+
StorageLive(_3);
60+
_3 = ((((*_1).0: alloc::raw_vec::RawVec<u8>).0: std::ptr::Unique<u8>).0: std::ptr::NonNull<u8>);
61+
_4 = (_3.0: *const u8);
62+
StorageDead(_3);
63+
StorageDead(_2);
64+
StorageLive(_5);
65+
_5 = ((*_1).1: usize);
66+
StorageLive(_6);
67+
_6 = std::ptr::internal_repr::PtrComponents::<*const u8, usize> { data_pointer: _4, metadata: _5 };
68+
_7 = move _6 as *const [u8] (Transmute);
69+
StorageDead(_6);
70+
StorageDead(_5);
71+
StorageDead(_4);
72+
_0 = &(*_7);
1273
return;
1374
}
1475
}

0 commit comments

Comments
 (0)