Skip to content

Commit 787f4de

Browse files
committed
Use new pointer metadata API inside libcore instead of manual transmutes
1 parent c0e3a1b commit 787f4de

File tree

5 files changed

+100
-42
lines changed

5 files changed

+100
-42
lines changed

library/core/src/hash/mod.rs

+44-26
Original file line numberDiff line numberDiff line change
@@ -673,39 +673,57 @@ mod impls {
673673
#[stable(feature = "rust1", since = "1.0.0")]
674674
impl<T: ?Sized> Hash for *const T {
675675
fn hash<H: Hasher>(&self, state: &mut H) {
676-
if mem::size_of::<Self>() == mem::size_of::<usize>() {
677-
// Thin pointer
678-
state.write_usize(*self as *const () as usize);
679-
} else {
680-
// Fat pointer
681-
// SAFETY: we are accessing the memory occupied by `self`
682-
// which is guaranteed to be valid.
683-
// This assumes a fat pointer can be represented by a `(usize, usize)`,
684-
// which is safe to do in `std` because it is shipped and kept in sync
685-
// with the implementation of fat pointers in `rustc`.
686-
let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
687-
state.write_usize(a);
688-
state.write_usize(b);
676+
#[cfg(not(bootstrap))]
677+
{
678+
let (address, metadata) = self.to_raw_parts();
679+
state.write_usize(address as usize);
680+
metadata.hash(state);
681+
}
682+
#[cfg(bootstrap)]
683+
{
684+
if mem::size_of::<Self>() == mem::size_of::<usize>() {
685+
// Thin pointer
686+
state.write_usize(*self as *const () as usize);
687+
} else {
688+
// Fat pointer
689+
// SAFETY: we are accessing the memory occupied by `self`
690+
// which is guaranteed to be valid.
691+
// This assumes a fat pointer can be represented by a `(usize, usize)`,
692+
// which is safe to do in `std` because it is shipped and kept in sync
693+
// with the implementation of fat pointers in `rustc`.
694+
let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
695+
state.write_usize(a);
696+
state.write_usize(b);
697+
}
689698
}
690699
}
691700
}
692701

693702
#[stable(feature = "rust1", since = "1.0.0")]
694703
impl<T: ?Sized> Hash for *mut T {
695704
fn hash<H: Hasher>(&self, state: &mut H) {
696-
if mem::size_of::<Self>() == mem::size_of::<usize>() {
697-
// Thin pointer
698-
state.write_usize(*self as *const () as usize);
699-
} else {
700-
// Fat pointer
701-
// SAFETY: we are accessing the memory occupied by `self`
702-
// which is guaranteed to be valid.
703-
// This assumes a fat pointer can be represented by a `(usize, usize)`,
704-
// which is safe to do in `std` because it is shipped and kept in sync
705-
// with the implementation of fat pointers in `rustc`.
706-
let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
707-
state.write_usize(a);
708-
state.write_usize(b);
705+
#[cfg(not(bootstrap))]
706+
{
707+
let (address, metadata) = self.to_raw_parts();
708+
state.write_usize(address as usize);
709+
metadata.hash(state);
710+
}
711+
#[cfg(bootstrap)]
712+
{
713+
if mem::size_of::<Self>() == mem::size_of::<usize>() {
714+
// Thin pointer
715+
state.write_usize(*self as *const () as usize);
716+
} else {
717+
// Fat pointer
718+
// SAFETY: we are accessing the memory occupied by `self`
719+
// which is guaranteed to be valid.
720+
// This assumes a fat pointer can be represented by a `(usize, usize)`,
721+
// which is safe to do in `std` because it is shipped and kept in sync
722+
// with the implementation of fat pointers in `rustc`.
723+
let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
724+
state.write_usize(a);
725+
state.write_usize(b);
726+
}
709727
}
710728
}
711729
}

library/core/src/ptr/const_ptr.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -916,9 +916,14 @@ impl<T> *const [T] {
916916
#[unstable(feature = "slice_ptr_len", issue = "71146")]
917917
#[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
918918
pub const fn len(self) -> usize {
919-
// SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
920-
// Only `std` can make this guarantee.
921-
unsafe { Repr { rust: self }.raw }.len
919+
#[cfg(bootstrap)]
920+
{
921+
// SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
922+
// Only `std` can make this guarantee.
923+
unsafe { Repr { rust: self }.raw }.len
924+
}
925+
#[cfg(not(bootstrap))]
926+
metadata(self)
922927
}
923928

924929
/// Returns a raw pointer to the slice's buffer.

library/core/src/ptr/mod.rs

+23-7
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ pub use crate::intrinsics::write_bytes;
8585
#[cfg(not(bootstrap))]
8686
mod metadata;
8787
#[cfg(not(bootstrap))]
88+
pub(crate) use metadata::PtrRepr;
89+
#[cfg(not(bootstrap))]
8890
#[unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
8991
pub use metadata::{from_raw_parts, from_raw_parts_mut, metadata, DynMetadata, Pointee, Thin};
9092

@@ -226,26 +228,30 @@ pub const fn null_mut<T>() -> *mut T {
226228
0 as *mut T
227229
}
228230

231+
#[cfg(bootstrap)]
229232
#[repr(C)]
230233
pub(crate) union Repr<T> {
231234
pub(crate) rust: *const [T],
232235
rust_mut: *mut [T],
233236
pub(crate) raw: FatPtr<T>,
234237
}
235238

239+
#[cfg(bootstrap)]
236240
#[repr(C)]
237241
pub(crate) struct FatPtr<T> {
238242
data: *const T,
239243
pub(crate) len: usize,
240244
}
241245

246+
#[cfg(bootstrap)]
242247
// Manual impl needed to avoid `T: Clone` bound.
243248
impl<T> Clone for FatPtr<T> {
244249
fn clone(&self) -> Self {
245250
*self
246251
}
247252
}
248253

254+
#[cfg(bootstrap)]
249255
// Manual impl needed to avoid `T: Copy` bound.
250256
impl<T> Copy for FatPtr<T> {}
251257

@@ -273,10 +279,15 @@ impl<T> Copy for FatPtr<T> {}
273279
#[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
274280
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
275281
pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
276-
// SAFETY: Accessing the value from the `Repr` union is safe since *const [T]
277-
// and FatPtr have the same memory layouts. Only std can make this
278-
// guarantee.
279-
unsafe { Repr { raw: FatPtr { data, len } }.rust }
282+
#[cfg(bootstrap)]
283+
{
284+
// SAFETY: Accessing the value from the `Repr` union is safe since *const [T]
285+
// and FatPtr have the same memory layouts. Only std can make this
286+
// guarantee.
287+
unsafe { Repr { raw: FatPtr { data, len } }.rust }
288+
}
289+
#[cfg(not(bootstrap))]
290+
from_raw_parts(data.cast(), len)
280291
}
281292

282293
/// Performs the same functionality as [`slice_from_raw_parts`], except that a
@@ -308,9 +319,14 @@ pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
308319
#[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
309320
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
310321
pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
311-
// SAFETY: Accessing the value from the `Repr` union is safe since *mut [T]
312-
// and FatPtr have the same memory layouts
313-
unsafe { Repr { raw: FatPtr { data, len } }.rust_mut }
322+
#[cfg(bootstrap)]
323+
{
324+
// SAFETY: Accessing the value from the `Repr` union is safe since *mut [T]
325+
// and FatPtr have the same memory layouts
326+
unsafe { Repr { raw: FatPtr { data, len } }.rust_mut }
327+
}
328+
#[cfg(not(bootstrap))]
329+
from_raw_parts_mut(data.cast(), len)
314330
}
315331

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

library/core/src/ptr/mut_ptr.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -1173,9 +1173,14 @@ impl<T> *mut [T] {
11731173
#[unstable(feature = "slice_ptr_len", issue = "71146")]
11741174
#[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
11751175
pub const fn len(self) -> usize {
1176-
// SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
1177-
// Only `std` can make this guarantee.
1178-
unsafe { Repr { rust_mut: self }.raw }.len
1176+
#[cfg(bootstrap)]
1177+
{
1178+
// SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
1179+
// Only `std` can make this guarantee.
1180+
unsafe { Repr { rust_mut: self }.raw }.len
1181+
}
1182+
#[cfg(not(bootstrap))]
1183+
metadata(self)
11791184
}
11801185

11811186
/// Returns a raw pointer to the slice's buffer.

library/core/src/slice/mod.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,23 @@ impl<T> [T] {
9494
// SAFETY: const sound because we transmute out the length field as a usize (which it must be)
9595
#[rustc_allow_const_fn_unstable(const_fn_union)]
9696
pub const fn len(&self) -> usize {
97-
// SAFETY: this is safe because `&[T]` and `FatPtr<T>` have the same layout.
98-
// Only `std` can make this guarantee.
99-
unsafe { crate::ptr::Repr { rust: self }.raw.len }
97+
#[cfg(bootstrap)]
98+
{
99+
// SAFETY: this is safe because `&[T]` and `FatPtr<T>` have the same layout.
100+
// Only `std` can make this guarantee.
101+
unsafe { crate::ptr::Repr { rust: self }.raw.len }
102+
}
103+
#[cfg(not(bootstrap))]
104+
{
105+
// FIXME: Replace with `crate::ptr::metadata(self)` when that is const-stable.
106+
// As of this writing this causes a "Const-stable functions can only call other
107+
// const-stable functions" error.
108+
109+
// SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
110+
// and PtrComponents<T> have the same memory layouts. Only std can make this
111+
// guarantee.
112+
unsafe { crate::ptr::PtrRepr { const_ptr: self }.components.metadata }
113+
}
100114
}
101115

102116
/// Returns `true` if the slice has a length of 0.

0 commit comments

Comments
 (0)