@@ -538,10 +538,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
538
538
// pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively
539
539
// unwrap those newtypes until we are there.
540
540
let mut receiver = args[ 0 ] . clone ( ) ;
541
- let receiver_place = loop {
541
+ let receiver = loop {
542
542
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,
545
544
_ => {
546
545
// Not there yet, search for the only non-ZST field.
547
546
let mut non_zst_field = None ;
@@ -567,39 +566,83 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
567
566
}
568
567
}
569
568
} ;
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
- } ;
577
569
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
+ } ;
586
633
587
634
// Now determine the actual method to call. We can do that in two different ways and
588
635
// compare them to ensure everything fits.
589
636
let Some ( ty:: VtblEntry :: Method ( fn_inst) ) = self . get_vtable_entries ( vptr) ?. get ( idx) . copied ( ) else {
590
637
throw_ub_format ! ( "`dyn` call trying to call something that is not a method" )
591
638
} ;
639
+ trace ! ( "Virtual call dispatches to {fn_inst:#?}" ) ;
592
640
if cfg ! ( debug_assertions) {
593
641
let tcx = * self . tcx ;
594
642
595
643
let trait_def_id = tcx. trait_of_item ( def_id) . unwrap ( ) ;
596
644
let virtual_trait_ref =
597
645
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
- ) ;
603
646
let existential_trait_ref =
604
647
ty:: ExistentialTraitRef :: erase_self_ty ( tcx, virtual_trait_ref) ;
605
648
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> {
614
657
assert_eq ! ( fn_inst, concrete_method) ;
615
658
}
616
659
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 ( ) ;
628
666
trace ! ( "Patched receiver operand to {:#?}" , args[ 0 ] ) ;
629
667
// recurse with concrete function
630
668
self . eval_fn_call (
@@ -653,15 +691,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
653
691
// implementation fail -- a problem shared by rustc.
654
692
let place = self . force_allocation ( place) ?;
655
693
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 ) => {
658
696
// 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
662
709
}
663
- _ => ( instance, place) ,
664
710
} ;
711
+ let instance = ty:: Instance :: resolve_drop_in_place ( * self . tcx , place. layout . ty ) ;
665
712
let fn_abi = self . fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ?;
666
713
667
714
let arg = ImmTy :: from_immediate (
0 commit comments