@@ -407,25 +407,41 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
407407 }
408408 // cannot use the shim here, because that will only result in infinite recursion
409409 ty:: InstanceDef :: Virtual ( _, idx) => {
410+ let mut args = args. to_vec ( ) ;
410411 let ptr_size = self . pointer_size ( ) ;
411- let ptr = self . deref_operand ( args[ 0 ] ) ?;
412- let vtable = ptr. vtable ( ) ?;
412+ // We have to implement all "object safe receivers". Currently we
413+ // support built-in pointers (&, &mut, Box) as well as unsized-self. We do
414+ // not yet support custom self types.
415+ // Also see librustc_codegen_llvm/abi.rs and librustc_codegen_llvm/mir/block.rs.
416+ let receiver_place = match args[ 0 ] . layout . ty . builtin_deref ( true ) {
417+ Some ( _) => {
418+ // Built-in pointer.
419+ self . deref_operand ( args[ 0 ] ) ?
420+ }
421+ None => {
422+ // Unsized self.
423+ args[ 0 ] . to_mem_place ( )
424+ }
425+ } ;
426+ // Find and consult vtable
427+ let vtable = receiver_place. vtable ( ) ?;
413428 self . memory . check_align ( vtable. into ( ) , self . tcx . data_layout . pointer_align . abi ) ?;
414429 let fn_ptr = self . memory . get ( vtable. alloc_id ) ?. read_ptr_sized (
415430 self ,
416431 vtable. offset ( ptr_size * ( idx as u64 + 3 ) , self ) ?,
417432 ) ?. to_ptr ( ) ?;
418433 let instance = self . memory . get_fn ( fn_ptr) ?;
419434
420- // We have to patch the self argument, in particular get the layout
421- // expected by the actual function. Cannot just use "field 0" due to
422- // Box<self>.
423- let mut args = args. to_vec ( ) ;
424- let pointee = args[ 0 ] . layout . ty . builtin_deref ( true ) . unwrap ( ) . ty ;
425- let fake_fat_ptr_ty = self . tcx . mk_mut_ptr ( pointee) ;
426- args[ 0 ] = OpTy :: from ( ImmTy { // strip vtable
427- layout : self . layout_of ( fake_fat_ptr_ty) ?. field ( self , 0 ) ?,
428- imm : Immediate :: Scalar ( ptr. ptr . into ( ) )
435+ // `*mut receiver_place.layout.ty` is almost the layout that we
436+ // want for args[0]: We have to project to field 0 because we want
437+ // a thin pointer.
438+ assert ! ( receiver_place. layout. is_unsized( ) ) ;
439+ let receiver_ptr_ty = self . tcx . mk_mut_ptr ( receiver_place. layout . ty ) ;
440+ let this_receiver_ptr = self . layout_of ( receiver_ptr_ty) ?. field ( self , 0 ) ?;
441+ // Adjust receiver argument.
442+ args[ 0 ] = OpTy :: from ( ImmTy {
443+ layout : this_receiver_ptr,
444+ imm : Immediate :: Scalar ( receiver_place. ptr . into ( ) )
429445 } ) ;
430446 trace ! ( "Patched self operand to {:#?}" , args[ 0 ] ) ;
431447 // recurse with concrete function
0 commit comments