Use new pointer metadata API inside libcore instead of manual transmutes
This commit is contained in:
parent
c0e3a1b096
commit
787f4de6ab
5 changed files with 100 additions and 42 deletions
|
@ -673,19 +673,28 @@ mod impls {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Hash for *const T {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
if mem::size_of::<Self>() == mem::size_of::<usize>() {
|
||||
// Thin pointer
|
||||
state.write_usize(*self as *const () as usize);
|
||||
} else {
|
||||
// Fat pointer
|
||||
// SAFETY: we are accessing the memory occupied by `self`
|
||||
// which is guaranteed to be valid.
|
||||
// This assumes a fat pointer can be represented by a `(usize, usize)`,
|
||||
// which is safe to do in `std` because it is shipped and kept in sync
|
||||
// with the implementation of fat pointers in `rustc`.
|
||||
let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
|
||||
state.write_usize(a);
|
||||
state.write_usize(b);
|
||||
#[cfg(not(bootstrap))]
|
||||
{
|
||||
let (address, metadata) = self.to_raw_parts();
|
||||
state.write_usize(address as usize);
|
||||
metadata.hash(state);
|
||||
}
|
||||
#[cfg(bootstrap)]
|
||||
{
|
||||
if mem::size_of::<Self>() == mem::size_of::<usize>() {
|
||||
// Thin pointer
|
||||
state.write_usize(*self as *const () as usize);
|
||||
} else {
|
||||
// Fat pointer
|
||||
// SAFETY: we are accessing the memory occupied by `self`
|
||||
// which is guaranteed to be valid.
|
||||
// This assumes a fat pointer can be represented by a `(usize, usize)`,
|
||||
// which is safe to do in `std` because it is shipped and kept in sync
|
||||
// with the implementation of fat pointers in `rustc`.
|
||||
let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
|
||||
state.write_usize(a);
|
||||
state.write_usize(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -693,19 +702,28 @@ mod impls {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Hash for *mut T {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
if mem::size_of::<Self>() == mem::size_of::<usize>() {
|
||||
// Thin pointer
|
||||
state.write_usize(*self as *const () as usize);
|
||||
} else {
|
||||
// Fat pointer
|
||||
// SAFETY: we are accessing the memory occupied by `self`
|
||||
// which is guaranteed to be valid.
|
||||
// This assumes a fat pointer can be represented by a `(usize, usize)`,
|
||||
// which is safe to do in `std` because it is shipped and kept in sync
|
||||
// with the implementation of fat pointers in `rustc`.
|
||||
let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
|
||||
state.write_usize(a);
|
||||
state.write_usize(b);
|
||||
#[cfg(not(bootstrap))]
|
||||
{
|
||||
let (address, metadata) = self.to_raw_parts();
|
||||
state.write_usize(address as usize);
|
||||
metadata.hash(state);
|
||||
}
|
||||
#[cfg(bootstrap)]
|
||||
{
|
||||
if mem::size_of::<Self>() == mem::size_of::<usize>() {
|
||||
// Thin pointer
|
||||
state.write_usize(*self as *const () as usize);
|
||||
} else {
|
||||
// Fat pointer
|
||||
// SAFETY: we are accessing the memory occupied by `self`
|
||||
// which is guaranteed to be valid.
|
||||
// This assumes a fat pointer can be represented by a `(usize, usize)`,
|
||||
// which is safe to do in `std` because it is shipped and kept in sync
|
||||
// with the implementation of fat pointers in `rustc`.
|
||||
let (a, b) = unsafe { *(self as *const Self as *const (usize, usize)) };
|
||||
state.write_usize(a);
|
||||
state.write_usize(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -916,9 +916,14 @@ impl<T> *const [T] {
|
|||
#[unstable(feature = "slice_ptr_len", issue = "71146")]
|
||||
#[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
|
||||
pub const fn len(self) -> usize {
|
||||
// SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
|
||||
// Only `std` can make this guarantee.
|
||||
unsafe { Repr { rust: self }.raw }.len
|
||||
#[cfg(bootstrap)]
|
||||
{
|
||||
// SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
|
||||
// Only `std` can make this guarantee.
|
||||
unsafe { Repr { rust: self }.raw }.len
|
||||
}
|
||||
#[cfg(not(bootstrap))]
|
||||
metadata(self)
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the slice's buffer.
|
||||
|
|
|
@ -85,6 +85,8 @@ pub use crate::intrinsics::write_bytes;
|
|||
#[cfg(not(bootstrap))]
|
||||
mod metadata;
|
||||
#[cfg(not(bootstrap))]
|
||||
pub(crate) use metadata::PtrRepr;
|
||||
#[cfg(not(bootstrap))]
|
||||
#[unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
|
||||
pub use metadata::{from_raw_parts, from_raw_parts_mut, metadata, DynMetadata, Pointee, Thin};
|
||||
|
||||
|
@ -226,6 +228,7 @@ pub const fn null_mut<T>() -> *mut T {
|
|||
0 as *mut T
|
||||
}
|
||||
|
||||
#[cfg(bootstrap)]
|
||||
#[repr(C)]
|
||||
pub(crate) union Repr<T> {
|
||||
pub(crate) rust: *const [T],
|
||||
|
@ -233,12 +236,14 @@ pub(crate) union Repr<T> {
|
|||
pub(crate) raw: FatPtr<T>,
|
||||
}
|
||||
|
||||
#[cfg(bootstrap)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct FatPtr<T> {
|
||||
data: *const T,
|
||||
pub(crate) len: usize,
|
||||
}
|
||||
|
||||
#[cfg(bootstrap)]
|
||||
// Manual impl needed to avoid `T: Clone` bound.
|
||||
impl<T> Clone for FatPtr<T> {
|
||||
fn clone(&self) -> Self {
|
||||
|
@ -246,6 +251,7 @@ impl<T> Clone for FatPtr<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(bootstrap)]
|
||||
// Manual impl needed to avoid `T: Copy` bound.
|
||||
impl<T> Copy for FatPtr<T> {}
|
||||
|
||||
|
@ -273,10 +279,15 @@ impl<T> Copy for FatPtr<T> {}
|
|||
#[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
|
||||
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
|
||||
pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
|
||||
// SAFETY: Accessing the value from the `Repr` union is safe since *const [T]
|
||||
// and FatPtr have the same memory layouts. Only std can make this
|
||||
// guarantee.
|
||||
unsafe { Repr { raw: FatPtr { data, len } }.rust }
|
||||
#[cfg(bootstrap)]
|
||||
{
|
||||
// SAFETY: Accessing the value from the `Repr` union is safe since *const [T]
|
||||
// and FatPtr have the same memory layouts. Only std can make this
|
||||
// guarantee.
|
||||
unsafe { Repr { raw: FatPtr { data, len } }.rust }
|
||||
}
|
||||
#[cfg(not(bootstrap))]
|
||||
from_raw_parts(data.cast(), len)
|
||||
}
|
||||
|
||||
/// 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] {
|
|||
#[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
|
||||
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
|
||||
pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
|
||||
// SAFETY: Accessing the value from the `Repr` union is safe since *mut [T]
|
||||
// and FatPtr have the same memory layouts
|
||||
unsafe { Repr { raw: FatPtr { data, len } }.rust_mut }
|
||||
#[cfg(bootstrap)]
|
||||
{
|
||||
// SAFETY: Accessing the value from the `Repr` union is safe since *mut [T]
|
||||
// and FatPtr have the same memory layouts
|
||||
unsafe { Repr { raw: FatPtr { data, len } }.rust_mut }
|
||||
}
|
||||
#[cfg(not(bootstrap))]
|
||||
from_raw_parts_mut(data.cast(), len)
|
||||
}
|
||||
|
||||
/// Swaps the values at two mutable locations of the same type, without
|
||||
|
|
|
@ -1173,9 +1173,14 @@ impl<T> *mut [T] {
|
|||
#[unstable(feature = "slice_ptr_len", issue = "71146")]
|
||||
#[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
|
||||
pub const fn len(self) -> usize {
|
||||
// SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
|
||||
// Only `std` can make this guarantee.
|
||||
unsafe { Repr { rust_mut: self }.raw }.len
|
||||
#[cfg(bootstrap)]
|
||||
{
|
||||
// SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
|
||||
// Only `std` can make this guarantee.
|
||||
unsafe { Repr { rust_mut: self }.raw }.len
|
||||
}
|
||||
#[cfg(not(bootstrap))]
|
||||
metadata(self)
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the slice's buffer.
|
||||
|
|
|
@ -94,9 +94,23 @@ impl<T> [T] {
|
|||
// SAFETY: const sound because we transmute out the length field as a usize (which it must be)
|
||||
#[rustc_allow_const_fn_unstable(const_fn_union)]
|
||||
pub const fn len(&self) -> usize {
|
||||
// SAFETY: this is safe because `&[T]` and `FatPtr<T>` have the same layout.
|
||||
// Only `std` can make this guarantee.
|
||||
unsafe { crate::ptr::Repr { rust: self }.raw.len }
|
||||
#[cfg(bootstrap)]
|
||||
{
|
||||
// SAFETY: this is safe because `&[T]` and `FatPtr<T>` have the same layout.
|
||||
// Only `std` can make this guarantee.
|
||||
unsafe { crate::ptr::Repr { rust: self }.raw.len }
|
||||
}
|
||||
#[cfg(not(bootstrap))]
|
||||
{
|
||||
// FIXME: Replace with `crate::ptr::metadata(self)` when that is const-stable.
|
||||
// As of this writing this causes a "Const-stable functions can only call other
|
||||
// const-stable functions" error.
|
||||
|
||||
// SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
|
||||
// and PtrComponents<T> have the same memory layouts. Only std can make this
|
||||
// guarantee.
|
||||
unsafe { crate::ptr::PtrRepr { const_ptr: self }.components.metadata }
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the slice has a length of 0.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue