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