Auto merge of #31307 - nagisa:mir-drop-terminator, r=nikomatsakis

The scope of these refactorings is a little bit bigger than the title implies. See each commit for details.

I’m submitting this for nitpicking now (the first 4 commits), because I feel the basic idea/implementation is sound and should work. I will eventually expand this PR to cover the translator changes necessary for all this to work (+ tests), ~~and perhaps implement a dynamic dropping scheme while I’m at it as well.~~

r? @nikomatsakis
This commit is contained in:
bors 2016-02-06 01:24:22 +00:00
commit 5147c1f2c0
25 changed files with 554 additions and 339 deletions

View file

@ -18,10 +18,11 @@ use trans::base;
use trans::build;
use trans::common::{self, Block, LandingPad};
use trans::debuginfo::DebugLoc;
use trans::Disr;
use trans::foreign;
use trans::glue;
use trans::type_of;
use trans::type_::Type;
use trans::Disr;
use super::MirContext;
use super::operand::OperandValue::{FatPtr, Immediate, Ref};
@ -94,7 +95,39 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
base::build_return_block(bcx.fcx, bcx, return_ty, DebugLoc::None);
}
mir::Terminator::Call { ref func, ref args, ref kind } => {
mir::Terminator::Drop { ref value, target, unwind } => {
let lvalue = self.trans_lvalue(bcx, value);
let ty = lvalue.ty.to_ty(bcx.tcx());
// Double check for necessity to drop
if !glue::type_needs_drop(bcx.tcx(), ty) {
build::Br(bcx, self.llblock(target), DebugLoc::None);
return;
}
let drop_fn = glue::get_drop_glue(bcx.ccx(), ty);
let drop_ty = glue::get_drop_glue_type(bcx.ccx(), ty);
let llvalue = if drop_ty != ty {
build::PointerCast(bcx, lvalue.llval,
type_of::type_of(bcx.ccx(), drop_ty).ptr_to())
} else {
lvalue.llval
};
if let Some(unwind) = unwind {
let uwbcx = self.bcx(unwind);
let unwind = self.make_landing_pad(uwbcx);
build::Invoke(bcx,
drop_fn,
&[llvalue],
self.llblock(target),
unwind.llbb,
None,
DebugLoc::None);
} else {
build::Call(bcx, drop_fn, &[llvalue], None, DebugLoc::None);
build::Br(bcx, self.llblock(target), DebugLoc::None);
}
}
mir::Terminator::Call { ref func, ref args, ref destination, ref cleanup } => {
// Create the callee. This will always be a fn ptr and hence a kind of scalar.
let callee = self.trans_operand(bcx, func);
let attrs = attributes::from_fn_type(bcx.ccx(), callee.ty);
@ -115,7 +148,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
};
// Prepare the return value destination
let (ret_dest_ty, must_copy_dest) = if let Some(d) = kind.destination() {
let (ret_dest_ty, must_copy_dest) = if let Some((ref d, _)) = *destination {
let dest = self.trans_lvalue(bcx, d);
let ret_ty = dest.ty.to_ty(bcx.tcx());
if !is_foreign && type_of::return_uses_outptr(bcx.ccx(), ret_ty) {
@ -144,9 +177,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
// Many different ways to call a function handled here
match (is_foreign, base::avoid_invoke(bcx), kind) {
match (is_foreign, base::avoid_invoke(bcx), cleanup, destination) {
// The two cases below are the only ones to use LLVMs `invoke`.
(false, false, &mir::CallKind::DivergingCleanup(cleanup)) => {
(false, false, &Some(cleanup), &None) => {
let cleanup = self.bcx(cleanup);
let landingpad = self.make_landing_pad(cleanup);
let unreachable_blk = self.unreachable_block();
@ -158,14 +191,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
Some(attrs),
debugloc);
},
(false, false, &mir::CallKind::ConvergingCleanup { ref targets, .. }) => {
let cleanup = self.bcx(targets.1);
(false, false, &Some(cleanup), &Some((_, success))) => {
let cleanup = self.bcx(cleanup);
let landingpad = self.make_landing_pad(cleanup);
let (target, postinvoke) = if must_copy_dest {
(bcx.fcx.new_block("", None),
Some(self.bcx(targets.0)))
(bcx.fcx.new_block("", None), Some(self.bcx(success)))
} else {
(self.bcx(targets.0), None)
(self.bcx(success), None)
};
let invokeret = build::Invoke(bcx,
callee.immediate(),
@ -205,19 +237,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
build::Br(target, postinvoketarget.llbb, debugloc);
}
},
(false, _, &mir::CallKind::DivergingCleanup(_)) |
(false, _, &mir::CallKind::Diverging) => {
(false, _, _, &None) => {
build::Call(bcx, callee.immediate(), &llargs[..], Some(attrs), debugloc);
build::Unreachable(bcx);
}
(false, _, k@&mir::CallKind::ConvergingCleanup { .. }) |
(false, _, k@&mir::CallKind::Converging { .. }) => {
// FIXME: Bug #20046
let target = match *k {
mir::CallKind::ConvergingCleanup { targets, .. } => targets.0,
mir::CallKind::Converging { target, .. } => target,
_ => unreachable!()
};
(false, _, _, &Some((_, target))) => {
let llret = build::Call(bcx,
callee.immediate(),
&llargs[..],
@ -231,7 +255,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
build::Br(bcx, self.llblock(target), debugloc);
}
// Foreign functions
(true, _, k) => {
(true, _, _, destination) => {
let (dest, _) = ret_dest_ty
.expect("return destination is not set");
bcx = foreign::trans_native_call(bcx,
@ -241,13 +265,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
&llargs[..],
arg_tys,
debugloc);
match *k {
mir::CallKind::ConvergingCleanup { targets, .. } =>
build::Br(bcx, self.llblock(targets.0), debugloc),
mir::CallKind::Converging { target, .. } =>
build::Br(bcx, self.llblock(target), debugloc),
_ => ()
};
if let Some((_, target)) = *destination {
build::Br(bcx, self.llblock(target), debugloc);
}
},
}
}

View file

@ -82,13 +82,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
constant: &mir::Constant<'tcx>)
-> OperandRef<'tcx>
{
let ty = bcx.monomorphize(&constant.ty);
match constant.literal {
mir::Literal::Item { def_id, kind, substs } => {
let substs = bcx.tcx().mk_substs(bcx.monomorphize(&substs));
self.trans_item_ref(bcx, ty, kind, substs, def_id)
self.trans_item_ref(bcx, constant.ty, kind, substs, def_id)
}
mir::Literal::Value { ref value } => {
let ty = bcx.monomorphize(&constant.ty);
self.trans_constval(bcx, value, ty)
}
}

View file

@ -65,7 +65,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
assert!(lvalue.llextra != ptr::null_mut());
lvalue.llextra
}
_ => bcx.sess().bug("unexpected type in get_base_and_len"),
_ => bcx.sess().bug("unexpected type in lvalue_len"),
}
}

View file

@ -195,8 +195,8 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>,
mod analyze;
mod block;
mod constant;
mod lvalue;
mod rvalue;
mod operand;
mod statement;
mod did;
mod lvalue;
mod operand;
mod rvalue;
mod statement;

View file

@ -8,11 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::middle::ty::LvaluePreference;
use rustc::mir::repr as mir;
use trans::common::Block;
use trans::debuginfo::DebugLoc;
use trans::glue;
use super::MirContext;
use super::TempRef;
@ -51,20 +48,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
}
}
mir::StatementKind::Drop(mir::DropKind::Deep, ref lvalue) => {
let tr_lvalue = self.trans_lvalue(bcx, lvalue);
let ty = tr_lvalue.ty.to_ty(bcx.tcx());
glue::drop_ty(bcx, tr_lvalue.llval, ty, DebugLoc::None)
}
mir::StatementKind::Drop(mir::DropKind::Free, ref lvalue) => {
let tr_lvalue = self.trans_lvalue(bcx, lvalue);
let ty = tr_lvalue.ty.to_ty(bcx.tcx());
let content_ty = ty.builtin_deref(true, LvaluePreference::NoPreference);
let content_ty = content_ty.unwrap().ty;
glue::trans_exchange_free_ty(bcx, tr_lvalue.llval, content_ty, DebugLoc::None)
}
}
}
}