@@ -32,13 +32,9 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
32
32
33
33
let mut result = match instance {
34
34
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
+ }
42
38
ty:: InstanceDef :: FnPtrShim ( def_id, ty) => {
43
39
// FIXME(eddyb) support generating shims for a "shallow type",
44
40
// 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<'
60
56
let sig = tcx. erase_late_bound_regions ( & ty. fn_sig ( tcx) ) ;
61
57
let arg_tys = sig. inputs ( ) ;
62
58
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) )
64
60
}
65
61
// We are generating a call back to our def-id, which the
66
62
// 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<'
134
130
135
131
#[ derive( Copy , Clone , Debug , PartialEq ) ]
136
132
enum Adjustment {
133
+ /// Pass the receiver as-is.
137
134
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`).
138
140
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.
140
146
RefMut ,
141
147
}
142
148
143
149
#[ 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`.
146
155
Direct ( DefId ) ,
147
156
}
148
157
@@ -662,7 +671,7 @@ fn build_call_shim<'tcx>(
662
671
tcx : TyCtxt < ' tcx > ,
663
672
instance : ty:: InstanceDef < ' tcx > ,
664
673
rcvr_adjustment : Option < Adjustment > ,
665
- call_kind : CallKind ,
674
+ call_kind : CallKind < ' tcx > ,
666
675
untuple_args : Option < & [ Ty < ' tcx > ] > ,
667
676
) -> Body < ' tcx > {
668
677
debug ! (
@@ -675,6 +684,29 @@ fn build_call_shim<'tcx>(
675
684
let sig = tcx. fn_sig ( def_id) ;
676
685
let mut sig = tcx. erase_late_bound_regions ( & sig) ;
677
686
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
+
678
710
// FIXME(eddyb) avoid having this snippet both here and in
679
711
// `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?).
680
712
if let ty:: InstanceDef :: VtableShim ( ..) = instance {
@@ -701,8 +733,7 @@ fn build_call_shim<'tcx>(
701
733
702
734
let rcvr = rcvr_adjustment. map ( |rcvr_adjustment| match rcvr_adjustment {
703
735
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 ( ) ) ) ,
706
737
Adjustment :: RefMut => {
707
738
// let rcvr = &mut rcvr;
708
739
let ref_rcvr = local_decls. push (
@@ -728,7 +759,10 @@ fn build_call_shim<'tcx>(
728
759
} ) ;
729
760
730
761
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.
732
766
CallKind :: Direct ( def_id) => {
733
767
let ty = tcx. type_of ( def_id) ;
734
768
(
0 commit comments