about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorSimonas Kazlauskas <git@kazlauskas.me>2015-12-19 00:44:32 +0200
committerSimonas Kazlauskas <git@kazlauskas.me>2016-01-06 13:57:51 +0200
commit4e86dcdb7295e88d3ccc28b508ba69a24fefa371 (patch)
treeb68f30dd6698552c9b331693e6b73968ad42d02f /src
parent5b34690842474019c0a1c6cd4d0a7b75108e9d2d (diff)
downloadrust-4e86dcdb7295e88d3ccc28b508ba69a24fefa371.tar.gz
rust-4e86dcdb7295e88d3ccc28b508ba69a24fefa371.zip
Remove diverge terminator
Unreachable terminator can be contained all within the trans.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/mir/repr.rs32
-rw-r--r--src/librustc/mir/visit.rs6
-rw-r--r--src/librustc_mir/build/cfg.rs12
-rw-r--r--src/librustc_mir/build/mod.rs1
-rw-r--r--src/librustc_mir/graphviz.rs4
-rw-r--r--src/librustc_mir/transform/erase_regions.rs3
-rw-r--r--src/librustc_mir/transform/simplify_cfg.rs26
-rw-r--r--src/librustc_mir/transform/util.rs2
-rw-r--r--src/librustc_trans/trans/mir/block.rs8
-rw-r--r--src/librustc_trans/trans/mir/mod.rs13
10 files changed, 40 insertions, 67 deletions
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index 8a43b8d0aaf..2878b3d5e4e 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -51,9 +51,6 @@ pub const START_BLOCK: BasicBlock = BasicBlock(0);
 /// where execution ends, on normal return
 pub const END_BLOCK: BasicBlock = BasicBlock(1);
 
-/// where execution ends, on panic
-pub const DIVERGE_BLOCK: BasicBlock = BasicBlock(2);
-
 impl<'tcx> Mir<'tcx> {
     pub fn all_basic_blocks(&self) -> Vec<BasicBlock> {
         (0..self.basic_blocks.len())
@@ -194,7 +191,7 @@ impl Debug for BasicBlock {
 #[derive(Debug, RustcEncodable, RustcDecodable)]
 pub struct BasicBlockData<'tcx> {
     pub statements: Vec<Statement<'tcx>>,
-    pub terminator: Terminator<'tcx>,
+    pub terminator: Option<Terminator<'tcx>>,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
@@ -237,14 +234,6 @@ pub enum Terminator<'tcx> {
         targets: Vec<BasicBlock>,
     },
 
-    /// Indicates that the last statement in the block panics, aborts,
-    /// etc. No successors. This terminator appears on exactly one
-    /// basic block which we create in advance. However, during
-    /// construction, we use this value as a sentinel for "terminator
-    /// not yet assigned", and assert at the end that only the
-    /// well-known diverging block actually diverges.
-    Diverge,
-
     /// Indicates that the landing pad is finished and unwinding should
     /// continue. Emitted by build::scope::diverge_cleanup.
     Resume,
@@ -317,7 +306,6 @@ impl<'tcx> Terminator<'tcx> {
             If { targets: ref b, .. } => b.as_slice(),
             Switch { targets: ref b, .. } => b,
             SwitchInt { targets: ref b, .. } => b,
-            Diverge => &[],
             Resume => &[],
             Return => &[],
             Call { targets: ref b, .. } => b.as_slice(),
@@ -336,7 +324,6 @@ impl<'tcx> Terminator<'tcx> {
             If { targets: ref mut b, .. } => b.as_mut_slice(),
             Switch { targets: ref mut b, .. } => b,
             SwitchInt { targets: ref mut b, .. } => b,
-            Diverge => &mut [],
             Resume => &mut [],
             Return => &mut [],
             Call { targets: ref mut b, .. } => b.as_mut_slice(),
@@ -350,12 +337,24 @@ impl<'tcx> Terminator<'tcx> {
 }
 
 impl<'tcx> BasicBlockData<'tcx> {
-    pub fn new(terminator: Terminator<'tcx>) -> BasicBlockData<'tcx> {
+    pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> {
         BasicBlockData {
             statements: vec![],
             terminator: terminator,
         }
     }
+
+    /// Accessor for terminator.
+    ///
+    /// Terminator may not be None after construction of the basic block is complete. This accessor
+    /// provides a convenience way to reach the terminator.
+    pub fn terminator(&self) -> &Terminator<'tcx> {
+        self.terminator.as_ref().expect("invalid terminator state")
+    }
+
+    pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> {
+        self.terminator.as_mut().expect("invalid terminator state")
+    }
 }
 
 impl<'tcx> Debug for Terminator<'tcx> {
@@ -396,7 +395,6 @@ impl<'tcx> Terminator<'tcx> {
             If { cond: ref lv, .. } => write!(fmt, "if({:?})", lv),
             Switch { discr: ref lv, .. } => write!(fmt, "switch({:?})", lv),
             SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
-            Diverge => write!(fmt, "diverge"),
             Return => write!(fmt, "return"),
             Resume => write!(fmt, "resume"),
             Call { .. } => {
@@ -414,7 +412,7 @@ impl<'tcx> Terminator<'tcx> {
     pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
         use self::Terminator::*;
         match *self {
-            Diverge | Return | Resume => vec![],
+            Return | Resume => vec![],
             Goto { .. } => vec!["".into_cow()],
             If { .. } => vec!["true".into_cow(), "false".into_cow()],
             Call { .. } => vec!["return".into_cow(), "unwind".into_cow()],
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 4d29a71c6e7..52bb9aa3d5c 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -84,7 +84,7 @@ pub trait Visitor<'tcx> {
         for statement in &data.statements {
             self.visit_statement(block, statement);
         }
-        self.visit_terminator(block, &data.terminator);
+        data.terminator.as_ref().map(|r| self.visit_terminator(block, r));
     }
 
     fn super_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) {
@@ -132,7 +132,6 @@ pub trait Visitor<'tcx> {
                 }
             }
 
-            Terminator::Diverge |
             Terminator::Resume |
             Terminator::Return => {
             }
@@ -374,7 +373,7 @@ pub trait MutVisitor<'tcx> {
         for statement in &mut data.statements {
             self.visit_statement(block, statement);
         }
-        self.visit_terminator(block, &mut data.terminator);
+        data.terminator.as_mut().map(|r| self.visit_terminator(block, r));
     }
 
     fn super_statement(&mut self,
@@ -429,7 +428,6 @@ pub trait MutVisitor<'tcx> {
                 }
             }
 
-            Terminator::Diverge |
             Terminator::Resume |
             Terminator::Return => {
             }
diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs
index d28724c30aa..2e70e6bb5ae 100644
--- a/src/librustc_mir/build/cfg.rs
+++ b/src/librustc_mir/build/cfg.rs
@@ -28,7 +28,7 @@ impl<'tcx> CFG<'tcx> {
 
     pub fn start_new_block(&mut self) -> BasicBlock {
         let node_index = self.basic_blocks.len();
-        self.basic_blocks.push(BasicBlockData::new(Terminator::Diverge));
+        self.basic_blocks.push(BasicBlockData::new(None));
         BasicBlock::new(node_index)
     }
 
@@ -67,15 +67,9 @@ impl<'tcx> CFG<'tcx> {
     pub fn terminate(&mut self,
                      block: BasicBlock,
                      terminator: Terminator<'tcx>) {
-        // Check whether this block has already been terminated. For
-        // this, we rely on the fact that the initial state is to have
-        // a Diverge terminator and an empty list of targets (which
-        // is not a valid state).
-        debug_assert!(match self.block_data(block).terminator { Terminator::Diverge => true,
-                                                                _ => false },
+        debug_assert!(self.block_data(block).terminator.is_none(),
                       "terminate: block {:?} already has a terminator set", block);
-
-        self.block_data_mut(block).terminator = terminator;
+        self.block_data_mut(block).terminator = Some(terminator);
     }
 }
 
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 8347a03cda6..e6e5b8380b2 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -107,7 +107,6 @@ pub fn construct<'a,'tcx>(mut hir: Cx<'a,'tcx>,
 
     assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
     assert_eq!(builder.cfg.start_new_block(), END_BLOCK);
-    assert_eq!(builder.cfg.start_new_block(), DIVERGE_BLOCK);
 
     let mut block = START_BLOCK;
     let arg_decls = unpack!(block = builder.args_and_body(block,
diff --git a/src/librustc_mir/graphviz.rs b/src/librustc_mir/graphviz.rs
index d1d3e80e340..1b8fe650558 100644
--- a/src/librustc_mir/graphviz.rs
+++ b/src/librustc_mir/graphviz.rs
@@ -62,7 +62,7 @@ fn write_node<W: Write>(block: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<(
     // Terminator head at the bottom, not including the list of successor blocks. Those will be
     // displayed as labels on the edges between blocks.
     let mut terminator_head = String::new();
-    data.terminator.fmt_head(&mut terminator_head).unwrap();
+    data.terminator().fmt_head(&mut terminator_head).unwrap();
     try!(write!(w, r#"<tr><td align="left">{}</td></tr>"#, dot::escape_html(&terminator_head)));
 
     // Close the table, node label, and the node itself.
@@ -71,7 +71,7 @@ fn write_node<W: Write>(block: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<(
 
 /// Write graphviz DOT edges with labels between the given basic block and all of its successors.
 fn write_edges<W: Write>(source: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<()> {
-    let terminator = &mir.basic_block_data(source).terminator;
+    let terminator = &mir.basic_block_data(source).terminator();
     let labels = terminator.fmt_successor_labels();
 
     for (&target, label) in terminator.successors().iter().zip(labels) {
diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs
index 90bb73dbe28..01d873abc6f 100644
--- a/src/librustc_mir/transform/erase_regions.rs
+++ b/src/librustc_mir/transform/erase_regions.rs
@@ -59,7 +59,7 @@ impl<'a, 'tcx> EraseRegions<'a, 'tcx> {
             self.erase_regions_statement(statement);
         }
 
-        self.erase_regions_terminator(&mut basic_block.terminator);
+        self.erase_regions_terminator(basic_block.terminator_mut());
     }
 
     fn erase_regions_statement(&mut self,
@@ -79,7 +79,6 @@ impl<'a, 'tcx> EraseRegions<'a, 'tcx> {
                                 terminator: &mut Terminator<'tcx>) {
         match *terminator {
             Terminator::Goto { .. } |
-            Terminator::Diverge |
             Terminator::Resume |
             Terminator::Return => {
                 /* nothing to do */
diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs
index d0c0afc80a6..7a5a00a8d56 100644
--- a/src/librustc_mir/transform/simplify_cfg.rs
+++ b/src/librustc_mir/transform/simplify_cfg.rs
@@ -10,7 +10,6 @@
 
 use rustc::middle::const_eval::ConstVal;
 use rustc::mir::repr::*;
-use std::mem;
 use transform::util;
 use transform::MirPass;
 
@@ -27,11 +26,10 @@ impl SimplifyCfg {
         // These blocks are always required.
         seen[START_BLOCK.index()] = true;
         seen[END_BLOCK.index()] = true;
-        seen[DIVERGE_BLOCK.index()] = true;
 
         let mut worklist = vec![START_BLOCK];
         while let Some(bb) = worklist.pop() {
-            for succ in mir.basic_block_data(bb).terminator.successors() {
+            for succ in mir.basic_block_data(bb).terminator().successors() {
                 if !seen[succ.index()] {
                     seen[succ.index()] = true;
                     worklist.push(*succ);
@@ -51,7 +49,7 @@ impl SimplifyCfg {
 
             while mir.basic_block_data(target).statements.is_empty() {
                 match mir.basic_block_data(target).terminator {
-                    Terminator::Goto { target: next } => {
+                    Some(Terminator::Goto { target: next }) => {
                         if seen.contains(&next) {
                             return None;
                         }
@@ -67,9 +65,9 @@ impl SimplifyCfg {
 
         let mut changed = false;
         for bb in mir.all_basic_blocks() {
-            // Temporarily swap out the terminator we're modifying to keep borrowck happy
-            let mut terminator = Terminator::Diverge;
-            mem::swap(&mut terminator, &mut mir.basic_block_data_mut(bb).terminator);
+            // Temporarily take ownership of the terminator we're modifying to keep borrowck happy
+            let mut terminator = mir.basic_block_data_mut(bb).terminator.take()
+                                    .expect("invalid terminator state");
 
             for target in terminator.successors_mut() {
                 let new_target = match final_target(mir, *target) {
@@ -80,10 +78,8 @@ impl SimplifyCfg {
                 changed |= *target != new_target;
                 *target = new_target;
             }
-
-            mir.basic_block_data_mut(bb).terminator = terminator;
+            mir.basic_block_data_mut(bb).terminator = Some(terminator);
         }
-
         changed
     }
 
@@ -91,11 +87,10 @@ impl SimplifyCfg {
         let mut changed = false;
 
         for bb in mir.all_basic_blocks() {
-            // Temporarily swap out the terminator we're modifying to keep borrowck happy
-            let mut terminator = Terminator::Diverge;
-            mem::swap(&mut terminator, &mut mir.basic_block_data_mut(bb).terminator);
+            let basic_block = mir.basic_block_data_mut(bb);
+            let mut terminator = basic_block.terminator_mut();
 
-            mir.basic_block_data_mut(bb).terminator = match terminator {
+            *terminator = match *terminator {
                 Terminator::If { ref targets, .. } if targets.0 == targets.1 => {
                     changed = true;
                     Terminator::Goto { target: targets.0 }
@@ -115,7 +110,7 @@ impl SimplifyCfg {
                 Terminator::SwitchInt { ref targets, .. }  if targets.len() == 1 => {
                     Terminator::Goto { target: targets[0] }
                 }
-                _ => terminator
+                _ => continue
             }
         }
 
@@ -131,7 +126,6 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg {
             changed |= self.remove_goto_chains(mir);
             self.remove_dead_blocks(mir);
         }
-
         // FIXME: Should probably be moved into some kind of pass manager
         mir.basic_blocks.shrink_to_fit();
     }
diff --git a/src/librustc_mir/transform/util.rs b/src/librustc_mir/transform/util.rs
index 95102694544..7e44beb18a2 100644
--- a/src/librustc_mir/transform/util.rs
+++ b/src/librustc_mir/transform/util.rs
@@ -15,7 +15,7 @@ use rustc::mir::repr::*;
 /// in a single pass
 pub fn update_basic_block_ids(mir: &mut Mir, replacements: &[BasicBlock]) {
     for bb in mir.all_basic_blocks() {
-        for target in mir.basic_block_data_mut(bb).terminator.successors_mut() {
+        for target in mir.basic_block_data_mut(bb).terminator_mut().successors_mut() {
             *target = replacements[target.index()];
         }
     }
diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs
index 4c2bec14e5e..c2645d9882b 100644
--- a/src/librustc_trans/trans/mir/block.rs
+++ b/src/librustc_trans/trans/mir/block.rs
@@ -33,9 +33,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             bcx = self.trans_statement(bcx, statement);
         }
 
-        debug!("trans_block: terminator: {:?}", data.terminator);
+        debug!("trans_block: terminator: {:?}", data.terminator());
 
-        match data.terminator {
+        match *data.terminator() {
             mir::Terminator::Goto { target } => {
                 build::Br(bcx, self.llblock(target), DebugLoc::None)
             }
@@ -82,10 +82,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 }
             }
 
-            mir::Terminator::Diverge => {
-                build::Unreachable(bcx);
-            }
-
             mir::Terminator::Resume => {
                 if let Some(llpersonalityslot) = self.llpersonalityslot {
                     let lp = build::Load(bcx, llpersonalityslot);
diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs
index 0ed76ebeb43..5403b53596c 100644
--- a/src/librustc_trans/trans/mir/mod.rs
+++ b/src/librustc_trans/trans/mir/mod.rs
@@ -125,16 +125,11 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
 
     // Translate the body of each block
     for &bb in &mir_blocks {
-        if bb != mir::DIVERGE_BLOCK {
-            mircx.trans_block(bb);
-        }
+        // 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);
     }
-
-    // Total hack: translate DIVERGE_BLOCK last. This is so that any
-    // panics which the fn may do can initialize the
-    // `llpersonalityslot` cell. We don't do this up front because the
-    // LLVM type of it is (frankly) annoying to compute.
-    mircx.trans_block(mir::DIVERGE_BLOCK);
 }
 
 /// Produce, for each argument, a `ValueRef` pointing at the