@@ -476,22 +476,47 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
476
476
// cannot use the shim here, because that will only result in infinite recursion
477
477
ty:: InstanceDef :: Virtual ( _, idx) => {
478
478
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
+ }
491
508
}
492
509
} ;
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 ( ) ) ;
495
520
let fn_val = self . get_vtable_slot ( vtable, u64:: try_from ( idx) . unwrap ( ) ) ?;
496
521
497
522
// `*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> {
505
530
Scalar :: from_maybe_pointer ( receiver_place. ptr , self ) . into ( ) ,
506
531
this_receiver_ptr,
507
532
) ) ;
508
- trace ! ( "Patched self operand to {:#?}" , args[ 0 ] ) ;
533
+ trace ! ( "Patched receiver operand to {:#?}" , args[ 0 ] ) ;
509
534
// recurse with concrete function
510
535
self . eval_fn_call (
511
536
fn_val,
0 commit comments