Skip to content

Commit fa5fa72

Browse files
committed
Miri: implement arbitrary-self dyn receivers
1 parent 461e807 commit fa5fa72

File tree

1 file changed

+40
-15
lines changed

1 file changed

+40
-15
lines changed

compiler/rustc_const_eval/src/interpret/terminator.rs

+40-15
Original file line numberDiff line numberDiff line change
@@ -476,22 +476,47 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
476476
// cannot use the shim here, because that will only result in infinite recursion
477477
ty::InstanceDef::Virtual(_, idx) => {
478478
let mut args = args.to_vec();
479-
// We have to implement all "object safe receivers". Currently we
480-
// support built-in pointers `(&, &mut, Box)` as well as unsized-self. We do
481-
// not yet support custom self types.
482-
// Also see `compiler/rustc_codegen_llvm/src/abi.rs` and `compiler/rustc_codegen_ssa/src/mir/block.rs`.
483-
let receiver_place = match args[0].layout.ty.builtin_deref(true) {
484-
Some(_) => {
485-
// Built-in pointer.
486-
self.deref_operand(&args[0])?
487-
}
488-
None => {
489-
// Unsized self.
490-
args[0].assert_mem_place()
479+
// We have to implement all "object safe receivers". So we have to go search for a
480+
// pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively
481+
// unwrap those newtypes until we are there.
482+
let mut receiver = args[0];
483+
let receiver_place = loop {
484+
match receiver.layout.ty.kind() {
485+
ty::Ref(..) | ty::RawPtr(..) => break self.deref_operand(&receiver)?,
486+
ty::Dynamic(..) => break receiver.assert_mem_place(),
487+
_ => {
488+
// Not there yet, search for the only non-ZST field.
489+
let mut non_zst_field = None;
490+
for i in 0..receiver.layout.fields.count() {
491+
let field = self.operand_field(&receiver, i)?;
492+
if !field.layout.is_zst() {
493+
assert!(
494+
non_zst_field.is_none(),
495+
"multiple non-ZST fields in dyn receiver type {}",
496+
receiver.layout.ty
497+
);
498+
non_zst_field = Some(field);
499+
}
500+
}
501+
receiver = non_zst_field.unwrap_or_else(|| {
502+
panic!(
503+
"no non-ZST fields in dyn receiver type {}",
504+
receiver.layout.ty
505+
)
506+
});
507+
}
491508
}
492509
};
493-
// Find and consult vtable
494-
let vtable = self.scalar_to_ptr(receiver_place.vtable());
510+
// Find and consult vtable. The type now could be something like RcBox<dyn Trait>,
511+
// i.e., it is still not necessarily `ty::Dynamic` (so we cannot use
512+
// `place.vtable()`), but it should have a `dyn Trait` tail.
513+
assert!(matches!(
514+
self.tcx
515+
.struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env)
516+
.kind(),
517+
ty::Dynamic(..)
518+
));
519+
let vtable = self.scalar_to_ptr(receiver_place.meta.unwrap_meta());
495520
let fn_val = self.get_vtable_slot(vtable, u64::try_from(idx).unwrap())?;
496521

497522
// `*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> {
505530
Scalar::from_maybe_pointer(receiver_place.ptr, self).into(),
506531
this_receiver_ptr,
507532
));
508-
trace!("Patched self operand to {:#?}", args[0]);
533+
trace!("Patched receiver operand to {:#?}", args[0]);
509534
// recurse with concrete function
510535
self.eval_fn_call(
511536
fn_val,

0 commit comments

Comments
 (0)