From 87b9f244814d03f0308a4e558b0b16efb527522d Mon Sep 17 00:00:00 2001 From: Scott McMurray <scottmcm@users.noreply.github.com> Date: Sun, 21 Apr 2024 16:11:01 -0700 Subject: [PATCH] Add an intrinsic for `ptr::metadata` --- core/src/intrinsics.rs | 15 +++++++++++++++ core/src/ptr/metadata.rs | 21 +++++++++++++++++---- core/tests/ptr.rs | 12 ++++++++++++ 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/core/src/intrinsics.rs b/core/src/intrinsics.rs index 5a2a4c5ae6ebe..89e0b67099519 100644 --- a/core/src/intrinsics.rs +++ b/core/src/intrinsics.rs @@ -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 diff --git a/core/src/ptr/metadata.rs b/core/src/ptr/metadata.rs index e501970b580de..84287ec3f5142 100644 --- a/core/src/ptr/metadata.rs +++ b/core/src/ptr/metadata.rs @@ -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. @@ -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. @@ -132,6 +141,7 @@ 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, @@ -139,15 +149,18 @@ union PtrRepr<T: ?Sized> { } #[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 diff --git a/core/tests/ptr.rs b/core/tests/ptr.rs index 7b55c2bf8a813..e8d05c2483de2 100644 --- a/core/tests/ptr.rs +++ b/core/tests/ptr.rs @@ -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); +}