Auto merge of #104376 - compiler-errors:thin-metadata-implies-thin-ptr, r=wesleywiser
layout_of: `T: Thin` implies `sizeof(&T) == sizeof(usize)` Use the `<T as Pointee>::Metadata` associated type to calculate the layout of a pointee's metadata, instead of hard-coding rules about certain types. Maybe this approach is overkill -- we could instead hard-code this approach as a fallback, with the matching on `Slice`/`Dynamic`/etc. happening first Fixes this issue here https://github.com/rust-lang/rust/pull/104338#issuecomment-1312595844 .. But is also useful with transmutes, for example, given the UI test I added below.
This commit is contained in:
commit
ddad1e1f15
@ -670,29 +670,50 @@ where
|
||||
});
|
||||
}
|
||||
|
||||
match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
|
||||
ty::Slice(_) | ty::Str => TyMaybeWithLayout::Ty(tcx.types.usize),
|
||||
ty::Dynamic(_, _, ty::Dyn) => {
|
||||
TyMaybeWithLayout::Ty(tcx.mk_imm_ref(
|
||||
tcx.lifetimes.re_static,
|
||||
tcx.mk_array(tcx.types.usize, 3),
|
||||
))
|
||||
/* FIXME: use actual fn pointers
|
||||
Warning: naively computing the number of entries in the
|
||||
vtable by counting the methods on the trait + methods on
|
||||
all parent traits does not work, because some methods can
|
||||
be not object safe and thus excluded from the vtable.
|
||||
Increase this counter if you tried to implement this but
|
||||
failed to do it without duplicating a lot of code from
|
||||
other places in the compiler: 2
|
||||
tcx.mk_tup(&[
|
||||
tcx.mk_array(tcx.types.usize, 3),
|
||||
tcx.mk_array(Option<fn()>),
|
||||
])
|
||||
*/
|
||||
let mk_dyn_vtable = || {
|
||||
tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3))
|
||||
/* FIXME: use actual fn pointers
|
||||
Warning: naively computing the number of entries in the
|
||||
vtable by counting the methods on the trait + methods on
|
||||
all parent traits does not work, because some methods can
|
||||
be not object safe and thus excluded from the vtable.
|
||||
Increase this counter if you tried to implement this but
|
||||
failed to do it without duplicating a lot of code from
|
||||
other places in the compiler: 2
|
||||
tcx.mk_tup(&[
|
||||
tcx.mk_array(tcx.types.usize, 3),
|
||||
tcx.mk_array(Option<fn()>),
|
||||
])
|
||||
*/
|
||||
};
|
||||
|
||||
let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
|
||||
let metadata = tcx.normalize_erasing_regions(
|
||||
cx.param_env(),
|
||||
tcx.mk_projection(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, substs) = metadata.kind()
|
||||
&& Some(def.did()) == tcx.lang_items().dyn_metadata()
|
||||
&& substs.type_at(0).is_trait()
|
||||
{
|
||||
mk_dyn_vtable()
|
||||
} else {
|
||||
metadata
|
||||
}
|
||||
_ => bug!("TyAndLayout::field({:?}): not applicable", this),
|
||||
}
|
||||
} else {
|
||||
match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
|
||||
ty::Slice(_) | ty::Str => tcx.types.usize,
|
||||
ty::Dynamic(_, _, ty::Dyn) => mk_dyn_vtable(),
|
||||
_ => bug!("TyAndLayout::field({:?}): not applicable", this),
|
||||
}
|
||||
};
|
||||
|
||||
TyMaybeWithLayout::Ty(metadata)
|
||||
}
|
||||
|
||||
// Arrays and slices.
|
||||
|
@ -155,17 +155,37 @@ fn layout_of_uncached<'tcx>(
|
||||
}
|
||||
|
||||
let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
|
||||
let metadata = match unsized_part.kind() {
|
||||
ty::Foreign(..) => {
|
||||
|
||||
let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
|
||||
let metadata_ty = tcx.normalize_erasing_regions(
|
||||
param_env,
|
||||
tcx.mk_projection(metadata_def_id, [pointee]),
|
||||
);
|
||||
let metadata_layout = cx.layout_of(metadata_ty)?;
|
||||
// If the metadata is a 1-zst, then the pointer is thin.
|
||||
if metadata_layout.is_zst() && metadata_layout.align.abi.bytes() == 1 {
|
||||
return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr)));
|
||||
}
|
||||
ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
|
||||
ty::Dynamic(..) => {
|
||||
let mut vtable = scalar_unit(Pointer);
|
||||
vtable.valid_range_mut().start = 1;
|
||||
vtable
|
||||
|
||||
let Abi::Scalar(metadata) = metadata_layout.abi else {
|
||||
return Err(LayoutError::Unknown(unsized_part));
|
||||
};
|
||||
metadata
|
||||
} else {
|
||||
match unsized_part.kind() {
|
||||
ty::Foreign(..) => {
|
||||
return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr)));
|
||||
}
|
||||
ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
|
||||
ty::Dynamic(..) => {
|
||||
let mut vtable = scalar_unit(Pointer);
|
||||
vtable.valid_range_mut().start = 1;
|
||||
vtable
|
||||
}
|
||||
_ => {
|
||||
return Err(LayoutError::Unknown(unsized_part));
|
||||
}
|
||||
}
|
||||
_ => return Err(LayoutError::Unknown(unsized_part)),
|
||||
};
|
||||
|
||||
// Effectively a (ptr, meta) tuple.
|
||||
|
11
src/test/ui/layout/thin-meta-implies-thin-ptr.rs
Normal file
11
src/test/ui/layout/thin-meta-implies-thin-ptr.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(ptr_metadata)]
|
||||
|
||||
use std::ptr::Thin;
|
||||
|
||||
fn main() {}
|
||||
|
||||
fn foo<T: ?Sized + Thin>(t: *const T) -> *const () {
|
||||
unsafe { std::mem::transmute(t) }
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user