Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

layout_of: T: Thin implies sizeof(&T) == sizeof(usize) #104376

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 43 additions & 22 deletions compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
36 changes: 28 additions & 8 deletions compiler/rustc_ty_utils/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 11 additions & 0 deletions src/test/ui/layout/thin-meta-implies-thin-ptr.rs
Original file line number Diff line number Diff line change
@@ -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) }
}