9
9
// except according to those terms.
10
10
11
11
use rustc:: hir;
12
+ use rustc:: hir:: def_id:: DefId ;
12
13
use rustc:: infer;
14
+ use rustc:: middle:: region:: ROOT_CODE_EXTENT ;
13
15
use rustc:: mir:: * ;
14
16
use rustc:: mir:: transform:: MirSource ;
15
17
use rustc:: ty:: { self , Ty } ;
18
+ use rustc:: ty:: subst:: Subst ;
16
19
use rustc:: ty:: maps:: Providers ;
17
20
18
21
use rustc_data_structures:: indexed_vec:: { IndexVec , Idx } ;
19
22
20
23
use syntax:: abi:: Abi ;
21
24
use syntax:: ast;
22
- use syntax:: codemap:: DUMMY_SP ;
23
25
use syntax_pos:: Span ;
24
26
25
27
use std:: cell:: RefCell ;
@@ -35,11 +37,51 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
35
37
-> & ' tcx RefCell < Mir < ' tcx > >
36
38
{
37
39
debug ! ( "make_shim({:?})" , instance) ;
40
+ let did = instance. def_id ( ) ;
41
+ let span = tcx. def_span ( did) ;
42
+ let param_env =
43
+ tcx. construct_parameter_environment ( span, did, ROOT_CODE_EXTENT ) ;
44
+
38
45
let result = match instance {
39
46
ty:: InstanceDef :: Item ( ..) =>
40
47
bug ! ( "item {:?} passed to make_shim" , instance) ,
41
- ty:: InstanceDef :: FnPtrShim ( _, ty) => {
42
- build_fn_ptr_shim ( tcx, ty, instance. def_ty ( tcx) )
48
+ ty:: InstanceDef :: FnPtrShim ( def_id, ty) => {
49
+ let trait_ = tcx. trait_of_item ( def_id) . unwrap ( ) ;
50
+ let adjustment = match tcx. lang_items . fn_trait_kind ( trait_) {
51
+ Some ( ty:: ClosureKind :: FnOnce ) => Adjustment :: Identity ,
52
+ Some ( ty:: ClosureKind :: FnMut ) |
53
+ Some ( ty:: ClosureKind :: Fn ) => Adjustment :: Deref ,
54
+ None => bug ! ( "fn pointer {:?} is not an fn" , ty)
55
+ } ;
56
+ // HACK: we need the "real" argument types for the MIR,
57
+ // but because our substs are (Self, Args), where Args
58
+ // is a tuple, we must include the *concrete* argument
59
+ // types in the MIR. They will be substituted again with
60
+ // the param-substs, but because they are concrete, this
61
+ // will not do any harm.
62
+ let sig = tcx. erase_late_bound_regions ( & ty. fn_sig ( ) ) ;
63
+ let arg_tys = sig. inputs ( ) ;
64
+
65
+ build_call_shim (
66
+ tcx,
67
+ & param_env,
68
+ def_id,
69
+ adjustment,
70
+ CallKind :: Indirect ,
71
+ Some ( arg_tys)
72
+ )
73
+ }
74
+ ty:: InstanceDef :: Virtual ( def_id, _) => {
75
+ // We are translating a call back to our def-id, which
76
+ // trans::mir knows to turn to an actual virtual call.
77
+ build_call_shim (
78
+ tcx,
79
+ & param_env,
80
+ def_id,
81
+ Adjustment :: Identity ,
82
+ CallKind :: Direct ( def_id) ,
83
+ None
84
+ )
43
85
}
44
86
_ => bug ! ( "unknown shim kind" )
45
87
} ;
@@ -51,124 +93,135 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
51
93
result
52
94
}
53
95
96
+ #[ derive( Copy , Clone , Debug , PartialEq ) ]
97
+ enum Adjustment {
98
+ Identity ,
99
+ Deref ,
100
+ }
101
+
102
+ #[ derive( Copy , Clone , Debug , PartialEq ) ]
103
+ enum CallKind {
104
+ Indirect ,
105
+ Direct ( DefId ) ,
106
+ }
107
+
108
+ fn temp_decl ( mutability : Mutability , ty : Ty ) -> LocalDecl {
109
+ LocalDecl { mutability, ty, name : None , source_info : None }
110
+ }
111
+
54
112
fn local_decls_for_sig < ' tcx > ( sig : & ty:: FnSig < ' tcx > )
55
113
-> IndexVec < Local , LocalDecl < ' tcx > >
56
114
{
57
- iter:: once ( LocalDecl {
58
- mutability : Mutability :: Mut ,
59
- ty : sig. output ( ) ,
60
- name : None ,
61
- source_info : None
62
- } ) . chain ( sig. inputs ( ) . iter ( ) . map ( |ity| LocalDecl {
63
- mutability : Mutability :: Not ,
64
- ty : * ity,
65
- name : None ,
66
- source_info : None ,
67
- } ) ) . collect ( )
115
+ iter:: once ( temp_decl ( Mutability :: Mut , sig. output ( ) ) )
116
+ . chain ( sig. inputs ( ) . iter ( ) . map (
117
+ |ity| temp_decl ( Mutability :: Not , ity) ) )
118
+ . collect ( )
68
119
}
69
120
70
-
71
- fn build_fn_ptr_shim < ' a , ' tcx > ( tcx : ty:: TyCtxt < ' a , ' tcx , ' tcx > ,
72
- fn_ty : Ty < ' tcx > ,
73
- sig_ty : Ty < ' tcx > )
74
- -> Mir < ' tcx >
121
+ /// Build a "call" shim for `def_id`. The shim calls the
122
+ /// function specified by `call_kind`, first adjusting its first
123
+ /// argument according to `rcvr_adjustment`.
124
+ ///
125
+ /// If `untuple_args` is a vec of types, the second argument of the
126
+ /// function will be untupled as these types.
127
+ fn build_call_shim < ' a , ' tcx > ( tcx : ty:: TyCtxt < ' a , ' tcx , ' tcx > ,
128
+ param_env : & ty:: ParameterEnvironment < ' tcx > ,
129
+ def_id : DefId ,
130
+ rcvr_adjustment : Adjustment ,
131
+ call_kind : CallKind ,
132
+ untuple_args : Option < & [ Ty < ' tcx > ] > )
133
+ -> Mir < ' tcx >
75
134
{
76
- debug ! ( "build_fn_ptr_shim(fn_ty={:?}, sig_ty={:?})" , fn_ty, sig_ty) ;
77
- let trait_sig = match sig_ty. sty {
78
- ty:: TyFnDef ( _, _, fty) => tcx. erase_late_bound_regions ( & fty) ,
79
- _ => bug ! ( "unexpected type for shim {:?}" , sig_ty)
80
- } ;
135
+ debug ! ( "build_call_shim(def_id={:?}, rcvr_adjustment={:?}, \
136
+ call_kind={:?}, untuple_args={:?})",
137
+ def_id, rcvr_adjustment, call_kind, untuple_args) ;
81
138
82
- let self_ty = match trait_sig. inputs ( ) [ 0 ] . sty {
83
- ty:: TyParam ( ..) => fn_ty,
84
- ty:: TyRef ( r, mt) => tcx. mk_ref ( r, ty:: TypeAndMut {
85
- ty : fn_ty,
86
- mutbl : mt. mutbl
87
- } ) ,
88
- _ => bug ! ( "unexpected self_ty {:?}" , trait_sig) ,
89
- } ;
139
+ let fn_ty = tcx. item_type ( def_id) . subst ( tcx, param_env. free_substs ) ;
140
+ // Not normalizing here without a param env.
141
+ let sig = tcx. erase_late_bound_regions ( & fn_ty. fn_sig ( ) ) ;
142
+ let span = tcx. def_span ( def_id) ;
90
143
91
- let fn_ptr_sig = match fn_ty. sty {
92
- ty:: TyFnPtr ( fty) |
93
- ty:: TyFnDef ( _, _, fty) =>
94
- tcx. erase_late_bound_regions_and_normalize ( & fty) ,
95
- _ => bug ! ( "non-fn-ptr {:?} in build_fn_ptr_shim" , fn_ty)
96
- } ;
97
-
98
- let sig = tcx. mk_fn_sig (
99
- [
100
- self_ty,
101
- tcx. intern_tup ( fn_ptr_sig. inputs ( ) , false )
102
- ] . iter ( ) . cloned ( ) ,
103
- fn_ptr_sig. output ( ) ,
104
- false ,
105
- hir:: Unsafety :: Normal ,
106
- Abi :: RustCall ,
107
- ) ;
144
+ debug ! ( "build_call_shim: sig={:?}" , sig) ;
108
145
109
146
let local_decls = local_decls_for_sig ( & sig) ;
110
- let source_info = SourceInfo {
111
- span : DUMMY_SP ,
112
- scope : ARGUMENT_VISIBILITY_SCOPE
147
+ let source_info = SourceInfo { span, scope : ARGUMENT_VISIBILITY_SCOPE } ;
148
+
149
+ let rcvr_l = Lvalue :: Local ( Local :: new ( 1 +0 ) ) ;
150
+
151
+ let return_block_id = BasicBlock :: new ( 1 ) ;
152
+
153
+ let rcvr = match rcvr_adjustment {
154
+ Adjustment :: Identity => Operand :: Consume ( rcvr_l) ,
155
+ Adjustment :: Deref => Operand :: Consume ( Lvalue :: Projection (
156
+ box Projection { base : rcvr_l, elem : ProjectionElem :: Deref }
157
+ ) )
113
158
} ;
114
159
115
- let fn_ptr = Lvalue :: Local ( Local :: new ( 1 +0 ) ) ;
116
- let fn_ptr = match trait_sig. inputs ( ) [ 0 ] . sty {
117
- ty:: TyParam ( ..) => fn_ptr,
118
- ty:: TyRef ( ..) => Lvalue :: Projection ( box Projection {
119
- base : fn_ptr, elem : ProjectionElem :: Deref
120
- } ) ,
121
- _ => bug ! ( "unexpected self_ty {:?}" , trait_sig) ,
160
+ let ( callee, mut args) = match call_kind {
161
+ CallKind :: Indirect => ( rcvr, vec ! [ ] ) ,
162
+ CallKind :: Direct ( def_id) => (
163
+ Operand :: Constant ( Constant {
164
+ span : span,
165
+ ty : tcx. item_type ( def_id) . subst ( tcx, param_env. free_substs ) ,
166
+ literal : Literal :: Item { def_id, substs : param_env. free_substs } ,
167
+ } ) ,
168
+ vec ! [ rcvr]
169
+ )
122
170
} ;
123
- let fn_args = Local :: new ( 1 +1 ) ;
124
171
125
- let return_block_id = BasicBlock :: new ( 1 ) ;
172
+ if let Some ( untuple_args) = untuple_args {
173
+ args. extend ( untuple_args. iter ( ) . enumerate ( ) . map ( |( i, ity) | {
174
+ let arg_lv = Lvalue :: Local ( Local :: new ( 1 +1 ) ) ;
175
+ Operand :: Consume ( Lvalue :: Projection ( box Projection {
176
+ base : arg_lv,
177
+ elem : ProjectionElem :: Field ( Field :: new ( i) , * ity)
178
+ } ) )
179
+ } ) ) ;
180
+ } else {
181
+ args. extend ( ( 1 ..sig. inputs ( ) . len ( ) ) . map ( |i| {
182
+ Operand :: Consume ( Lvalue :: Local ( Local :: new ( 1 +i) ) )
183
+ } ) ) ;
184
+ }
126
185
127
- // return = ADT(arg0, arg1, ...); return
128
- let start_block = BasicBlockData {
186
+ let mut blocks = IndexVec :: new ( ) ;
187
+ blocks . push ( BasicBlockData {
129
188
statements : vec ! [ ] ,
130
189
terminator : Some ( Terminator {
131
190
source_info : source_info,
132
191
kind : TerminatorKind :: Call {
133
- func : Operand :: Consume ( fn_ptr) ,
134
- args : fn_ptr_sig. inputs ( ) . iter ( ) . enumerate ( ) . map ( |( i, ity) | {
135
- Operand :: Consume ( Lvalue :: Projection ( box Projection {
136
- base : Lvalue :: Local ( fn_args) ,
137
- elem : ProjectionElem :: Field (
138
- Field :: new ( i) , * ity
139
- )
140
- } ) )
141
- } ) . collect ( ) ,
142
- // FIXME: can we pass a Some destination for an uninhabited ty?
192
+ func : callee,
193
+ args : args,
143
194
destination : Some ( ( Lvalue :: Local ( RETURN_POINTER ) ,
144
195
return_block_id) ) ,
145
196
cleanup : None
146
197
}
147
198
} ) ,
148
199
is_cleanup : false
149
- } ;
150
- let return_block = BasicBlockData {
200
+ } ) ;
201
+ blocks . push ( BasicBlockData {
151
202
statements : vec ! [ ] ,
152
203
terminator : Some ( Terminator {
153
204
source_info : source_info,
154
205
kind : TerminatorKind :: Return
155
206
} ) ,
156
207
is_cleanup : false
157
- } ;
208
+ } ) ;
158
209
159
210
let mut mir = Mir :: new (
160
- vec ! [ start_block , return_block ] . into_iter ( ) . collect ( ) ,
211
+ blocks ,
161
212
IndexVec :: from_elem_n (
162
- VisibilityScopeData { span : DUMMY_SP , parent_scope : None } , 1
213
+ VisibilityScopeData { span : span , parent_scope : None } , 1
163
214
) ,
164
215
IndexVec :: new ( ) ,
165
216
sig. output ( ) ,
166
217
local_decls,
167
218
sig. inputs ( ) . len ( ) ,
168
219
vec ! [ ] ,
169
- DUMMY_SP
220
+ span
170
221
) ;
171
- mir. spread_arg = Some ( fn_args) ;
222
+ if let Abi :: RustCall = sig. abi {
223
+ mir. spread_arg = Some ( Local :: new ( sig. inputs ( ) . len ( ) ) ) ;
224
+ }
172
225
mir
173
226
}
174
227
0 commit comments