@@ -538,10 +538,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
538538 // pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively
539539 // unwrap those newtypes until we are there.
540540 let mut receiver = args[ 0 ] . clone ( ) ;
541- let receiver_place = loop {
541+ let receiver = loop {
542542 match receiver. layout . ty . kind ( ) {
543- ty:: Ref ( ..) | ty:: RawPtr ( ..) => break self . deref_operand ( & receiver) ?,
544- ty:: Dynamic ( ..) => break receiver. assert_mem_place ( ) , // no immediate unsized values
543+ ty:: Dynamic ( ..) | ty:: Ref ( ..) | ty:: RawPtr ( ..) => break receiver,
545544 _ => {
546545 // Not there yet, search for the only non-ZST field.
547546 let mut non_zst_field = None ;
@@ -567,39 +566,83 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
567566 }
568567 }
569568 } ;
570- // Obtain the underlying trait we are working on.
571- let receiver_tail = self
572- . tcx
573- . struct_tail_erasing_lifetimes ( receiver_place. layout . ty , self . param_env ) ;
574- let ty:: Dynamic ( data, ..) = receiver_tail. kind ( ) else {
575- span_bug ! ( self . cur_span( ) , "dynamic call on non-`dyn` type {}" , receiver_tail)
576- } ;
577569
578- // Get the required information from the vtable.
579- let vptr = receiver_place. meta . unwrap_meta ( ) . to_pointer ( self ) ?;
580- let ( dyn_ty, dyn_trait) = self . get_ptr_vtable ( vptr) ?;
581- if dyn_trait != data. principal ( ) {
582- throw_ub_format ! (
583- "`dyn` call on a pointer whose vtable does not match its type"
584- ) ;
585- }
570+ // break self.deref_operand(&receiver)?.into();
571+
572+ // Obtain the underlying trait we are working on, and the adjusted receiver argument.
573+ let recv_ty = receiver. layout . ty ;
574+ let ( vptr, dyn_ty, adjusted_receiver) = match recv_ty. kind ( ) {
575+ ty:: Ref ( ..) | ty:: RawPtr ( ..)
576+ if matches ! (
577+ recv_ty. builtin_deref( true ) . unwrap( ) . ty. kind( ) ,
578+ ty:: Dynamic ( _, _, ty:: DynStar )
579+ ) =>
580+ {
581+ let receiver = self . deref_operand ( & receiver) ?;
582+ let ty:: Dynamic ( data, ..) = receiver. layout . ty . kind ( ) else { bug ! ( ) } ;
583+ let ( recv, vptr) = self . unpack_dyn_star ( & receiver. into ( ) ) ?;
584+ let ( dyn_ty, dyn_trait) = self . get_ptr_vtable ( vptr) ?;
585+ if dyn_trait != data. principal ( ) {
586+ throw_ub_format ! (
587+ "`dyn*` call on a pointer whose vtable does not match its type"
588+ ) ;
589+ }
590+ let recv = recv. assert_mem_place ( ) ; // we passed an MPlaceTy to `unpack_dyn_star` so we definitely still have one
591+
592+ ( vptr, dyn_ty, recv. ptr )
593+ }
594+ ty:: Dynamic ( _, _, ty:: DynStar ) => {
595+ // Not clear how to handle this, so far we assume the receiver is always a pointer.
596+ span_bug ! (
597+ self . cur_span( ) ,
598+ "by-value calls on a `dyn*`... are those a thing?"
599+ ) ;
600+ }
601+ _ => {
602+ let receiver_place = match recv_ty. kind ( ) {
603+ ty:: Ref ( ..) | ty:: RawPtr ( ..) => self . deref_operand ( & receiver) ?,
604+ ty:: Dynamic ( _, _, ty:: Dyn ) => receiver. assert_mem_place ( ) , // unsized (`dyn`) cannot be immediate
605+ _ => bug ! ( ) ,
606+ } ;
607+ // Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`.
608+ // (For that reason we also cannot use `unpack_dyn_trait`.)
609+ let receiver_tail = self . tcx . struct_tail_erasing_lifetimes (
610+ receiver_place. layout . ty ,
611+ self . param_env ,
612+ ) ;
613+ let ty:: Dynamic ( data, _, ty:: Dyn ) = receiver_tail. kind ( ) else {
614+ span_bug ! ( self . cur_span( ) , "dynamic call on non-`dyn` type {}" , receiver_tail)
615+ } ;
616+ assert ! ( receiver_place. layout. is_unsized( ) ) ;
617+
618+ // Get the required information from the vtable.
619+ let vptr = receiver_place. meta . unwrap_meta ( ) . to_pointer ( self ) ?;
620+ let ( dyn_ty, dyn_trait) = self . get_ptr_vtable ( vptr) ?;
621+ if dyn_trait != data. principal ( ) {
622+ throw_ub_format ! (
623+ "`dyn` call on a pointer whose vtable does not match its type"
624+ ) ;
625+ }
626+
627+ // It might be surprising that we use a pointer as the receiver even if this
628+ // is a by-val case; this works because by-val passing of an unsized `dyn
629+ // Trait` to a function is actually desugared to a pointer.
630+ ( vptr, dyn_ty, receiver_place. ptr )
631+ }
632+ } ;
586633
587634 // Now determine the actual method to call. We can do that in two different ways and
588635 // compare them to ensure everything fits.
589636 let Some ( ty:: VtblEntry :: Method ( fn_inst) ) = self . get_vtable_entries ( vptr) ?. get ( idx) . copied ( ) else {
590637 throw_ub_format ! ( "`dyn` call trying to call something that is not a method" )
591638 } ;
639+ trace ! ( "Virtual call dispatches to {fn_inst:#?}" ) ;
592640 if cfg ! ( debug_assertions) {
593641 let tcx = * self . tcx ;
594642
595643 let trait_def_id = tcx. trait_of_item ( def_id) . unwrap ( ) ;
596644 let virtual_trait_ref =
597645 ty:: TraitRef :: from_method ( tcx, trait_def_id, instance. substs ) ;
598- assert_eq ! (
599- receiver_tail,
600- virtual_trait_ref. self_ty( ) ,
601- "mismatch in underlying dyn trait computation within Miri and MIR building" ,
602- ) ;
603646 let existential_trait_ref =
604647 ty:: ExistentialTraitRef :: erase_self_ty ( tcx, virtual_trait_ref) ;
605648 let concrete_trait_ref = existential_trait_ref. with_self_ty ( tcx, dyn_ty) ;
@@ -614,17 +657,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
614657 assert_eq ! ( fn_inst, concrete_method) ;
615658 }
616659
617- // `*mut receiver_place.layout.ty` is almost the layout that we
618- // want for args[0]: We have to project to field 0 because we want
619- // a thin pointer.
620- assert ! ( receiver_place. layout. is_unsized( ) ) ;
621- let receiver_ptr_ty = self . tcx . mk_mut_ptr ( receiver_place. layout . ty ) ;
622- let this_receiver_ptr = self . layout_of ( receiver_ptr_ty) ?. field ( self , 0 ) ;
623- // Adjust receiver argument.
624- args[ 0 ] = OpTy :: from ( ImmTy :: from_immediate (
625- Scalar :: from_maybe_pointer ( receiver_place. ptr , self ) . into ( ) ,
626- this_receiver_ptr,
627- ) ) ;
660+ // Adjust receiver argument. Layout can be any (thin) ptr.
661+ args[ 0 ] = ImmTy :: from_immediate (
662+ Scalar :: from_maybe_pointer ( adjusted_receiver, self ) . into ( ) ,
663+ self . layout_of ( self . tcx . mk_mut_ptr ( dyn_ty) ) ?,
664+ )
665+ . into ( ) ;
628666 trace ! ( "Patched receiver operand to {:#?}" , args[ 0 ] ) ;
629667 // recurse with concrete function
630668 self . eval_fn_call (
@@ -653,15 +691,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
653691 // implementation fail -- a problem shared by rustc.
654692 let place = self . force_allocation ( place) ?;
655693
656- let ( instance , place) = match place. layout . ty . kind ( ) {
657- ty:: Dynamic ( .. ) => {
694+ let place = match place. layout . ty . kind ( ) {
695+ ty:: Dynamic ( _ , _ , ty :: Dyn ) => {
658696 // Dropping a trait object. Need to find actual drop fn.
659- let place = self . unpack_dyn_trait ( & place) ?;
660- let instance = ty:: Instance :: resolve_drop_in_place ( * self . tcx , place. layout . ty ) ;
661- ( instance, place)
697+ self . unpack_dyn_trait ( & place) ?. 0
698+ }
699+ ty:: Dynamic ( _, _, ty:: DynStar ) => {
700+ // Dropping a `dyn*`. Need to find actual drop fn.
701+ self . unpack_dyn_star ( & place. into ( ) ) ?. 0 . assert_mem_place ( )
702+ }
703+ _ => {
704+ debug_assert_eq ! (
705+ instance,
706+ ty:: Instance :: resolve_drop_in_place( * self . tcx, place. layout. ty)
707+ ) ;
708+ place
662709 }
663- _ => ( instance, place) ,
664710 } ;
711+ let instance = ty:: Instance :: resolve_drop_in_place ( * self . tcx , place. layout . ty ) ;
665712 let fn_abi = self . fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ?;
666713
667714 let arg = ImmTy :: from_immediate (
0 commit comments