diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index f59cdb74b62..fa3573b383b 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -192,6 +192,7 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { pub struct BasicBlockData<'tcx> { pub statements: Vec>, pub terminator: Option>, + pub is_cleanup: bool, } #[derive(RustcEncodable, RustcDecodable)] @@ -341,6 +342,7 @@ pub fn new(terminator: Option>) -> BasicBlockData<'tcx> { BasicBlockData { statements: vec![], terminator: terminator, + is_cleanup: false, } } diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 758c5781efc..080b979c1ec 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -251,6 +251,7 @@ pub fn diverge_cleanup(&mut self) -> Option { continue; } else { let new_block = self.cfg.start_new_block(); + self.cfg.block_data_mut(new_block).is_cleanup = true; self.cfg.terminate(new_block, terminator); terminator = Terminator::Goto { target: new_block }; for &(kind, span, ref lvalue) in scope.drops.iter().rev() { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 4197f80cb5e..a6e6d304220 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -958,22 +958,28 @@ pub fn wants_msvc_seh(sess: &Session) -> bool { sess.target.target.options.is_like_msvc && sess.target.target.arch == "x86" } -pub fn need_invoke(bcx: Block) -> bool { +pub fn avoid_invoke(bcx: Block) -> bool { // FIXME(#25869) currently SEH-based unwinding is pretty buggy in LLVM and // is being overhauled as this is being written. Until that // time such that upstream LLVM's implementation is more solid // and we start binding it we need to skip invokes for any // target which wants SEH-based unwinding. if bcx.sess().no_landing_pads() || wants_msvc_seh(bcx.sess()) { - return false; + true + } else if bcx.is_lpad { + // Avoid using invoke if we are already inside a landing pad. + true + } else { + false } +} - // Avoid using invoke if we are already inside a landing pad. - if bcx.is_lpad { - return false; +pub fn need_invoke(bcx: Block) -> bool { + if avoid_invoke(bcx) { + false + } else { + bcx.fcx.needs_invoke() } - - bcx.fcx.needs_invoke() } pub fn load_if_immediate<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, t: Ty<'tcx>) -> ValueRef { diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index d41c4dec2b2..55117a6db39 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -128,19 +128,9 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) { let debugloc = DebugLoc::None; let attrs = attributes::from_fn_type(bcx.ccx(), callee.ty); - match *targets { - mir::CallTargets::Return(ret) => { - let llret = build::Call(bcx, - callee.immediate(), - &llargs[..], - Some(attrs), - debugloc); - if !return_outptr && !common::type_is_zero_size(bcx.ccx(), ret_ty) { - base::store_ty(bcx, llret, call_dest.llval, ret_ty); - } - build::Br(bcx, self.llblock(ret), debugloc) - } - mir::CallTargets::WithCleanup((ret, cleanup)) => { + match (*targets, base::avoid_invoke(bcx)) { + (mir::CallTargets::WithCleanup((ret, cleanup)), false) => { + let cleanup = self.bcx(cleanup); let landingpad = self.make_landing_pad(cleanup); build::Invoke(bcx, callee.immediate(), @@ -153,6 +143,26 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) { // FIXME: What do we do here? unimplemented!() } + }, + (t, _) => { + let ret = match t { + mir::CallTargets::Return(ret) => ret, + mir::CallTargets::WithCleanup((ret, _)) => { + // make a landing pad regardless (so it sets the personality slot. + let block = self.unreachable_block(); + self.make_landing_pad(block); + ret + } + }; + let llret = build::Call(bcx, + callee.immediate(), + &llargs[..], + Some(attrs), + debugloc); + if !return_outptr && !common::type_is_zero_size(bcx.ccx(), ret_ty) { + base::store_ty(bcx, llret, call_dest.llval, ret_ty); + } + build::Br(bcx, self.llblock(ret), debugloc) } } }, @@ -171,12 +181,9 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) { } let debugloc = DebugLoc::None; let attrs = attributes::from_fn_type(bcx.ccx(), callee.ty); - match *cleanup { - None => { - build::Call(bcx, callee.immediate(), &llargs[..], Some(attrs), debugloc); - build::Unreachable(bcx); - } - Some(cleanup) => { + match (*cleanup, base::avoid_invoke(bcx)) { + (Some(cleanup), false) => { + let cleanup = self.bcx(cleanup); let landingpad = self.make_landing_pad(cleanup); let unreachable = self.unreachable_block(); build::Invoke(bcx, @@ -187,13 +194,22 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) { Some(attrs), debugloc); } + (t, _) => { + if t.is_some() { + // make a landing pad regardless, so it sets the personality slot. + let block = self.unreachable_block(); + self.make_landing_pad(block); + } + build::Call(bcx, callee.immediate(), &llargs[..], Some(attrs), debugloc); + build::Unreachable(bcx); + } } } } } - fn make_landing_pad(&mut self, cleanup: mir::BasicBlock) -> Block<'bcx, 'tcx> { - let bcx = self.bcx(cleanup).fcx.new_block(true, "cleanup", None); + fn make_landing_pad(&mut self, cleanup: Block<'bcx, 'tcx>) -> Block<'bcx, 'tcx> { + let bcx = cleanup.fcx.new_block(true, "cleanup", None); let ccx = bcx.ccx(); let llpersonality = bcx.fcx.eh_personality(); let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false); @@ -208,7 +224,7 @@ fn make_landing_pad(&mut self, cleanup: mir::BasicBlock) -> Block<'bcx, 'tcx> { build::Store(bcx, llretval, personalityslot) } }; - build::Br(bcx, self.llblock(cleanup), DebugLoc::None); + build::Br(bcx, cleanup.llbb, DebugLoc::None); bcx } diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs index 8eb06731ea3..1aceb67dd12 100644 --- a/src/librustc_trans/trans/mir/mod.rs +++ b/src/librustc_trans/trans/mir/mod.rs @@ -113,7 +113,10 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) { // Allocate a `Block` for every basic block let block_bcxs: Vec> = mir_blocks.iter() - .map(|&bb| fcx.new_block(false, &format!("{:?}", bb), None)) + .map(|&bb|{ + let is_cleanup = mir.basic_block_data(bb).is_cleanup; + fcx.new_block(is_cleanup, &format!("{:?}", bb), None) + }) .collect(); // Branch to the START block