From b1e15fa8a29558b1233278f5d6da9ee37e30dcee Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 29 Dec 2020 18:31:22 +0100 Subject: [PATCH] Parameterize `DynMetadata` over its `dyn SomeTrait` type --- compiler/rustc_middle/src/ty/sty.rs | 5 ++- library/core/src/ptr/metadata.rs | 55 +++++++++++++++++++++++++---- library/core/tests/ptr.rs | 35 ++++++++++-------- 3 files changed, 73 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 3992e570cdc..b534b5ac4d4 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2164,7 +2164,10 @@ impl<'tcx> TyS<'tcx> { | ty::Tuple(..) => tcx.types.unit, ty::Str | ty::Slice(_) => tcx.types.usize, - ty::Dynamic(..) => tcx.type_of(tcx.lang_items().dyn_metadata().unwrap()), + ty::Dynamic(..) => { + let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap(); + tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()]) + }, ty::Projection(_) | ty::Param(_) diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 416b1b860ce..948d7f0b039 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -1,7 +1,7 @@ #![unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")] use crate::fmt; -use crate::hash::Hash; +use crate::hash::{Hash, Hasher}; use crate::ptr::NonNull; /// FIXME docs @@ -61,17 +61,60 @@ impl Clone for PtrComponents { /// The metadata for a `dyn SomeTrait` trait object type. #[lang = "dyn_metadata"] -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct DynMetadata { +pub struct DynMetadata { #[allow(unused)] vtable_ptr: NonNull<()>, + phantom: crate::marker::PhantomData, } -unsafe impl Send for DynMetadata {} -unsafe impl Sync for DynMetadata {} +unsafe impl Send for DynMetadata {} +unsafe impl Sync for DynMetadata {} -impl fmt::Debug for DynMetadata { +impl fmt::Debug for DynMetadata { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("DynMetadata { … }") } } + +// Manual impls needed to avoid `Dyn: $Trait` bounds. + +impl Unpin for DynMetadata {} + +impl Copy for DynMetadata {} + +impl Clone for DynMetadata { + #[inline] + fn clone(&self) -> Self { + *self + } +} + +impl Eq for DynMetadata {} + +impl PartialEq for DynMetadata { + #[inline] + fn eq(&self, other: &Self) -> bool { + 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) + } +} + +impl PartialOrd for DynMetadata { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.vtable_ptr.cmp(&other.vtable_ptr)) + } +} + +impl Hash for DynMetadata { + #[inline] + fn hash(&self, hasher: &mut H) { + self.vtable_ptr.hash(hasher) + } +} diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 03d2be725ef..ff3db740dfd 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -1,6 +1,6 @@ use core::cell::RefCell; use core::ptr::*; -use std::fmt::Display; +use std::fmt::{Debug, Display}; #[test] fn test_const_from_raw_parts() { @@ -452,20 +452,25 @@ fn ptr_metadata() { assert_eq!(metadata(dst_struct), 3_usize); } - let vtable_1: DynMetadata = metadata(&4_u32 as &dyn Display); - let vtable_2: DynMetadata = metadata(&(true, 7_u32) as &(bool, dyn Display)); - let vtable_3: DynMetadata = metadata(&Pair(true, 7_u32) as &Pair); - let vtable_4: DynMetadata = metadata(&4_u16 as &dyn Display); + let vtable_1: DynMetadata = metadata(&4_u16 as &dyn Debug); + let vtable_2: DynMetadata = metadata(&4_u16 as &dyn Display); + let vtable_3: DynMetadata = metadata(&4_u32 as &dyn Display); + let vtable_4: DynMetadata = metadata(&(true, 7_u32) as &(bool, dyn Display)); + let vtable_5: DynMetadata = + metadata(&Pair(true, 7_u32) as &Pair); unsafe { let address_1: usize = std::mem::transmute(vtable_1); let address_2: usize = std::mem::transmute(vtable_2); let address_3: usize = std::mem::transmute(vtable_3); let address_4: usize = std::mem::transmute(vtable_4); - // Same erased type and same trait: same vtable pointer - assert_eq!(address_1, address_2); - assert_eq!(address_1, address_3); - // Different erased type: different vtable pointer - assert_ne!(address_1, address_4); + let address_5: usize = std::mem::transmute(vtable_5); + // Different trait => different vtable pointer + assert_ne!(address_1, address_2); + // Different erased type => different vtable pointer + assert_ne!(address_2, address_3); + // Same erased type and same trait => same vtable pointer + assert_eq!(address_3, address_4); + assert_eq!(address_3, address_5); } } @@ -486,11 +491,11 @@ fn ptr_metadata_bounds() { // For this reason, let’s check here that bounds are satisfied: - static_assert_expected_bounds_for_metadata::<()>(); - static_assert_expected_bounds_for_metadata::(); - static_assert_expected_bounds_for_metadata::(); - fn static_assert_associated_type() { - static_assert_expected_bounds_for_metadata::<::Metadata>() + let _ = static_assert_expected_bounds_for_metadata::<()>; + let _ = static_assert_expected_bounds_for_metadata::; + let _ = static_assert_expected_bounds_for_metadata::>; + fn _static_assert_associated_type() { + let _ = static_assert_expected_bounds_for_metadata::<::Metadata>; } fn static_assert_expected_bounds_for_metadata()