Skip to content

Commit 5d5c421

Browse files
committed
Refactor common part of evaluating Call&TailCall in the interpreter
1 parent 4e05b67 commit 5d5c421

File tree

1 file changed

+56
-63
lines changed

1 file changed

+56
-63
lines changed

compiler/rustc_const_eval/src/interpret/terminator.rs

Lines changed: 56 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ impl<'tcx, Prov: Provenance> FnArg<'tcx, Prov> {
4242
}
4343
}
4444

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+
4554
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
4655
/// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the
4756
/// original memory occurs.
@@ -122,40 +131,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
122131
} => {
123132
let old_stack = self.frame_idx();
124133
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)?;
155137

156138
let destination = self.eval_place(destination)?;
157139
self.eval_fn_call(
158-
fn_val,
140+
callee,
159141
(fn_sig.abi, fn_abi),
160142
&args,
161143
with_caller_location,
@@ -171,38 +153,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
171153
}
172154

173155
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?
175156
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)?;
206160

207161
// This is the "canonical" implementation of tails calls,
208162
// 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> {
225179
};
226180

227181
self.eval_fn_call(
228-
fn_val,
182+
callee,
229183
(fn_sig.abi, fn_abi),
230184
&args,
231185
with_caller_location,
@@ -561,6 +515,45 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
561515
Ok(())
562516
}
563517

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+
564557
/// Call this function -- pushing the stack frame and initializing the arguments.
565558
///
566559
/// `caller_fn_abi` is used to determine if all the arguments are passed the proper way.

0 commit comments

Comments
 (0)