-use rustc::hir;
-use rustc::hir::def_id::DefId;
use rustc::mir::*;
use rustc::ty::layout::VariantIdx;
use rustc::ty::query::Providers;
use rustc::ty::subst::{InternalSubsts, Subst};
use rustc::ty::{self, Ty, TyCtxt};
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
use rustc_index::vec::{Idx, IndexVec};
let mut result = match instance {
ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance),
- ty::InstanceDef::VtableShim(def_id) => {
- build_call_shim(tcx, instance, Adjustment::DerefMove, CallKind::Direct(def_id), None)
- }
+ ty::InstanceDef::VtableShim(def_id) => build_call_shim(
+ tcx,
+ instance,
+ Some(Adjustment::DerefMove),
+ CallKind::Direct(def_id),
+ None,
+ ),
ty::InstanceDef::FnPtrShim(def_id, ty) => {
let trait_ = tcx.trait_of_item(def_id).unwrap();
let adjustment = match tcx.lang_items().fn_trait_kind(trait_) {
let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx));
let arg_tys = sig.inputs();
- build_call_shim(tcx, instance, adjustment, CallKind::Indirect, Some(arg_tys))
+ build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect, Some(arg_tys))
}
// We are generating a call back to our def-id, which the
// codegen backend knows to turn to an actual call, be it
// indirect calls must be codegen'd differently than direct ones
// (such as `#[track_caller]`).
ty::InstanceDef::ReifyShim(def_id) => {
- build_call_shim(tcx, instance, Adjustment::Identity, CallKind::Direct(def_id), None)
+ build_call_shim(tcx, instance, None, CallKind::Direct(def_id), None)
}
ty::InstanceDef::ClosureOnceShim { call_once: _ } => {
let fn_mut = tcx.lang_items().fn_mut_trait().unwrap();
.unwrap()
.def_id;
- build_call_shim(tcx, instance, Adjustment::RefMut, CallKind::Direct(call_mut), None)
+ build_call_shim(
+ tcx,
+ instance,
+ Some(Adjustment::RefMut),
+ CallKind::Direct(call_mut),
+ None,
+ )
}
ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty),
ty::InstanceDef::CloneShim(def_id, ty) => {
fn build_call_shim<'tcx>(
tcx: TyCtxt<'tcx>,
instance: ty::InstanceDef<'tcx>,
- rcvr_adjustment: Adjustment,
+ rcvr_adjustment: Option<Adjustment>,
call_kind: CallKind,
untuple_args: Option<&[Ty<'tcx>]>,
) -> BodyAndCache<'tcx> {
let mut local_decls = local_decls_for_sig(&sig, span);
let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };
- let rcvr_arg = Local::new(1 + 0);
- let rcvr_l = Place::from(rcvr_arg);
+ let rcvr_place = || {
+ assert!(rcvr_adjustment.is_some());
+ Place::from(Local::new(1 + 0))
+ };
let mut statements = vec![];
- let rcvr = match rcvr_adjustment {
- Adjustment::Identity => Operand::Move(rcvr_l),
- Adjustment::Deref => Operand::Copy(tcx.mk_place_deref(rcvr_l)),
- Adjustment::DerefMove => Operand::Move(tcx.mk_place_deref(rcvr_l)),
+ let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment {
+ Adjustment::Identity => Operand::Move(rcvr_place()),
+ Adjustment::Deref => Operand::Copy(tcx.mk_place_deref(rcvr_place())),
+ Adjustment::DerefMove => Operand::Move(tcx.mk_place_deref(rcvr_place())),
Adjustment::RefMut => {
// let rcvr = &mut rcvr;
let ref_rcvr = local_decls.push(temp_decl(
source_info,
kind: StatementKind::Assign(box (
Place::from(ref_rcvr),
- Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l),
+ Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_place()),
)),
});
Operand::Move(Place::from(ref_rcvr))
}
- };
+ });
let (callee, mut args) = match call_kind {
- CallKind::Indirect => (rcvr, vec![]),
+ CallKind::Indirect => (rcvr.unwrap(), vec![]),
CallKind::Direct(def_id) => {
let ty = tcx.type_of(def_id);
(
user_ty: None,
literal: ty::Const::zero_sized(tcx, ty),
}),
- vec![rcvr],
+ rcvr.into_iter().collect::<Vec<_>>(),
)
}
};
+ let mut arg_range = 0..sig.inputs().len();
+
+ // Take the `self` ("receiver") argument out of the range (it's adjusted above).
+ if rcvr_adjustment.is_some() {
+ arg_range.start += 1;
+ }
+
+ // Take the last argument, if we need to untuple it (handled below).
+ if untuple_args.is_some() {
+ arg_range.end -= 1;
+ }
+
+ // Pass all of the non-special arguments directly.
+ args.extend(arg_range.map(|i| Operand::Move(Place::from(Local::new(1 + i)))));
+
+ // Untuple the last argument, if we have to.
if let Some(untuple_args) = untuple_args {
+ let tuple_arg = Local::new(1 + (sig.inputs().len() - 1));
args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
- let arg_place = Place::from(Local::new(1 + 1));
- Operand::Move(tcx.mk_place_field(arg_place, Field::new(i), *ity))
+ Operand::Move(tcx.mk_place_field(Place::from(tuple_arg), Field::new(i), *ity))
}));
- } else {
- args.extend((1..sig.inputs().len()).map(|i| Operand::Move(Place::from(Local::new(1 + i)))));
}
- let n_blocks = if let Adjustment::RefMut = rcvr_adjustment { 5 } else { 2 };
+ let n_blocks = if let Some(Adjustment::RefMut) = rcvr_adjustment { 5 } else { 2 };
let mut blocks = IndexVec::with_capacity(n_blocks);
let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
blocks.push(BasicBlockData {
func: callee,
args,
destination: Some((Place::return_place(), BasicBlock::new(1))),
- cleanup: if let Adjustment::RefMut = rcvr_adjustment {
+ cleanup: if let Some(Adjustment::RefMut) = rcvr_adjustment {
Some(BasicBlock::new(3))
} else {
None
false,
);
- if let Adjustment::RefMut = rcvr_adjustment {
+ if let Some(Adjustment::RefMut) = rcvr_adjustment {
// BB #1 - drop for Self
block(
&mut blocks,
vec![],
TerminatorKind::Drop {
- location: Place::from(rcvr_arg),
+ location: rcvr_place(),
target: BasicBlock::new(2),
unwind: None,
},
}
// BB #1/#2 - return
block(&mut blocks, vec![], TerminatorKind::Return, false);
- if let Adjustment::RefMut = rcvr_adjustment {
+ if let Some(Adjustment::RefMut) = rcvr_adjustment {
// BB #3 - drop if closure panics
block(
&mut blocks,
vec![],
TerminatorKind::Drop {
- location: Place::from(rcvr_arg),
+ location: rcvr_place(),
target: BasicBlock::new(4),
unwind: None,
},