Skip to content

Commit

Permalink
Add an intrinsic for ptr::metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
scottmcm committed May 28, 2024
1 parent 6fcf130 commit 87b9f24
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 4 deletions.
15 changes: 15 additions & 0 deletions core/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2821,6 +2821,21 @@ impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*mut T> for *mut P {
type Metadata = <P as ptr::Pointee>::Metadata;
}

/// Lowers in MIR to `Rvalue::UnaryOp` with `UnOp::PtrMetadata`.
///
/// This is used to implement functions like `ptr::metadata`.
#[rustc_nounwind]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
#[cfg(not(bootstrap))]
pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *const P) -> M {
// To implement a fallback we'd have to assume the layout of the pointer,
// but the whole point of this intrinsic is that we shouldn't do that.
unreachable!()
}

// Some functions are defined here because they accidentally got made
// available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
// (`transmute` also falls into this category, but it cannot be wrapped due to the
Expand Down
21 changes: 17 additions & 4 deletions core/src/ptr/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::intrinsics::aggregate_raw_ptr;
#[cfg(not(bootstrap))]
use crate::intrinsics::ptr_metadata;
use crate::marker::Freeze;

/// Provides the pointer metadata type of any pointed-to type.
Expand Down Expand Up @@ -94,10 +96,17 @@ pub trait Thin = Pointee<Metadata = ()>;
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
#[inline]
pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
// 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 { PtrRepr { const_ptr: ptr }.components.metadata }
#[cfg(bootstrap)]
{
// 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 { PtrRepr { const_ptr: ptr }.components.metadata }
}
#[cfg(not(bootstrap))]
{
ptr_metadata(ptr)
}
}

/// Forms a (possibly-wide) raw pointer from a data pointer and metadata.
Expand Down Expand Up @@ -132,22 +141,26 @@ pub const fn from_raw_parts_mut<T: ?Sized>(
}

#[repr(C)]
#[cfg(bootstrap)]
union PtrRepr<T: ?Sized> {
const_ptr: *const T,
mut_ptr: *mut T,
components: PtrComponents<T>,
}

#[repr(C)]
#[cfg(bootstrap)]
struct PtrComponents<T: ?Sized> {
data_pointer: *const (),
metadata: <T as Pointee>::Metadata,
}

// Manual impl needed to avoid `T: Copy` bound.
#[cfg(bootstrap)]
impl<T: ?Sized> Copy for PtrComponents<T> {}

// Manual impl needed to avoid `T: Clone` bound.
#[cfg(bootstrap)]
impl<T: ?Sized> Clone for PtrComponents<T> {
fn clone(&self) -> Self {
*self
Expand Down
12 changes: 12 additions & 0 deletions core/tests/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1171,3 +1171,15 @@ fn test_ptr_from_raw_parts_in_const() {
assert_eq!(EMPTY_SLICE_PTR.addr(), 123);
assert_eq!(EMPTY_SLICE_PTR.len(), 456);
}

#[test]
fn test_ptr_metadata_in_const() {
use std::fmt::Debug;

const ARRAY_META: () = std::ptr::metadata::<[u16; 3]>(&[1, 2, 3]);
const SLICE_META: usize = std::ptr::metadata::<[u16]>(&[1, 2, 3]);
const DYN_META: DynMetadata<dyn Debug> = std::ptr::metadata::<dyn Debug>(&[0_u8; 42]);
assert_eq!(ARRAY_META, ());
assert_eq!(SLICE_META, 3);
assert_eq!(DYN_META.size_of(), 42);
}

0 comments on commit 87b9f24

Please sign in to comment.