Skip to content

Commit

Permalink
Auto merge of #95071 - RalfJung:arbitrary-self-dyn, r=oli-obk
Browse files Browse the repository at this point in the history
Miri: implement arbitrary-self dyn receivers

Roughly follows the [codegen logic](https://github.com/rust-lang/rust/blob/851fcc7a54262748b1aa9e16de91453998d896f3/compiler/rustc_codegen_ssa/src/mir/block.rs#L809).

Fixes rust-lang/miri#1038
r? `@oli-obk` Cc `@eddyb`
  • Loading branch information
bors committed Mar 20, 2022
2 parents c7ce69f + fa5fa72 commit 9bd5371
Showing 1 changed file with 40 additions and 15 deletions.
55 changes: 40 additions & 15 deletions compiler/rustc_const_eval/src/interpret/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,22 +476,47 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// cannot use the shim here, because that will only result in infinite recursion
ty::InstanceDef::Virtual(_, idx) => {
let mut args = args.to_vec();
// We have to implement all "object safe receivers". Currently we
// support built-in pointers `(&, &mut, Box)` as well as unsized-self. We do
// not yet support custom self types.
// Also see `compiler/rustc_codegen_llvm/src/abi.rs` and `compiler/rustc_codegen_ssa/src/mir/block.rs`.
let receiver_place = match args[0].layout.ty.builtin_deref(true) {
Some(_) => {
// Built-in pointer.
self.deref_operand(&args[0])?
}
None => {
// Unsized self.
args[0].assert_mem_place()
// We have to implement all "object safe receivers". So we have to go search for a
// pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively
// unwrap those newtypes until we are there.
let mut receiver = args[0];
let receiver_place = loop {
match receiver.layout.ty.kind() {
ty::Ref(..) | ty::RawPtr(..) => break self.deref_operand(&receiver)?,
ty::Dynamic(..) => break receiver.assert_mem_place(),
_ => {
// Not there yet, search for the only non-ZST field.
let mut non_zst_field = None;
for i in 0..receiver.layout.fields.count() {
let field = self.operand_field(&receiver, i)?;
if !field.layout.is_zst() {
assert!(
non_zst_field.is_none(),
"multiple non-ZST fields in dyn receiver type {}",
receiver.layout.ty
);
non_zst_field = Some(field);
}
}
receiver = non_zst_field.unwrap_or_else(|| {
panic!(
"no non-ZST fields in dyn receiver type {}",
receiver.layout.ty
)
});
}
}
};
// Find and consult vtable
let vtable = self.scalar_to_ptr(receiver_place.vtable());
// Find and consult vtable. The type now could be something like RcBox<dyn Trait>,
// i.e., it is still not necessarily `ty::Dynamic` (so we cannot use
// `place.vtable()`), but it should have a `dyn Trait` tail.
assert!(matches!(
self.tcx
.struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env)
.kind(),
ty::Dynamic(..)
));
let vtable = self.scalar_to_ptr(receiver_place.meta.unwrap_meta());
let fn_val = self.get_vtable_slot(vtable, u64::try_from(idx).unwrap())?;

// `*mut receiver_place.layout.ty` is almost the layout that we
Expand All @@ -505,7 +530,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Scalar::from_maybe_pointer(receiver_place.ptr, self).into(),
this_receiver_ptr,
));
trace!("Patched self operand to {:#?}", args[0]);
trace!("Patched receiver operand to {:#?}", args[0]);
// recurse with concrete function
self.eval_fn_call(
fn_val,
Expand Down

0 comments on commit 9bd5371

Please sign in to comment.