From b25da9ce6dd28d13c85911e0630d019403b7f5f3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 12 Nov 2022 23:54:39 +0000 Subject: [PATCH 1/3] layout_of: `T: Thin` implies `sizeof(&T) == sizeof(usize)` --- compiler/rustc_ty_utils/src/layout.rs | 36 ++++++++++++++----- .../ui/layout/thin-meta-implies-thin-ptr.rs | 11 ++++++ 2 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/layout/thin-meta-implies-thin-ptr.rs diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index c8c6acaa45397..6aa016133ca59 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -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. diff --git a/src/test/ui/layout/thin-meta-implies-thin-ptr.rs b/src/test/ui/layout/thin-meta-implies-thin-ptr.rs new file mode 100644 index 0000000000000..972579ea8be0d --- /dev/null +++ b/src/test/ui/layout/thin-meta-implies-thin-ptr.rs @@ -0,0 +1,11 @@ +// check-pass + +#![feature(ptr_metadata)] + +use std::ptr::Thin; + +fn main() {} + +fn foo(t: *const T) -> *const () { + unsafe { std::mem::transmute(t) } +} From 2011316e596c19a8b5ae8cc00102667c2cdb1ef7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 13 Nov 2022 21:49:54 +0000 Subject: [PATCH 2/3] Mirror metadata changes in layout sanity check --- compiler/rustc_middle/src/ty/layout.rs | 52 ++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 9e0ca44d0981d..112f15c6f9e6c 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -670,13 +670,24 @@ 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( + 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` 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() + { + 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 @@ -690,9 +701,36 @@ where tcx.mk_array(Option), ]) */ + } 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) => { + 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), + ]) + */ + } + _ => bug!("TyAndLayout::field({:?}): not applicable", this), + } + }; + + TyMaybeWithLayout::Ty(metadata) } // Arrays and slices. From a5d39cf290d9762d982b6930f10fb4dd34119c3f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 4 Jan 2023 01:02:52 +0000 Subject: [PATCH 3/3] review comment: Deduplicate dyn ty_and_layout_field code --- compiler/rustc_middle/src/ty/layout.rs | 55 +++++++++----------------- 1 file changed, 19 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 112f15c6f9e6c..00f53afd66328 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -670,6 +670,23 @@ where }); } + 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), + ]) + */ + }; + let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() { let metadata = tcx.normalize_erasing_regions( cx.param_env(), @@ -684,48 +701,14 @@ where && Some(def.did()) == tcx.lang_items().dyn_metadata() && substs.type_at(0).is_trait() { - 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), - ]) - */ + mk_dyn_vtable() } else { metadata } } else { match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() { ty::Slice(_) | ty::Str => tcx.types.usize, - ty::Dynamic(_, _, ty::Dyn) => { - 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), - ]) - */ - } + ty::Dynamic(_, _, ty::Dyn) => mk_dyn_vtable(), _ => bug!("TyAndLayout::field({:?}): not applicable", this), } };