diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 948d7f0b039..5b5a403e719 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -2,7 +2,6 @@ use crate::fmt; use crate::hash::{Hash, Hasher}; -use crate::ptr::NonNull; /// FIXME docs #[lang = "pointee_trait"] @@ -62,17 +61,48 @@ fn clone(&self) -> Self { /// The metadata for a `dyn SomeTrait` trait object type. #[lang = "dyn_metadata"] pub struct DynMetadata { - #[allow(unused)] - vtable_ptr: NonNull<()>, + vtable_ptr: &'static VTable, phantom: crate::marker::PhantomData, } +/// The common prefix of all vtables. It is followed by function pointers for trait methods. +/// +/// Private implementation detail of `DynMetadata::size_of` etc. +#[repr(C)] +struct VTable { + drop_in_place: fn(*mut ()), + size_of: usize, + align_of: usize, +} + +impl DynMetadata { + /// Returns the size of the type associated with this vtable. + #[inline] + pub fn size_of(self) -> usize { + self.vtable_ptr.size_of + } + + /// Returns the alignment of the type associated with this vtable. + #[inline] + pub fn align_of(self) -> usize { + self.vtable_ptr.align_of + } + + /// Returns the size and alignment together as a `Layout` + #[inline] + pub fn layout(self) -> crate::alloc::Layout { + // SAFETY: the compiler emitted this vtable for a concrete Rust type which + // is known to have a valid layout. Same rationale as in `Layout::for_value`. + unsafe { crate::alloc::Layout::from_size_align_unchecked(self.size_of(), self.align_of()) } + } +} + unsafe impl Send for DynMetadata {} unsafe impl Sync for DynMetadata {} impl fmt::Debug for DynMetadata { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("DynMetadata { … }") + f.debug_tuple("DynMetadata").field(&(self.vtable_ptr as *const VTable)).finish() } } @@ -94,27 +124,27 @@ impl Eq for DynMetadata {} impl PartialEq for DynMetadata { #[inline] fn eq(&self, other: &Self) -> bool { - self.vtable_ptr == other.vtable_ptr + crate::ptr::eq::(self.vtable_ptr, other.vtable_ptr) } } impl Ord for DynMetadata { #[inline] fn cmp(&self, other: &Self) -> crate::cmp::Ordering { - self.vtable_ptr.cmp(&other.vtable_ptr) + (self.vtable_ptr as *const VTable).cmp(&(other.vtable_ptr as *const VTable)) } } impl PartialOrd for DynMetadata { #[inline] fn partial_cmp(&self, other: &Self) -> Option { - Some(self.vtable_ptr.cmp(&other.vtable_ptr)) + Some(self.cmp(other)) } } impl Hash for DynMetadata { #[inline] fn hash(&self, hasher: &mut H) { - self.vtable_ptr.hash(hasher) + crate::ptr::hash::(self.vtable_ptr, hasher) } } diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index ff3db740dfd..26fafd01806 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -505,3 +505,23 @@ fn static_assert_expected_bounds_for_metadata() { } } + +#[test] +#[cfg(not(bootstrap))] +fn dyn_metadata() { + #[derive(Debug)] + #[repr(align(32))] + struct Something([u8; 47]); + + let value = Something([0; 47]); + let trait_object: &dyn Debug = &value; + let meta = metadata(trait_object); + + assert_eq!(meta.size_of(), 64); + assert_eq!(meta.size_of(), std::mem::size_of::()); + assert_eq!(meta.align_of(), 32); + assert_eq!(meta.align_of(), std::mem::align_of::()); + assert_eq!(meta.layout(), std::alloc::Layout::new::()); + + assert!(format!("{:?}", meta).starts_with("DynMetadata(0x")); +}