Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What if DynMetadata wasn't special? #125532

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 2 additions & 15 deletions compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -853,23 +853,10 @@ where
// fall back to structurally deducing metadata.
&& !pointee.references_error()
{
let metadata = tcx.normalize_erasing_regions(
tcx.normalize_erasing_regions(
cx.param_env(),
Ty::new_projection(tcx, metadata_def_id, [pointee]),
);

// Map `Metadata = DynMetadata<dyn Trait>` back to a vtable, since it
// offers better information than `std::ptr::metadata::VTable`,
// and we rely on this layout information to trigger a panic in
// `std::mem::uninitialized::<&dyn Trait>()`, for example.
if let ty::Adt(def, args) = metadata.kind()
&& Some(def.did()) == tcx.lang_items().dyn_metadata()
&& args.type_at(0).is_trait()
{
mk_dyn_vtable()
} else {
metadata
}
)
} else {
match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
ty::Slice(_) | ty::Str => tcx.types.usize,
Expand Down
9 changes: 0 additions & 9 deletions compiler/rustc_mir_transform/src/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -685,15 +685,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
check_equal(self, location, *f_ty);
}
ty::Adt(adt_def, args) => {
// see <https://github.com/rust-lang/rust/blob/7601adcc764d42c9f2984082b49948af652df986/compiler/rustc_middle/src/ty/layout.rs#L861-L864>
if Some(adt_def.did()) == self.tcx.lang_items().dyn_metadata() {
self.fail(
location,
format!("You can't project to field {f:?} of `DynMetadata` because \
layout is weird and thinks it doesn't have fields."),
);
}

let var = parent_ty.variant_index.unwrap_or(FIRST_VARIANT);
let Some(field) = adt_def.variant(var).fields.get(f) else {
fail_out_of_bounds(self, location);
Expand Down
40 changes: 15 additions & 25 deletions library/core/src/ptr/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,31 +177,21 @@ impl<T: ?Sized> Clone for PtrComponents<T> {
/// duplicated in multiple codegen units), and pointers to vtables of *different* types/traits can
/// compare equal (since identical vtables can be deduplicated within a codegen unit).
#[lang = "dyn_metadata"]
// codegen assumes it can treat this as a single pointer
#[repr(transparent)]
pub struct DynMetadata<Dyn: ?Sized> {
_vtable_ptr: &'static VTable,
_phantom: crate::marker::PhantomData<Dyn>,
vtable_ptr: &'static VTable,
phantom: crate::marker::PhantomData<Dyn>,
}

extern "C" {
/// Opaque type for accessing vtables.
///
/// Private implementation detail of `DynMetadata::size_of` etc.
/// There is conceptually not actually any Abstract Machine memory behind this pointer.
type VTable;
/// This is not really what's behind a vtable, but the codegen tests want the
/// pointers to get `dereferencable` metadata, for example, and there's currently
/// no way to get that with `extern type`, which would otherwise be nicer.
struct VTable {
_stub: usize,
}

impl<Dyn: ?Sized> DynMetadata<Dyn> {
/// One of the things that rustc_middle does with this being a lang item is
/// give it `FieldsShape::Primitive`, which means that as far as codegen can
/// tell, it *is* a reference, and thus doesn't have any fields.
/// That means we can't use field access, and have to transmute it instead.
#[inline]
fn vtable_ptr(self) -> *const VTable {
// SAFETY: this layout assumption is hard-coded into the compiler.
// If it's somehow not a size match, the transmute will error.
unsafe { crate::mem::transmute::<Self, &'static VTable>(self) }
}

/// Returns the size of the type associated with this vtable.
#[inline]
pub fn size_of(self) -> usize {
Expand All @@ -210,7 +200,7 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> {
// `Send` part!
// SAFETY: DynMetadata always contains a valid vtable pointer
return unsafe {
crate::intrinsics::vtable_size(self.vtable_ptr() as *const ())
crate::intrinsics::vtable_size(self.vtable_ptr as *const VTable as *const ())
};
}

Expand All @@ -219,7 +209,7 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> {
pub fn align_of(self) -> usize {
// SAFETY: DynMetadata always contains a valid vtable pointer
return unsafe {
crate::intrinsics::vtable_align(self.vtable_ptr() as *const ())
crate::intrinsics::vtable_align(self.vtable_ptr as *const VTable as *const ())
};
}

Expand All @@ -237,7 +227,7 @@ unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}

impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("DynMetadata").field(&self.vtable_ptr()).finish()
f.debug_tuple("DynMetadata").field(&(self.vtable_ptr as *const VTable)).finish()
}
}

Expand All @@ -259,15 +249,15 @@ impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {}
impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
#[inline]
fn eq(&self, other: &Self) -> bool {
crate::ptr::eq::<VTable>(self.vtable_ptr(), other.vtable_ptr())
crate::ptr::eq::<VTable>(self.vtable_ptr, other.vtable_ptr)
}
}

impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
#[inline]
#[allow(ambiguous_wide_pointer_comparisons)]
fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
<*const VTable>::cmp(&self.vtable_ptr(), &other.vtable_ptr())
(self.vtable_ptr as *const VTable).cmp(&(other.vtable_ptr as *const VTable))
}
}

Expand All @@ -281,6 +271,6 @@ impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {
impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {
#[inline]
fn hash<H: Hasher>(&self, hasher: &mut H) {
crate::ptr::hash::<VTable, _>(self.vtable_ptr(), hasher)
crate::ptr::hash::<VTable, _>(self.vtable_ptr, hasher)
}
}
Loading