From 36b3951c7338ae0d69e125383038e76d00fc7d77 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 2 Jan 2016 00:45:21 +0200 Subject: [PATCH] Create personality slot when translating Resume This considerably simplifies code around calling functions and translation of Resume itself. This removes requirement that a block containing Resume terminator is always translated after something which creates a landing pad, thus allowing us to actually translate some valid MIRs we could not translate before. However, an assumption is added that translator is correct (in regards to landing pad generation) and code will never reach the Resume terminator without going through a landing pad first. Breaking these assumptions would pass an `undef` value into the personality functions. --- src/librustc_trans/trans/mir/block.rs | 61 ++++++++++++--------------- src/librustc_trans/trans/mir/mod.rs | 3 -- 2 files changed, 26 insertions(+), 38 deletions(-) diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index 969b9cd19d1a1..aa0b3a25ebb0c 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use llvm::BasicBlockRef; +use llvm::{BasicBlockRef, ValueRef}; use rustc::mir::repr as mir; use trans::adt; use trans::base; @@ -80,13 +80,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } mir::Terminator::Resume => { - if let Some(personalityslot) = self.llpersonalityslot { - let lp = build::Load(bcx, personalityslot); - base::call_lifetime_end(bcx, personalityslot); - build::Resume(bcx, lp); - } else { - panic!("resume terminator without personality slot set") - } + let ps = self.get_personality_slot(bcx); + let lp = build::Load(bcx, ps); + base::call_lifetime_end(bcx, ps); + base::trans_unwind_resume(bcx, lp); } mir::Terminator::Return => { @@ -187,29 +184,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { build::Br(target, postinvoketarget.llbb, debugloc); } }, - // Everything else uses the regular `Call`, but we have to be careful to - // generate landing pads for later, even if we do not use it. - // FIXME: maybe just change Resume to not panic in that case? - (_, k@&mir::CallKind::DivergingCleanup(_)) | - (_, k@&mir::CallKind::Diverging) => { - if let mir::CallKind::DivergingCleanup(_) = *k { - // make a landing pad regardless, so it sets the personality slot. - let block = self.unreachable_block(); - self.make_landing_pad(block); - } + (_, &mir::CallKind::DivergingCleanup(_)) | + (_, &mir::CallKind::Diverging) => { build::Call(bcx, callee.immediate(), &llargs[..], Some(attrs), debugloc); build::Unreachable(bcx); } (_, k@&mir::CallKind::ConvergingCleanup { .. }) | (_, k@&mir::CallKind::Converging { .. }) => { - let ret = match *k { + // Bug #20046 + let target = match *k { + mir::CallKind::ConvergingCleanup { targets, .. } => targets.0, mir::CallKind::Converging { target, .. } => target, - mir::CallKind::ConvergingCleanup { targets, .. } => { - // make a landing pad regardless (so it sets the personality slot. - let block = self.unreachable_block(); - self.make_landing_pad(block); - targets.0 - }, _ => unreachable!() }; let llret = build::Call(bcx, @@ -222,13 +207,26 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { .expect("return destination and type not set"); base::store_ty(bcx, llret, ret_dest.llval, ret_ty); } - build::Br(bcx, self.llblock(ret), debugloc) + build::Br(bcx, self.llblock(target), debugloc); } } } } } + fn get_personality_slot(&mut self, bcx: Block<'bcx, 'tcx>) -> ValueRef { + let ccx = bcx.ccx(); + if let Some(slot) = self.llpersonalityslot { + slot + } else { + let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false); + let slot = base::alloca(bcx, llretty, "personalityslot"); + self.llpersonalityslot = Some(slot); + base::call_lifetime_start(bcx, slot); + slot + } + } + 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(); @@ -236,15 +234,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false); let llretval = build::LandingPad(bcx, llretty, llpersonality, 1); build::SetCleanup(bcx, llretval); - match self.llpersonalityslot { - Some(slot) => build::Store(bcx, llretval, slot), - None => { - let personalityslot = base::alloca(bcx, llretty, "personalityslot"); - self.llpersonalityslot = Some(personalityslot); - base::call_lifetime_start(bcx, personalityslot); - build::Store(bcx, llretval, personalityslot) - } - }; + let slot = self.get_personality_slot(bcx); + build::Store(bcx, llretval, slot); 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 1aceb67dd1210..75ce33da2c9b9 100644 --- a/src/librustc_trans/trans/mir/mod.rs +++ b/src/librustc_trans/trans/mir/mod.rs @@ -136,9 +136,6 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) { // Translate the body of each block for &bb in &mir_blocks { - // NB that we do not handle the Resume terminator specially, because a block containing - // that terminator will have a higher block number than a function call which should take - // care of filling in that information. mircx.trans_block(bb); } }