@@ -32,13 +32,9 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
3232
3333 let mut result = match instance {
3434 ty:: InstanceDef :: Item ( ..) => bug ! ( "item {:?} passed to make_shim" , instance) ,
35- ty:: InstanceDef :: VtableShim ( def_id) => build_call_shim (
36- tcx,
37- instance,
38- Some ( Adjustment :: DerefMove ) ,
39- CallKind :: Direct ( def_id) ,
40- None ,
41- ) ,
35+ ty:: InstanceDef :: VtableShim ( def_id) => {
36+ build_call_shim ( tcx, instance, Some ( Adjustment :: Deref ) , CallKind :: Direct ( def_id) , None )
37+ }
4238 ty:: InstanceDef :: FnPtrShim ( def_id, ty) => {
4339 // FIXME(eddyb) support generating shims for a "shallow type",
4440 // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
@@ -60,7 +56,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
6056 let sig = tcx. erase_late_bound_regions ( & ty. fn_sig ( tcx) ) ;
6157 let arg_tys = sig. inputs ( ) ;
6258
63- build_call_shim ( tcx, instance, Some ( adjustment) , CallKind :: Indirect , Some ( arg_tys) )
59+ build_call_shim ( tcx, instance, Some ( adjustment) , CallKind :: Indirect ( ty ) , Some ( arg_tys) )
6460 }
6561 // We are generating a call back to our def-id, which the
6662 // codegen backend knows to turn to an actual call, be it
@@ -134,15 +130,28 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
134130
135131#[ derive( Copy , Clone , Debug , PartialEq ) ]
136132enum Adjustment {
133+ /// Pass the receiver as-is.
137134 Identity ,
135+
136+ /// We get passed `&[mut] self` and call the target with `*self`.
137+ ///
138+ /// This either copies `self` (if `Self: Copy`, eg. for function items), or moves out of it
139+ /// (for `VtableShim`, which effectively is passed `&own Self`).
138140 Deref ,
139- DerefMove ,
141+
142+ /// We get passed `self: Self` and call the target with `&mut self`.
143+ ///
144+ /// In this case we need to ensure that the `Self` is dropped after the call, as the callee
145+ /// won't do it for us.
140146 RefMut ,
141147}
142148
143149#[ derive( Copy , Clone , Debug , PartialEq ) ]
144- enum CallKind {
145- Indirect ,
150+ enum CallKind < ' tcx > {
151+ /// Call the `FnPtr` that was passed as the receiver.
152+ Indirect ( Ty < ' tcx > ) ,
153+
154+ /// Call a known `FnDef`.
146155 Direct ( DefId ) ,
147156}
148157
@@ -662,7 +671,7 @@ fn build_call_shim<'tcx>(
662671 tcx : TyCtxt < ' tcx > ,
663672 instance : ty:: InstanceDef < ' tcx > ,
664673 rcvr_adjustment : Option < Adjustment > ,
665- call_kind : CallKind ,
674+ call_kind : CallKind < ' tcx > ,
666675 untuple_args : Option < & [ Ty < ' tcx > ] > ,
667676) -> Body < ' tcx > {
668677 debug ! (
@@ -675,6 +684,29 @@ fn build_call_shim<'tcx>(
675684 let sig = tcx. fn_sig ( def_id) ;
676685 let mut sig = tcx. erase_late_bound_regions ( & sig) ;
677686
687+ if let CallKind :: Indirect ( fnty) = call_kind {
688+ // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
689+ // can only be an `FnDef` or `FnPtr`, but currently will be `Self` since the types come from
690+ // the implemented `FnX` trait.
691+
692+ // Apply the opposite adjustment to the MIR input.
693+ let mut inputs_and_output = sig. inputs_and_output . to_vec ( ) ;
694+
695+ // Initial signature is `fn(&? Self, Args) -> Self::Output` where `Args` is a tuple of the
696+ // fn arguments. `Self` may be passed via (im)mutable reference or by-value.
697+ assert_eq ! ( inputs_and_output. len( ) , 3 ) ;
698+
699+ // `Self` is always the original fn type `ty`. The MIR call terminator is only defined for
700+ // `FnDef` and `FnPtr` callees, not the `Self` type param.
701+ let self_arg = & mut inputs_and_output[ 0 ] ;
702+ * self_arg = match rcvr_adjustment. unwrap ( ) {
703+ Adjustment :: Identity => fnty,
704+ Adjustment :: Deref => tcx. mk_imm_ptr ( fnty) ,
705+ Adjustment :: RefMut => tcx. mk_mut_ptr ( fnty) ,
706+ } ;
707+ sig. inputs_and_output = tcx. intern_type_list ( & inputs_and_output) ;
708+ }
709+
678710 // FIXME(eddyb) avoid having this snippet both here and in
679711 // `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?).
680712 if let ty:: InstanceDef :: VtableShim ( ..) = instance {
@@ -701,8 +733,7 @@ fn build_call_shim<'tcx>(
701733
702734 let rcvr = rcvr_adjustment. map ( |rcvr_adjustment| match rcvr_adjustment {
703735 Adjustment :: Identity => Operand :: Move ( rcvr_place ( ) ) ,
704- Adjustment :: Deref => Operand :: Move ( tcx. mk_place_deref ( rcvr_place ( ) ) ) , // Can't copy `&mut`
705- Adjustment :: DerefMove => Operand :: Move ( tcx. mk_place_deref ( rcvr_place ( ) ) ) ,
736+ Adjustment :: Deref => Operand :: Move ( tcx. mk_place_deref ( rcvr_place ( ) ) ) ,
706737 Adjustment :: RefMut => {
707738 // let rcvr = &mut rcvr;
708739 let ref_rcvr = local_decls. push (
@@ -728,7 +759,10 @@ fn build_call_shim<'tcx>(
728759 } ) ;
729760
730761 let ( callee, mut args) = match call_kind {
731- CallKind :: Indirect => ( rcvr. unwrap ( ) , vec ! [ ] ) ,
762+ // `FnPtr` call has no receiver. Args are untupled below.
763+ CallKind :: Indirect ( _) => ( rcvr. unwrap ( ) , vec ! [ ] ) ,
764+
765+ // `FnDef` call with optional receiver.
732766 CallKind :: Direct ( def_id) => {
733767 let ty = tcx. type_of ( def_id) ;
734768 (
0 commit comments