diff options
| author | bors <bors@rust-lang.org> | 2023-01-04 06:28:05 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-01-04 06:28:05 +0000 |
| commit | ddad1e1f15f77074738bb3d7fb7688a9177b6450 (patch) | |
| tree | 805c0c24682e69fc40fba1ff446aa1a8a8f8d6ee | |
| parent | c361616c3ca3e3e3069dbdf90557181233387444 (diff) | |
| parent | a5d39cf290d9762d982b6930f10fb4dd34119c3f (diff) | |
| download | rust-ddad1e1f15f77074738bb3d7fb7688a9177b6450.tar.gz rust-ddad1e1f15f77074738bb3d7fb7688a9177b6450.zip | |
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.
| -rw-r--r-- | compiler/rustc_middle/src/ty/layout.rs | 65 | ||||
| -rw-r--r-- | compiler/rustc_ty_utils/src/layout.rs | 36 | ||||
| -rw-r--r-- | src/test/ui/layout/thin-meta-implies-thin-ptr.rs | 11 |
3 files changed, 82 insertions, 30 deletions
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 9e0ca44d098..00f53afd663 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -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. diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index c8c6acaa453..6aa016133ca 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 00000000000..972579ea8be --- /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: ?Sized + Thin>(t: *const T) -> *const () { + unsafe { std::mem::transmute(t) } +} |
