@@ -547,7 +547,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
547547 let receiver_place = loop {
548548 match receiver. layout . ty . kind ( ) {
549549 ty:: Ref ( ..) | ty:: RawPtr ( ..) => break self . deref_operand ( & receiver) ?,
550- ty:: Dynamic ( ..) => break receiver. assert_mem_place ( ) , // no immediate unsized values
550+ ty:: Dynamic ( .., ty:: Dyn ) => break receiver. assert_mem_place ( ) , // no immediate unsized values
551+ ty:: Dynamic ( .., ty:: DynStar ) => {
552+ // Not clear how to handle this, so far we assume the receiver is always a pointer.
553+ span_bug ! (
554+ self . cur_span( ) ,
555+ "by-value calls on a `dyn*`... are those a thing?"
556+ ) ;
557+ }
551558 _ => {
552559 // Not there yet, search for the only non-ZST field.
553560 let mut non_zst_field = None ;
@@ -573,39 +580,59 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
573580 }
574581 }
575582 } ;
576- // Obtain the underlying trait we are working on.
577- let receiver_tail = self
578- . tcx
579- . struct_tail_erasing_lifetimes ( receiver_place. layout . ty , self . param_env ) ;
580- let ty:: Dynamic ( data, ..) = receiver_tail. kind ( ) else {
581- span_bug ! ( self . cur_span( ) , "dynamic call on non-`dyn` type {}" , receiver_tail)
582- } ;
583583
584- // Get the required information from the vtable.
585- let vptr = receiver_place. meta . unwrap_meta ( ) . to_pointer ( self ) ?;
586- let ( dyn_ty, dyn_trait) = self . get_ptr_vtable ( vptr) ?;
587- if dyn_trait != data. principal ( ) {
588- throw_ub_format ! (
589- "`dyn` call on a pointer whose vtable does not match its type"
590- ) ;
591- }
584+ // Obtain the underlying trait we are working on, and the adjusted receiver argument.
585+ let ( vptr, dyn_ty, adjusted_receiver) = if let ty:: Dynamic ( data, _, ty:: DynStar ) =
586+ receiver_place. layout . ty . kind ( )
587+ {
588+ let ( recv, vptr) = self . unpack_dyn_star ( & receiver_place. into ( ) ) ?;
589+ let ( dyn_ty, dyn_trait) = self . get_ptr_vtable ( vptr) ?;
590+ if dyn_trait != data. principal ( ) {
591+ throw_ub_format ! (
592+ "`dyn*` call on a pointer whose vtable does not match its type"
593+ ) ;
594+ }
595+ let recv = recv. assert_mem_place ( ) ; // we passed an MPlaceTy to `unpack_dyn_star` so we definitely still have one
596+
597+ ( vptr, dyn_ty, recv. ptr )
598+ } else {
599+ // Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`.
600+ // (For that reason we also cannot use `unpack_dyn_trait`.)
601+ let receiver_tail = self
602+ . tcx
603+ . struct_tail_erasing_lifetimes ( receiver_place. layout . ty , self . param_env ) ;
604+ let ty:: Dynamic ( data, _, ty:: Dyn ) = receiver_tail. kind ( ) else {
605+ span_bug ! ( self . cur_span( ) , "dynamic call on non-`dyn` type {}" , receiver_tail)
606+ } ;
607+ assert ! ( receiver_place. layout. is_unsized( ) ) ;
608+
609+ // Get the required information from the vtable.
610+ let vptr = receiver_place. meta . unwrap_meta ( ) . to_pointer ( self ) ?;
611+ let ( dyn_ty, dyn_trait) = self . get_ptr_vtable ( vptr) ?;
612+ if dyn_trait != data. principal ( ) {
613+ throw_ub_format ! (
614+ "`dyn` call on a pointer whose vtable does not match its type"
615+ ) ;
616+ }
617+
618+ // It might be surprising that we use a pointer as the receiver even if this
619+ // is a by-val case; this works because by-val passing of an unsized `dyn
620+ // Trait` to a function is actually desugared to a pointer.
621+ ( vptr, dyn_ty, receiver_place. ptr )
622+ } ;
592623
593624 // Now determine the actual method to call. We can do that in two different ways and
594625 // compare them to ensure everything fits.
595626 let Some ( ty:: VtblEntry :: Method ( fn_inst) ) = self . get_vtable_entries ( vptr) ?. get ( idx) . copied ( ) else {
596627 throw_ub_format ! ( "`dyn` call trying to call something that is not a method" )
597628 } ;
629+ trace ! ( "Virtual call dispatches to {fn_inst:#?}" ) ;
598630 if cfg ! ( debug_assertions) {
599631 let tcx = * self . tcx ;
600632
601633 let trait_def_id = tcx. trait_of_item ( def_id) . unwrap ( ) ;
602634 let virtual_trait_ref =
603635 ty:: TraitRef :: from_method ( tcx, trait_def_id, instance. substs ) ;
604- assert_eq ! (
605- receiver_tail,
606- virtual_trait_ref. self_ty( ) ,
607- "mismatch in underlying dyn trait computation within Miri and MIR building" ,
608- ) ;
609636 let existential_trait_ref =
610637 ty:: ExistentialTraitRef :: erase_self_ty ( tcx, virtual_trait_ref) ;
611638 let concrete_trait_ref = existential_trait_ref. with_self_ty ( tcx, dyn_ty) ;
@@ -620,17 +647,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
620647 assert_eq ! ( fn_inst, concrete_method) ;
621648 }
622649
623- // `*mut receiver_place.layout.ty` is almost the layout that we
624- // want for args[0]: We have to project to field 0 because we want
625- // a thin pointer.
626- assert ! ( receiver_place. layout. is_unsized( ) ) ;
627- let receiver_ptr_ty = self . tcx . mk_mut_ptr ( receiver_place. layout . ty ) ;
628- let this_receiver_ptr = self . layout_of ( receiver_ptr_ty) ?. field ( self , 0 ) ;
629- // Adjust receiver argument.
630- args[ 0 ] = OpTy :: from ( ImmTy :: from_immediate (
631- Scalar :: from_maybe_pointer ( receiver_place. ptr , self ) . into ( ) ,
632- this_receiver_ptr,
633- ) ) ;
650+ // Adjust receiver argument. Layout can be any (thin) ptr.
651+ args[ 0 ] = ImmTy :: from_immediate (
652+ Scalar :: from_maybe_pointer ( adjusted_receiver, self ) . into ( ) ,
653+ self . layout_of ( self . tcx . mk_mut_ptr ( dyn_ty) ) ?,
654+ )
655+ . into ( ) ;
634656 trace ! ( "Patched receiver operand to {:#?}" , args[ 0 ] ) ;
635657 // recurse with concrete function
636658 self . eval_fn_call (
@@ -659,15 +681,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
659681 // implementation fail -- a problem shared by rustc.
660682 let place = self . force_allocation ( place) ?;
661683
662- let ( instance , place) = match place. layout . ty . kind ( ) {
663- ty:: Dynamic ( .. ) => {
684+ let place = match place. layout . ty . kind ( ) {
685+ ty:: Dynamic ( _ , _ , ty :: Dyn ) => {
664686 // Dropping a trait object. Need to find actual drop fn.
665- let place = self . unpack_dyn_trait ( & place) ?;
666- let instance = ty:: Instance :: resolve_drop_in_place ( * self . tcx , place. layout . ty ) ;
667- ( instance, place)
687+ self . unpack_dyn_trait ( & place) ?. 0
688+ }
689+ ty:: Dynamic ( _, _, ty:: DynStar ) => {
690+ // Dropping a `dyn*`. Need to find actual drop fn.
691+ self . unpack_dyn_star ( & place. into ( ) ) ?. 0 . assert_mem_place ( )
692+ }
693+ _ => {
694+ debug_assert_eq ! (
695+ instance,
696+ ty:: Instance :: resolve_drop_in_place( * self . tcx, place. layout. ty)
697+ ) ;
698+ place
668699 }
669- _ => ( instance, place) ,
670700 } ;
701+ let instance = ty:: Instance :: resolve_drop_in_place ( * self . tcx , place. layout . ty ) ;
671702 let fn_abi = self . fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ?;
672703
673704 let arg = ImmTy :: from_immediate (
0 commit comments