diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 3a2b2c5f3002d..66cc65de64709 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -685,6 +685,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { check_equal(self, location, *f_ty); } ty::Adt(adt_def, args) => { + // see + 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); diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index eb815b6d822c5..e501970b580de 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -178,8 +178,8 @@ impl Clone for PtrComponents { /// compare equal (since identical vtables can be deduplicated within a codegen unit). #[lang = "dyn_metadata"] pub struct DynMetadata { - vtable_ptr: &'static VTable, - phantom: crate::marker::PhantomData, + _vtable_ptr: &'static VTable, + _phantom: crate::marker::PhantomData, } extern "C" { @@ -191,6 +191,17 @@ extern "C" { } impl DynMetadata { + /// 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) } + } + /// Returns the size of the type associated with this vtable. #[inline] pub fn size_of(self) -> usize { @@ -199,7 +210,7 @@ impl DynMetadata { // `Send` part! // SAFETY: DynMetadata always contains a valid vtable pointer return unsafe { - crate::intrinsics::vtable_size(self.vtable_ptr as *const VTable as *const ()) + crate::intrinsics::vtable_size(self.vtable_ptr() as *const ()) }; } @@ -208,7 +219,7 @@ impl DynMetadata { 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 VTable as *const ()) + crate::intrinsics::vtable_align(self.vtable_ptr() as *const ()) }; } @@ -226,7 +237,7 @@ unsafe impl Sync for DynMetadata {} impl fmt::Debug for DynMetadata { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("DynMetadata").field(&(self.vtable_ptr as *const VTable)).finish() + f.debug_tuple("DynMetadata").field(&self.vtable_ptr()).finish() } } @@ -248,7 +259,7 @@ impl Eq for DynMetadata {} impl PartialEq for DynMetadata { #[inline] fn eq(&self, other: &Self) -> bool { - crate::ptr::eq::(self.vtable_ptr, other.vtable_ptr) + crate::ptr::eq::(self.vtable_ptr(), other.vtable_ptr()) } } @@ -256,7 +267,7 @@ impl Ord for DynMetadata { #[inline] #[allow(ambiguous_wide_pointer_comparisons)] fn cmp(&self, other: &Self) -> crate::cmp::Ordering { - (self.vtable_ptr as *const VTable).cmp(&(other.vtable_ptr as *const VTable)) + <*const VTable>::cmp(&self.vtable_ptr(), &other.vtable_ptr()) } } @@ -270,6 +281,6 @@ impl PartialOrd for DynMetadata { impl Hash for DynMetadata { #[inline] fn hash(&self, hasher: &mut H) { - crate::ptr::hash::(self.vtable_ptr, hasher) + crate::ptr::hash::(self.vtable_ptr(), hasher) } }