]> git.lizzy.rs Git - rust.git/commitdiff
Have a cached unreachable block inside MIR state
authorSimonas Kazlauskas <git@kazlauskas.me>
Sat, 19 Dec 2015 14:47:52 +0000 (16:47 +0200)
committerSimonas Kazlauskas <git@kazlauskas.me>
Wed, 6 Jan 2016 11:57:51 +0000 (13:57 +0200)
It is useful for various cases where direct unreachable cannot be translated and a separate block
is necessary.

src/librustc/mir/repr.rs
src/librustc_trans/trans/mir/block.rs
src/librustc_trans/trans/mir/mod.rs

index 2878b3d5e4e9af1da1447d2c2488384a1643fb14..f59cdb74b625de397a67a611681a57254fd18115 100644 (file)
@@ -265,7 +265,7 @@ pub enum Terminator<'tcx> {
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, RustcEncodable, RustcDecodable)]
 pub enum CallTargets {
     /// The only target that should be entered when function returns normally.
     Return(BasicBlock),
index c2645d9882b42160828af622d1a2b740788ba6d5..72d5709e02229bb7cffcd01887396f7daf044ae4 100644 (file)
@@ -9,15 +9,15 @@
 // except according to those terms.
 
 use llvm::BasicBlockRef;
-use middle::infer;
-use middle::ty;
 use rustc::mir::repr as mir;
 use trans::adt;
 use trans::base;
 use trans::build;
+use trans::attributes;
 use trans::common::{self, Block};
 use trans::debuginfo::DebugLoc;
 use trans::type_of;
+use trans::type_::Type;
 
 use super::MirContext;
 use super::operand::OperandValue::{FatPtr, Immediate, Ref};
@@ -56,10 +56,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
 
                 // The else branch of the Switch can't be hit, so branch to an unreachable
                 // instruction so LLVM knows that
-                // FIXME it might be nice to have just one such block (created lazilly), we could
-                // store it in the "MIR trans" state.
-                let unreachable_blk = bcx.fcx.new_temp_block("enum-variant-unreachable");
-                build::Unreachable(unreachable_blk);
+                let unreachable_blk = self.unreachable_block();
 
                 let switch = build::Switch(bcx, discr, unreachable_blk.llbb, targets.len());
                 assert_eq!(adt_def.variants.len(), targets.len());
@@ -164,6 +161,18 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
         }
     }
 
+    fn unreachable_block(&mut self) -> Block<'bcx, 'tcx> {
+        match self.unreachable_block {
+            Some(b) => b,
+            None => {
+                let bl = self.fcx.new_block(false, "unreachable", None);
+                build::Unreachable(bl);
+                self.unreachable_block = Some(bl);
+                bl
+            }
+        }
+    }
+
     fn bcx(&self, bb: mir::BasicBlock) -> Block<'bcx, 'tcx> {
         self.blocks[bb.index()]
     }
index 5403b53596c489d99b007514d3d647b9f9dde893..8eb06731ea3ae3c68e821d5968363795dd9c043f 100644 (file)
@@ -28,6 +28,9 @@
 pub struct MirContext<'bcx, 'tcx:'bcx> {
     mir: &'bcx mir::Mir<'tcx>,
 
+    /// Function context
+    fcx: &'bcx common::FunctionContext<'bcx, 'tcx>,
+
     /// When unwinding is initiated, we have to store this personality
     /// value somewhere so that we can load it and re-use it in the
     /// resume instruction. The personality is (afaik) some kind of
@@ -40,6 +43,9 @@ pub struct MirContext<'bcx, 'tcx:'bcx> {
     /// A `Block` for each MIR `BasicBlock`
     blocks: Vec<Block<'bcx, 'tcx>>,
 
+    /// Cached unreachable block
+    unreachable_block: Option<Block<'bcx, 'tcx>>,
+
     /// An LLVM alloca for each MIR `VarDecl`
     vars: Vec<LvalueRef<'tcx>>,
 
@@ -116,8 +122,10 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
 
     let mut mircx = MirContext {
         mir: mir,
+        fcx: fcx,
         llpersonalityslot: None,
         blocks: block_bcxs,
+        unreachable_block: None,
         vars: vars,
         temps: temps,
         args: args,