about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2022-03-18 08:48:34 -0400
committerRalf Jung <post@ralfj.de>2022-03-18 08:50:30 -0400
commitfa5fa72fe1c7c29f3a52f9be14a2ed0acb03b5ce (patch)
tree6de9c5b2c18f28c4284a8b7dbd0a2356f5c6c374 /compiler
parent461e8078010433ff7de2db2aaae8a3cfb0847215 (diff)
downloadrust-fa5fa72fe1c7c29f3a52f9be14a2ed0acb03b5ce.tar.gz
rust-fa5fa72fe1c7c29f3a52f9be14a2ed0acb03b5ce.zip
Miri: implement arbitrary-self dyn receivers
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs55
1 files changed, 40 insertions, 15 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index d2fbd6a9654..57a93ed4d55 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -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
@@ -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,