MSVC SEH in MIR is implemented here

This commit is contained in:
Simonas Kazlauskas 2016-02-11 22:57:09 +02:00
parent 5ad4673a40
commit 1752615591
8 changed files with 80 additions and 32 deletions

View File

@ -148,9 +148,6 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
Ok(mut mir) => {
// FIXME: This should run later rather than earlier (since this is supposed to be a
// codegen option), but we do not want to re-run the whole simplify_cfg pass all
// over again after this pass.
no_landing_pads::NoLandingPads.run_on_mir(&mut mir, self.tcx);
simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir, self.tcx);

View File

@ -26,7 +26,9 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
Terminator::Return |
Terminator::If { .. } |
Terminator::Switch { .. } |
Terminator::SwitchInt { .. } => { /* nothing to do */ },
Terminator::SwitchInt { .. } => {
/* nothing to do */
},
Terminator::Drop { ref mut unwind, .. } => {
unwind.take();
},

View File

@ -767,6 +767,10 @@ impl<'blk, 'tcx> BlockAndBuilder<'blk, 'tcx> {
{
self.bcx.monomorphize(value)
}
pub fn set_lpad(&self, lpad: Option<LandingPad>) {
self.bcx.lpad.set(lpad.map(|p| &*self.fcx().lpad_arena.alloc(p)))
}
}
impl<'blk, 'tcx> Deref for BlockAndBuilder<'blk, 'tcx> {

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use llvm::{BasicBlockRef, ValueRef};
use llvm::{BasicBlockRef, ValueRef, OperandBundleDef};
use rustc::middle::ty;
use rustc::mir::repr as mir;
use syntax::abi::Abi;
@ -34,6 +34,18 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let mut bcx = self.bcx(bb);
let data = self.mir.basic_block_data(bb);
// MSVC SEH bits
let (cleanup_pad, cleanup_bundle) = if let Some((cp, cb)) = self.make_cleanup_pad(bb) {
(Some(cp), Some(cb))
} else {
(None, None)
};
let funclet_br = |bcx: BlockAndBuilder, llbb: BasicBlockRef| if let Some(cp) = cleanup_pad {
bcx.cleanup_ret(cp, Some(llbb));
} else {
bcx.br(llbb);
};
for statement in &data.statements {
bcx = self.trans_statement(bcx, statement);
}
@ -41,8 +53,21 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
debug!("trans_block: terminator: {:?}", data.terminator());
match *data.terminator() {
mir::Terminator::Resume => {
if let Some(cleanup_pad) = cleanup_pad {
bcx.cleanup_ret(cleanup_pad, None);
} else {
let ps = self.get_personality_slot(&bcx);
let lp = bcx.load(ps);
bcx.with_block(|bcx| {
base::call_lifetime_end(bcx, ps);
base::trans_unwind_resume(bcx, lp);
});
}
}
mir::Terminator::Goto { target } => {
bcx.br(self.llblock(target));
funclet_br(bcx, self.llblock(target));
}
mir::Terminator::If { ref cond, targets: (true_bb, false_bb) } => {
@ -85,19 +110,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
}
mir::Terminator::Resume => {
let ps = self.get_personality_slot(&bcx);
let lp = bcx.load(ps);
bcx.with_block(|bcx| {
base::call_lifetime_end(bcx, ps);
base::trans_unwind_resume(bcx, lp);
});
}
mir::Terminator::Return => {
let return_ty = bcx.monomorphize(&self.mir.return_ty);
bcx.with_block(|bcx| {
base::build_return_block(bcx.fcx, bcx, return_ty, DebugLoc::None);
base::build_return_block(self.fcx, bcx, return_ty, DebugLoc::None);
})
}
@ -106,7 +122,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let ty = lvalue.ty.to_ty(bcx.tcx());
// Double check for necessity to drop
if !glue::type_needs_drop(bcx.tcx(), ty) {
bcx.br(self.llblock(target));
funclet_br(bcx, self.llblock(target));
return;
}
let drop_fn = glue::get_drop_glue(bcx.ccx(), ty);
@ -123,11 +139,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
&[llvalue],
self.llblock(target),
unwind.llbb(),
None,
cleanup_bundle.as_ref(),
None);
} else {
bcx.call(drop_fn, &[llvalue], None, None);
bcx.br(self.llblock(target));
bcx.call(drop_fn, &[llvalue], cleanup_bundle.as_ref(), None);
funclet_br(bcx, self.llblock(target));
}
}
@ -191,14 +207,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
&llargs[..],
unreachable_blk.llbb,
landingpad.llbb(),
None,
cleanup_bundle.as_ref(),
Some(attrs));
},
(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).build(), Some(self.bcx(success)))
(self.fcx.new_block("", None).build(), Some(self.bcx(success)))
} else {
(self.bcx(success), None)
};
@ -206,7 +222,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
&llargs[..],
target.llbb(),
landingpad.llbb(),
None,
cleanup_bundle.as_ref(),
Some(attrs));
if let Some(postinvoketarget) = postinvoke {
// We translate the copy into a temporary block. The temporary block is
@ -242,13 +258,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
},
(false, _, &None) => {
bcx.call(callee.immediate(), &llargs[..], None, Some(attrs));
bcx.call(callee.immediate(),
&llargs[..],
cleanup_bundle.as_ref(),
Some(attrs));
bcx.unreachable();
}
(false, _, &Some((_, target))) => {
let llret = bcx.call(callee.immediate(),
&llargs[..],
None,
cleanup_bundle.as_ref(),
Some(attrs));
if must_copy_dest {
let (ret_dest, ret_ty) = ret_dest_ty
@ -257,7 +276,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
base::store_ty(bcx, llret, ret_dest.llval, ret_ty);
});
}
bcx.br(self.llblock(target));
funclet_br(bcx, self.llblock(target));
}
// Foreign functions
(true, _, destination) => {
@ -273,7 +292,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
debugloc)
});
if let Some((_, target)) = *destination {
bcx.br(self.llblock(target));
funclet_br(bcx, self.llblock(target));
}
},
}
@ -296,11 +315,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
}
/// Create a landingpad wrapper around the given Block.
///
/// No-op in MSVC SEH scheme.
fn make_landing_pad(&mut self,
cleanup: BlockAndBuilder<'bcx, 'tcx>)
-> BlockAndBuilder<'bcx, 'tcx>
{
// FIXME(#30941) this doesn't handle msvc-style exceptions
if base::wants_msvc_seh(cleanup.sess()) {
return cleanup;
}
let bcx = self.fcx.new_block("cleanup", None).build();
let ccx = bcx.ccx();
let llpersonality = self.fcx.eh_personality();
@ -313,6 +337,31 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
bcx
}
/// Create prologue cleanuppad instruction under MSVC SEH handling scheme.
///
/// Also handles setting some state for the original trans and creating an operand bundle for
/// function calls.
fn make_cleanup_pad(&mut self, bb: mir::BasicBlock) -> Option<(ValueRef, OperandBundleDef)> {
let bcx = self.bcx(bb);
let data = self.mir.basic_block_data(bb);
let use_funclets = base::wants_msvc_seh(bcx.sess()) && data.is_cleanup;
let cleanup_pad = if use_funclets {
bcx.set_personality_fn(self.fcx.eh_personality());
Some(bcx.cleanup_pad(None, &[]))
} else {
None
};
// Set the landingpad global-state for old translator, so it knows about the SEH used.
bcx.set_lpad(if let Some(cleanup_pad) = cleanup_pad {
Some(common::LandingPad::msvc(cleanup_pad))
} else if data.is_cleanup {
Some(common::LandingPad::gnu())
} else {
None
});
cleanup_pad.map(|f| (f, OperandBundleDef::new("funclet", &[f])))
}
fn unreachable_block(&mut self) -> Block<'bcx, 'tcx> {
self.unreachable_block.unwrap_or_else(|| {
let bl = self.fcx.new_block("unreachable", None);

View File

@ -9,7 +9,6 @@
// except according to those terms.
#![feature(rustc_attrs)]
// ignore-msvc: FIXME(#30941)
// error-pattern:panic 1
// error-pattern:drop 2
use std::io::{self, Write};

View File

@ -10,7 +10,6 @@
#![feature(rustc_attrs)]
// ignore-msvc: FIXME(#30941)
// error-pattern:converging_fn called
// error-pattern:0 dropped
// error-pattern:exit

View File

@ -10,7 +10,6 @@
#![feature(rustc_attrs)]
// ignore-msvc: FIXME(#30941)
// error-pattern:complex called
// error-pattern:dropped
// error-pattern:exit

View File

@ -10,7 +10,6 @@
#![feature(rustc_attrs)]
// ignore-msvc: FIXME(#30941)
// error-pattern:diverging_fn called
// error-pattern:0 dropped