Validate the special layout restriction on DynMetadata
This commit is contained in:
parent
5baee04b63
commit
d83f3ca8ca
2 changed files with 28 additions and 8 deletions
|
@ -685,6 +685,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
check_equal(self, location, *f_ty);
|
check_equal(self, location, *f_ty);
|
||||||
}
|
}
|
||||||
ty::Adt(adt_def, args) => {
|
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 var = parent_ty.variant_index.unwrap_or(FIRST_VARIANT);
|
||||||
let Some(field) = adt_def.variant(var).fields.get(f) else {
|
let Some(field) = adt_def.variant(var).fields.get(f) else {
|
||||||
fail_out_of_bounds(self, location);
|
fail_out_of_bounds(self, location);
|
||||||
|
|
|
@ -178,8 +178,8 @@ impl<T: ?Sized> Clone for PtrComponents<T> {
|
||||||
/// compare equal (since identical vtables can be deduplicated within a codegen unit).
|
/// compare equal (since identical vtables can be deduplicated within a codegen unit).
|
||||||
#[lang = "dyn_metadata"]
|
#[lang = "dyn_metadata"]
|
||||||
pub struct DynMetadata<Dyn: ?Sized> {
|
pub struct DynMetadata<Dyn: ?Sized> {
|
||||||
vtable_ptr: &'static VTable,
|
_vtable_ptr: &'static VTable,
|
||||||
phantom: crate::marker::PhantomData<Dyn>,
|
_phantom: crate::marker::PhantomData<Dyn>,
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -191,6 +191,17 @@ extern "C" {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Dyn: ?Sized> DynMetadata<Dyn> {
|
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.
|
/// Returns the size of the type associated with this vtable.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn size_of(self) -> usize {
|
pub fn size_of(self) -> usize {
|
||||||
|
@ -199,7 +210,7 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> {
|
||||||
// `Send` part!
|
// `Send` part!
|
||||||
// SAFETY: DynMetadata always contains a valid vtable pointer
|
// SAFETY: DynMetadata always contains a valid vtable pointer
|
||||||
return unsafe {
|
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<Dyn: ?Sized> DynMetadata<Dyn> {
|
||||||
pub fn align_of(self) -> usize {
|
pub fn align_of(self) -> usize {
|
||||||
// SAFETY: DynMetadata always contains a valid vtable pointer
|
// SAFETY: DynMetadata always contains a valid vtable pointer
|
||||||
return unsafe {
|
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<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
|
||||||
|
|
||||||
impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
|
impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
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<Dyn: ?Sized> Eq for DynMetadata<Dyn> {}
|
||||||
impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
|
impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, other: &Self) -> bool {
|
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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +267,7 @@ impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(ambiguous_wide_pointer_comparisons)]
|
#[allow(ambiguous_wide_pointer_comparisons)]
|
||||||
fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
|
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<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {
|
||||||
impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {
|
impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
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…
Add table
Add a link
Reference in a new issue