diff options
| author | bors <bors@rust-lang.org> | 2022-03-20 13:48:23 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-03-20 13:48:23 +0000 |
| commit | 9bd53718e2537d95d8c092609618c2dcd6f05127 (patch) | |
| tree | d2d0f21ef4c3baa836cf9737d810a18107f3aa17 | |
| parent | c7ce69faf2a7ea16c15d922985ca27ba70da30ee (diff) | |
| parent | fa5fa72fe1c7c29f3a52f9be14a2ed0acb03b5ce (diff) | |
| download | rust-9bd53718e2537d95d8c092609618c2dcd6f05127.tar.gz rust-9bd53718e2537d95d8c092609618c2dcd6f05127.zip | |
Auto merge of #95071 - RalfJung:arbitrary-self-dyn, r=oli-obk
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 https://github.com/rust-lang/miri/issues/1038 r? `@oli-obk` Cc `@eddyb`
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/terminator.rs | 55 |
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, |
