Miri: implement arbitrary-self dyn receivers
This commit is contained in:
parent
461e807801
commit
fa5fa72fe1
@ -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
|
// cannot use the shim here, because that will only result in infinite recursion
|
||||||
ty::InstanceDef::Virtual(_, idx) => {
|
ty::InstanceDef::Virtual(_, idx) => {
|
||||||
let mut args = args.to_vec();
|
let mut args = args.to_vec();
|
||||||
// We have to implement all "object safe receivers". Currently we
|
// We have to implement all "object safe receivers". So we have to go search for a
|
||||||
// support built-in pointers `(&, &mut, Box)` as well as unsized-self. We do
|
// pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively
|
||||||
// not yet support custom self types.
|
// unwrap those newtypes until we are there.
|
||||||
// Also see `compiler/rustc_codegen_llvm/src/abi.rs` and `compiler/rustc_codegen_ssa/src/mir/block.rs`.
|
let mut receiver = args[0];
|
||||||
let receiver_place = match args[0].layout.ty.builtin_deref(true) {
|
let receiver_place = loop {
|
||||||
Some(_) => {
|
match receiver.layout.ty.kind() {
|
||||||
// Built-in pointer.
|
ty::Ref(..) | ty::RawPtr(..) => break self.deref_operand(&receiver)?,
|
||||||
self.deref_operand(&args[0])?
|
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
|
||||||
|
)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
None => {
|
|
||||||
// Unsized self.
|
|
||||||
args[0].assert_mem_place()
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Find and consult vtable
|
// Find and consult vtable. The type now could be something like RcBox<dyn Trait>,
|
||||||
let vtable = self.scalar_to_ptr(receiver_place.vtable());
|
// 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())?;
|
let fn_val = self.get_vtable_slot(vtable, u64::try_from(idx).unwrap())?;
|
||||||
|
|
||||||
// `*mut receiver_place.layout.ty` is almost the layout that we
|
// `*mut receiver_place.layout.ty` is almost the layout that we
|
||||||
@ -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(),
|
Scalar::from_maybe_pointer(receiver_place.ptr, self).into(),
|
||||||
this_receiver_ptr,
|
this_receiver_ptr,
|
||||||
));
|
));
|
||||||
trace!("Patched self operand to {:#?}", args[0]);
|
trace!("Patched receiver operand to {:#?}", args[0]);
|
||||||
// recurse with concrete function
|
// recurse with concrete function
|
||||||
self.eval_fn_call(
|
self.eval_fn_call(
|
||||||
fn_val,
|
fn_val,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user