Skip to content

Commit af97a11

Browse files
shim.rs: call FnPtr, not Self
The `Call` terminator only works with `FnDef` and `FnPtr` types. It happened to work with `Self` so far because it was always substituted with the real type before being used.
1 parent 58062e1 commit af97a11

File tree

1 file changed

+28
-5
lines changed

1 file changed

+28
-5
lines changed

src/librustc_mir/shim.rs

+28-5
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
5656
let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx));
5757
let arg_tys = sig.inputs();
5858

59-
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))
6060
}
6161
// We are generating a call back to our def-id, which the
6262
// codegen backend knows to turn to an actual call, be it
@@ -147,9 +147,9 @@ enum Adjustment {
147147
}
148148

149149
#[derive(Copy, Clone, Debug, PartialEq)]
150-
enum CallKind {
150+
enum CallKind<'tcx> {
151151
/// Call the `FnPtr` that was passed as the receiver.
152-
Indirect,
152+
Indirect(Ty<'tcx>),
153153

154154
/// Call a known `FnDef`.
155155
Direct(DefId),
@@ -671,7 +671,7 @@ fn build_call_shim<'tcx>(
671671
tcx: TyCtxt<'tcx>,
672672
instance: ty::InstanceDef<'tcx>,
673673
rcvr_adjustment: Option<Adjustment>,
674-
call_kind: CallKind,
674+
call_kind: CallKind<'tcx>,
675675
untuple_args: Option<&[Ty<'tcx>]>,
676676
) -> Body<'tcx> {
677677
debug!(
@@ -684,6 +684,29 @@ fn build_call_shim<'tcx>(
684684
let sig = tcx.fn_sig(def_id);
685685
let mut sig = tcx.erase_late_bound_regions(&sig);
686686

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+
687710
// FIXME(eddyb) avoid having this snippet both here and in
688711
// `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?).
689712
if let ty::InstanceDef::VtableShim(..) = instance {
@@ -737,7 +760,7 @@ fn build_call_shim<'tcx>(
737760

738761
let (callee, mut args) = match call_kind {
739762
// `FnPtr` call has no receiver. Args are untupled below.
740-
CallKind::Indirect => (rcvr.unwrap(), vec![]),
763+
CallKind::Indirect(_) => (rcvr.unwrap(), vec![]),
741764

742765
// `FnDef` call with optional receiver.
743766
CallKind::Direct(def_id) => {

0 commit comments

Comments
 (0)