@@ -547,7 +547,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
547
547
let receiver_place = loop {
548
548
match receiver. layout . ty . kind ( ) {
549
549
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
+ }
551
558
_ => {
552
559
// Not there yet, search for the only non-ZST field.
553
560
let mut non_zst_field = None ;
@@ -573,39 +580,59 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
573
580
}
574
581
}
575
582
} ;
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
- } ;
583
583
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
+ } ;
592
623
593
624
// Now determine the actual method to call. We can do that in two different ways and
594
625
// compare them to ensure everything fits.
595
626
let Some ( ty:: VtblEntry :: Method ( fn_inst) ) = self . get_vtable_entries ( vptr) ?. get ( idx) . copied ( ) else {
596
627
throw_ub_format ! ( "`dyn` call trying to call something that is not a method" )
597
628
} ;
629
+ trace ! ( "Virtual call dispatches to {fn_inst:#?}" ) ;
598
630
if cfg ! ( debug_assertions) {
599
631
let tcx = * self . tcx ;
600
632
601
633
let trait_def_id = tcx. trait_of_item ( def_id) . unwrap ( ) ;
602
634
let virtual_trait_ref =
603
635
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
- ) ;
609
636
let existential_trait_ref =
610
637
ty:: ExistentialTraitRef :: erase_self_ty ( tcx, virtual_trait_ref) ;
611
638
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> {
620
647
assert_eq ! ( fn_inst, concrete_method) ;
621
648
}
622
649
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 ( ) ;
634
656
trace ! ( "Patched receiver operand to {:#?}" , args[ 0 ] ) ;
635
657
// recurse with concrete function
636
658
self . eval_fn_call (
@@ -659,15 +681,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
659
681
// implementation fail -- a problem shared by rustc.
660
682
let place = self . force_allocation ( place) ?;
661
683
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 ) => {
664
686
// 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
668
699
}
669
- _ => ( instance, place) ,
670
700
} ;
701
+ let instance = ty:: Instance :: resolve_drop_in_place ( * self . tcx , place. layout . ty ) ;
671
702
let fn_abi = self . fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ?;
672
703
673
704
let arg = ImmTy :: from_immediate (
0 commit comments