diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 75a588d424e..42c9b7b0f39 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -256,13 +256,51 @@ pub enum Terminator<'tcx> { /// `END_BLOCK`. Return, - /// block ends with a call; it should have two successors. The - /// first successor indicates normal return. The second indicates - /// unwinding. + /// Block ends with a call of a converging function Call { - data: CallData<'tcx>, - targets: (BasicBlock, BasicBlock), + /// The function that’s being called + func: Operand<'tcx>, + /// Arguments the function is called with + args: Vec>, + /// Location to write the return value into + destination: Lvalue<'tcx>, + targets: CallTargets, }, + + /// Block ends with a call of a diverging function. + DivergingCall { + /// The function that’s being called + func: Operand<'tcx>, + /// Arguments the function is called with + args: Vec>, + /// Some, if there’s any cleanup to be done when function unwinds + cleanup: Option, + } +} + +#[derive(RustcEncodable, RustcDecodable)] +pub enum CallTargets { + /// The only target that should be entered when function returns normally. + Return(BasicBlock), + /// In addition to the normal-return block, function has associated cleanup that should be done + /// when function unwinds. + WithCleanup((BasicBlock, BasicBlock)) +} + +impl CallTargets { + pub fn as_slice(&self) -> &[BasicBlock] { + match *self { + CallTargets::Return(ref b) => slice::ref_slice(b), + CallTargets::WithCleanup(ref bs) => bs.as_slice() + } + } + + pub fn as_mut_slice(&mut self) -> &mut [BasicBlock] { + match *self { + CallTargets::Return(ref mut b) => slice::mut_ref_slice(b), + CallTargets::WithCleanup(ref mut bs) => bs.as_mut_slice() + } + } } impl<'tcx> Terminator<'tcx> { @@ -271,12 +309,17 @@ impl<'tcx> Terminator<'tcx> { match *self { Goto { target: ref b } => slice::ref_slice(b), Panic { target: ref b } => slice::ref_slice(b), - If { cond: _, targets: ref b } => b.as_slice(), + If { targets: ref b, .. } => b.as_slice(), Switch { targets: ref b, .. } => b, SwitchInt { targets: ref b, .. } => b, Diverge => &[], Return => &[], - Call { data: _, targets: ref b } => b.as_slice(), + Call { targets: ref b, .. } => b.as_slice(), + DivergingCall { cleanup: ref b, .. } => if let Some(b) = b.as_ref() { + slice::ref_slice(b) + } else { + &mut [] + }, } } @@ -285,28 +328,21 @@ impl<'tcx> Terminator<'tcx> { match *self { Goto { target: ref mut b } => slice::mut_ref_slice(b), Panic { target: ref mut b } => slice::mut_ref_slice(b), - If { cond: _, targets: ref mut b } => b.as_mut_slice(), + If { targets: ref mut b, .. } => b.as_mut_slice(), Switch { targets: ref mut b, .. } => b, SwitchInt { targets: ref mut b, .. } => b, Diverge => &mut [], Return => &mut [], - Call { data: _, targets: ref mut b } => b.as_mut_slice(), + Call { targets: ref mut b, .. } => b.as_mut_slice(), + DivergingCall { cleanup: ref mut b, .. } => if let Some(b) = b.as_mut() { + slice::mut_ref_slice(b) + } else { + &mut [] + }, } } } -#[derive(Debug, RustcEncodable, RustcDecodable)] -pub struct CallData<'tcx> { - /// where the return value is written to - pub destination: Lvalue<'tcx>, - - /// the fn being called - pub func: Operand<'tcx>, - - /// the arguments - pub args: Vec>, -} - impl<'tcx> BasicBlockData<'tcx> { pub fn new(terminator: Terminator<'tcx>) -> BasicBlockData<'tcx> { BasicBlockData { @@ -357,15 +393,13 @@ impl<'tcx> Terminator<'tcx> { SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv), Diverge => write!(fmt, "diverge"), Return => write!(fmt, "return"), - Call { data: ref c, .. } => { - try!(write!(fmt, "{:?} = {:?}(", c.destination, c.func)); - for (index, arg) in c.args.iter().enumerate() { - if index > 0 { - try!(write!(fmt, ", ")); - } - try!(write!(fmt, "{:?}", arg)); - } - write!(fmt, ")") + Call { .. } => { + // the author didn’t bother rebasing this + unimplemented!() + }, + DivergingCall { .. } => { + // the author didn’t bother rebasing this + unimplemented!() } } } @@ -378,6 +412,7 @@ impl<'tcx> Terminator<'tcx> { Goto { .. } | Panic { .. } => vec!["".into_cow()], If { .. } => vec!["true".into_cow(), "false".into_cow()], Call { .. } => vec!["return".into_cow(), "unwind".into_cow()], + DivergingCall { .. } => vec!["unwind".into_cow()], Switch { ref adt_def, .. } => { adt_def.variants .iter() diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 00d21d3c16e..c3a335fdfaa 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -137,16 +137,26 @@ pub trait Visitor<'tcx> { Terminator::Return => { } - Terminator::Call { ref data, ref targets } => { - self.visit_lvalue(&data.destination, LvalueContext::Store); - self.visit_operand(&data.func); - for arg in &data.args { + Terminator::Call { ref func, ref args, ref destination, ref targets } => { + self.visit_lvalue(destination, LvalueContext::Store); + self.visit_operand(func); + for arg in args { self.visit_operand(arg); } for &target in targets.as_slice() { self.visit_branch(block, target); } } + + Terminator::DivergingCall { ref func, ref args, ref cleanup } => { + self.visit_operand(func); + for arg in args { + self.visit_operand(arg); + } + for &target in cleanup.as_ref() { + self.visit_branch(block, target); + } + } } } @@ -424,16 +434,29 @@ pub trait MutVisitor<'tcx> { Terminator::Return => { } - Terminator::Call { ref mut data, ref mut targets } => { - self.visit_lvalue(&mut data.destination, LvalueContext::Store); - self.visit_operand(&mut data.func); - for arg in &mut data.args { + Terminator::Call { ref mut func, + ref mut args, + ref mut destination, + ref mut targets } => { + self.visit_lvalue(destination, LvalueContext::Store); + self.visit_operand(func); + for arg in args { self.visit_operand(arg); } for &target in targets.as_slice() { self.visit_branch(block, target); } } + + Terminator::DivergingCall { ref mut func, ref mut args, ref mut cleanup } => { + self.visit_operand(func); + for arg in args { + self.visit_operand(arg); + } + for &target in cleanup.as_ref() { + self.visit_branch(block, target); + } + } } } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 802c55ce764..4a262196d36 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -218,14 +218,13 @@ impl<'a,'tcx> Builder<'a,'tcx> { .collect(); let success = this.cfg.start_new_block(); let panic = this.diverge_cleanup(); + let targets = CallTargets::WithCleanup((success, panic)); this.cfg.terminate(block, Terminator::Call { - data: CallData { - destination: destination.clone(), - func: fun, - args: args, - }, - targets: (success, panic), + func: fun, + args: args, + destination: destination.clone(), + targets: targets }); success.unit() } diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 1eb3bfd7e02..1e7bb305cdb 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -90,28 +90,23 @@ impl<'a, 'tcx> EraseRegions<'a, 'tcx> { Terminator::Switch { ref mut discr, .. } => { self.erase_regions_lvalue(discr); } - Terminator::SwitchInt { - ref mut discr, - ref mut switch_ty, - .. - } => { + Terminator::SwitchInt { ref mut discr, ref mut switch_ty, .. } => { self.erase_regions_lvalue(discr); *switch_ty = self.tcx.erase_regions(switch_ty); }, - Terminator::Call { - data: CallData { - ref mut destination, - ref mut func, - ref mut args - }, - .. - } => { + Terminator::Call { ref mut destination, ref mut func, ref mut args, .. } => { self.erase_regions_lvalue(destination); self.erase_regions_operand(func); for arg in &mut *args { self.erase_regions_operand(arg); } } + Terminator::DivergingCall { ref mut func, ref mut args, .. } => { + self.erase_regions_operand(func); + for arg in &mut *args { + self.erase_regions_operand(arg); + } + } } } diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index 265969c52b3..00508ed21e5 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -164,6 +164,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } build::Br(bcx, self.llblock(targets.0), DebugLoc::None) + }, + + mir::Terminator::DivergingCall { .. } => { + unimplemented!() } } }