@@ -42,6 +42,15 @@ impl<'tcx, Prov: Provenance> FnArg<'tcx, Prov> {
42
42
}
43
43
}
44
44
45
+ struct EvaluatedCalleeAndArgs < ' tcx , ' mir , M : Machine < ' mir , ' tcx > > {
46
+ callee : FnVal < ' tcx , M :: ExtraFnVal > ,
47
+ args : Vec < FnArg < ' tcx , <M as Machine < ' mir , ' tcx > >:: Provenance > > ,
48
+ fn_sig : ty:: FnSig < ' tcx > ,
49
+ fn_abi : & ' tcx FnAbi < ' tcx , Ty < ' tcx > > ,
50
+ /// True if the function is marked as `#[track_caller]` ([`ty::InstanceDef::requires_caller_location`])
51
+ with_caller_location : bool ,
52
+ }
53
+
45
54
impl < ' mir , ' tcx : ' mir , M : Machine < ' mir , ' tcx > > InterpCx < ' mir , ' tcx , M > {
46
55
/// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the
47
56
/// original memory occurs.
@@ -122,40 +131,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
122
131
} => {
123
132
let old_stack = self . frame_idx ( ) ;
124
133
let old_loc = self . frame ( ) . loc ;
125
- let func = self . eval_operand ( func, None ) ?;
126
- let args = self . eval_fn_call_arguments ( args) ?;
127
-
128
- let fn_sig_binder = func. layout . ty . fn_sig ( * self . tcx ) ;
129
- let fn_sig =
130
- self . tcx . normalize_erasing_late_bound_regions ( self . param_env , fn_sig_binder) ;
131
- let extra_args = & args[ fn_sig. inputs ( ) . len ( ) ..] ;
132
- let extra_args =
133
- self . tcx . mk_type_list_from_iter ( extra_args. iter ( ) . map ( |arg| arg. layout ( ) . ty ) ) ;
134
-
135
- let ( fn_val, fn_abi, with_caller_location) = match * func. layout . ty . kind ( ) {
136
- ty:: FnPtr ( _sig) => {
137
- let fn_ptr = self . read_pointer ( & func) ?;
138
- let fn_val = self . get_ptr_fn ( fn_ptr) ?;
139
- ( fn_val, self . fn_abi_of_fn_ptr ( fn_sig_binder, extra_args) ?, false )
140
- }
141
- ty:: FnDef ( def_id, args) => {
142
- let instance = self . resolve ( def_id, args) ?;
143
- (
144
- FnVal :: Instance ( instance) ,
145
- self . fn_abi_of_instance ( instance, extra_args) ?,
146
- instance. def . requires_caller_location ( * self . tcx ) ,
147
- )
148
- }
149
- _ => span_bug ! (
150
- terminator. source_info. span,
151
- "invalid callee of type {}" ,
152
- func. layout. ty
153
- ) ,
154
- } ;
134
+
135
+ let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
136
+ self . eval_callee_and_args ( terminator, func, args) ?;
155
137
156
138
let destination = self . eval_place ( destination) ?;
157
139
self . eval_fn_call (
158
- fn_val ,
140
+ callee ,
159
141
( fn_sig. abi , fn_abi) ,
160
142
& args,
161
143
with_caller_location,
@@ -171,38 +153,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
171
153
}
172
154
173
155
TailCall { ref func, ref args, fn_span : _ } => {
174
- // FIXME(explicit_tail_calls): a lot of code here is duplicated with normal calls, can we refactor this?
175
156
let old_frame_idx = self . frame_idx ( ) ;
176
- let func = self . eval_operand ( func, None ) ?;
177
- let args = self . eval_fn_call_arguments ( args) ?;
178
-
179
- let fn_sig_binder = func. layout . ty . fn_sig ( * self . tcx ) ;
180
- let fn_sig =
181
- self . tcx . normalize_erasing_late_bound_regions ( self . param_env , fn_sig_binder) ;
182
- let extra_args = & args[ fn_sig. inputs ( ) . len ( ) ..] ;
183
- let extra_args =
184
- self . tcx . mk_type_list_from_iter ( extra_args. iter ( ) . map ( |arg| arg. layout ( ) . ty ) ) ;
185
-
186
- let ( fn_val, fn_abi, with_caller_location) = match * func. layout . ty . kind ( ) {
187
- ty:: FnPtr ( _sig) => {
188
- let fn_ptr = self . read_pointer ( & func) ?;
189
- let fn_val = self . get_ptr_fn ( fn_ptr) ?;
190
- ( fn_val, self . fn_abi_of_fn_ptr ( fn_sig_binder, extra_args) ?, false )
191
- }
192
- ty:: FnDef ( def_id, substs) => {
193
- let instance = self . resolve ( def_id, substs) ?;
194
- (
195
- FnVal :: Instance ( instance) ,
196
- self . fn_abi_of_instance ( instance, extra_args) ?,
197
- instance. def . requires_caller_location ( * self . tcx ) ,
198
- )
199
- }
200
- _ => span_bug ! (
201
- terminator. source_info. span,
202
- "invalid callee of type {:?}" ,
203
- func. layout. ty
204
- ) ,
205
- } ;
157
+
158
+ let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
159
+ self . eval_callee_and_args ( terminator, func, args) ?;
206
160
207
161
// This is the "canonical" implementation of tails calls,
208
162
// a pop of the current stack frame, followed by a normal call
@@ -225,7 +179,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
225
179
} ;
226
180
227
181
self . eval_fn_call (
228
- fn_val ,
182
+ callee ,
229
183
( fn_sig. abi , fn_abi) ,
230
184
& args,
231
185
with_caller_location,
@@ -561,6 +515,45 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
561
515
Ok ( ( ) )
562
516
}
563
517
518
+ /// Shared part of `Call` and `TailCall` implementation — finding and evaluating all the
519
+ /// necessary information about callee and arguments to make a call.
520
+ fn eval_callee_and_args (
521
+ & self ,
522
+ terminator : & mir:: Terminator < ' tcx > ,
523
+ func : & mir:: Operand < ' tcx > ,
524
+ args : & [ Spanned < mir:: Operand < ' tcx > > ] ,
525
+ ) -> InterpResult < ' tcx , EvaluatedCalleeAndArgs < ' tcx , ' mir , M > > {
526
+ let func = self . eval_operand ( func, None ) ?;
527
+ let args = self . eval_fn_call_arguments ( args) ?;
528
+
529
+ let fn_sig_binder = func. layout . ty . fn_sig ( * self . tcx ) ;
530
+ let fn_sig = self . tcx . normalize_erasing_late_bound_regions ( self . param_env , fn_sig_binder) ;
531
+ let extra_args = & args[ fn_sig. inputs ( ) . len ( ) ..] ;
532
+ let extra_args =
533
+ self . tcx . mk_type_list_from_iter ( extra_args. iter ( ) . map ( |arg| arg. layout ( ) . ty ) ) ;
534
+
535
+ let ( callee, fn_abi, with_caller_location) = match * func. layout . ty . kind ( ) {
536
+ ty:: FnPtr ( _sig) => {
537
+ let fn_ptr = self . read_pointer ( & func) ?;
538
+ let fn_val = self . get_ptr_fn ( fn_ptr) ?;
539
+ ( fn_val, self . fn_abi_of_fn_ptr ( fn_sig_binder, extra_args) ?, false )
540
+ }
541
+ ty:: FnDef ( def_id, args) => {
542
+ let instance = self . resolve ( def_id, args) ?;
543
+ (
544
+ FnVal :: Instance ( instance) ,
545
+ self . fn_abi_of_instance ( instance, extra_args) ?,
546
+ instance. def . requires_caller_location ( * self . tcx ) ,
547
+ )
548
+ }
549
+ _ => {
550
+ span_bug ! ( terminator. source_info. span, "invalid callee of type {}" , func. layout. ty)
551
+ }
552
+ } ;
553
+
554
+ Ok ( EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } )
555
+ }
556
+
564
557
/// Call this function -- pushing the stack frame and initializing the arguments.
565
558
///
566
559
/// `caller_fn_abi` is used to determine if all the arguments are passed the proper way.
0 commit comments