@@ -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