about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-11-18 18:06:30 +0000
committerbors <bors@rust-lang.org>2015-11-18 18:06:30 +0000
commit3c68f646e957065fe5fabd4af850abaa8c4ee0af (patch)
tree43913dee13ff252ec221ccc871849659872a720c
parent64a65692a2cef74246dd0dab7f534b33936b748a (diff)
parentc533902285787c3cd3abd911103d8d0280c3a011 (diff)
downloadrust-3c68f646e957065fe5fabd4af850abaa8c4ee0af.tar.gz
rust-3c68f646e957065fe5fabd4af850abaa8c4ee0af.zip
Auto merge of #29886 - michaelwoerister:mir-erase-regions, r=nikomatsakis
This change adds a `MirPass` erasing all early-bound regions from MIR, right before storing it in the MIR map. I've added some assertions at neuralgic points in `trans::mir` doing cheap checks whether region have actually been erased.

Here are some assumptions that I worked under:
- AdtDef references stay untouched. It's the `Substs` accompanying them that need to be handled (e.g. in `AggregateKind::Adt`).
- We can't really get rid of late-bound regions at this point because there is no version `BareFnTy` (for example) that comes without one. These still have to be handled on demand in trans.

Are this assumptions right?

r? @nikomatsakis
-rw-r--r--src/librustc_driver/driver.rs10
-rw-r--r--src/librustc_mir/transform/erase_regions.rs234
-rw-r--r--src/librustc_mir/transform/mod.rs5
-rw-r--r--src/librustc_mir/transform/simplify_cfg.rs4
-rw-r--r--src/librustc_trans/trans/mir/constant.rs5
-rw-r--r--src/librustc_trans/trans/mir/lvalue.rs3
-rw-r--r--src/librustc_trans/trans/mir/operand.rs5
-rw-r--r--src/test/run-make/execution-engine/test.rs2
8 files changed, 257 insertions, 11 deletions
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 2d7f5544402..c284ce5551a 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -167,7 +167,7 @@ pub fn compile_input(sess: Session,
                                             tcx.print_debug_stats();
                                         }
                                         let trans = phase_4_translate_to_llvm(tcx,
-                                                                              &mir_map,
+                                                                              mir_map,
                                                                               analysis);
 
                                         if log_enabled!(::log::INFO) {
@@ -849,7 +849,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
 /// Run the translation phase to LLVM, after which the AST and analysis can
 /// be discarded.
 pub fn phase_4_translate_to_llvm<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                       mir_map: &MirMap<'tcx>,
+                                       mut mir_map: MirMap<'tcx>,
                                        analysis: ty::CrateAnalysis)
                                        -> trans::CrateTranslation {
     let time_passes = tcx.sess.time_passes();
@@ -858,10 +858,14 @@ pub fn phase_4_translate_to_llvm<'tcx>(tcx: &ty::ctxt<'tcx>,
          "resolving dependency formats",
          || dependency_format::calculate(&tcx.sess));
 
+    time(time_passes,
+         "erasing regions from MIR",
+         || mir::transform::erase_regions::erase_regions(tcx, &mut mir_map));
+
     // Option dance to work around the lack of stack once closures.
     time(time_passes,
          "translation",
-         move || trans::trans_crate(tcx, mir_map, analysis))
+         move || trans::trans_crate(tcx, &mir_map, analysis))
 }
 
 /// Run LLVM itself, producing a bitcode file, assembly file or object file
diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs
new file mode 100644
index 00000000000..e156fbf004f
--- /dev/null
+++ b/src/librustc_mir/transform/erase_regions.rs
@@ -0,0 +1,234 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This pass erases all early-bound regions from the types occuring in the MIR.
+//! We want to do this once just before trans, so trans does not have to take
+//! care erasing regions all over the place.
+
+use repr::*;
+use rustc::middle::ty;
+use transform::MirPass;
+use mir_map::MirMap;
+
+pub fn erase_regions<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &mut MirMap<'tcx>) {
+    let mut eraser = EraseRegions::new(tcx);
+
+    for mir in mir_map.iter_mut().map(|(_, v)| v) {
+        eraser.run_on_mir(mir);
+    }
+}
+
+pub struct EraseRegions<'a, 'tcx: 'a> {
+    tcx: &'a ty::ctxt<'tcx>,
+}
+
+impl<'a, 'tcx> MirPass<'tcx> for EraseRegions<'a, 'tcx> {
+
+    fn run_on_mir(&mut self, mir: &mut Mir<'tcx>) {
+
+        for basic_block in &mut mir.basic_blocks {
+            self.erase_regions_basic_block(basic_block);
+        }
+
+        self.erase_regions_return_ty(&mut mir.return_ty);
+
+        self.erase_regions_tys(mir.var_decls.iter_mut().map(|d| &mut d.ty));
+        self.erase_regions_tys(mir.arg_decls.iter_mut().map(|d| &mut d.ty));
+        self.erase_regions_tys(mir.temp_decls.iter_mut().map(|d| &mut d.ty));
+    }
+}
+
+impl<'a, 'tcx> EraseRegions<'a, 'tcx> {
+
+    pub fn new(tcx: &'a ty::ctxt<'tcx>) -> EraseRegions<'a, 'tcx> {
+        EraseRegions {
+            tcx: tcx
+        }
+    }
+
+    fn erase_regions_basic_block(&mut self,
+                                 basic_block: &mut BasicBlockData<'tcx>) {
+        for statement in &mut basic_block.statements {
+            self.erase_regions_statement(statement);
+        }
+
+        self.erase_regions_terminator(&mut basic_block.terminator);
+    }
+
+    fn erase_regions_statement(&mut self,
+                               statement: &mut Statement<'tcx>) {
+        match statement.kind {
+            StatementKind::Assign(ref mut lvalue, ref mut rvalue) => {
+                self.erase_regions_lvalue(lvalue);
+                self.erase_regions_rvalue(rvalue);
+            }
+            StatementKind::Drop(_, ref mut lvalue) => {
+                self.erase_regions_lvalue(lvalue);
+            }
+        }
+    }
+
+    fn erase_regions_terminator(&mut self,
+                                terminator: &mut Terminator<'tcx>) {
+        match *terminator {
+            Terminator::Goto { .. } |
+            Terminator::Diverge |
+            Terminator::Return |
+            Terminator::Panic { .. } => {
+                /* nothing to do */
+            }
+            Terminator::If { ref mut cond, .. } => {
+                self.erase_regions_operand(cond);
+            }
+            Terminator::Switch { ref mut discr, .. } => {
+                self.erase_regions_lvalue(discr);
+            }
+            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
+                },
+                ..
+            } => {
+                self.erase_regions_lvalue(destination);
+                self.erase_regions_operand(func);
+                for arg in &mut *args {
+                    self.erase_regions_operand(arg);
+                }
+            }
+        }
+    }
+
+    fn erase_regions_operand(&mut self, operand: &mut Operand<'tcx>) {
+        match *operand {
+            Operand::Consume(ref mut lvalue) => {
+                self.erase_regions_lvalue(lvalue);
+            }
+            Operand::Constant(ref mut constant) => {
+                self.erase_regions_constant(constant);
+            }
+        }
+    }
+
+    fn erase_regions_lvalue(&mut self, lvalue: &mut Lvalue<'tcx>) {
+        match *lvalue {
+            Lvalue::Var(_)        |
+            Lvalue::Temp(_)       |
+            Lvalue::Arg(_)        |
+            Lvalue::Static(_)     |
+            Lvalue::ReturnPointer => {}
+            Lvalue::Projection(ref mut lvalue_projection) => {
+                self.erase_regions_lvalue(&mut lvalue_projection.base);
+                match lvalue_projection.elem {
+                    ProjectionElem::Deref              |
+                    ProjectionElem::Field(_)           |
+                    ProjectionElem::Downcast(..)       |
+                    ProjectionElem::ConstantIndex {..} => { /* nothing to do */ }
+                    ProjectionElem::Index(ref mut index) => {
+                        self.erase_regions_operand(index);
+                    }
+                }
+            }
+        }
+    }
+
+    fn erase_regions_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>) {
+        match *rvalue {
+            Rvalue::Use(ref mut operand) => {
+                self.erase_regions_operand(operand)
+            }
+            Rvalue::Repeat(ref mut operand, ref mut constant) => {
+                self.erase_regions_operand(operand);
+                self.erase_regions_constant(constant);
+            }
+            Rvalue::Ref(ref mut region, _, ref mut lvalue) => {
+                *region = ty::ReStatic;
+                self.erase_regions_lvalue(lvalue);
+            }
+            Rvalue::Len(ref mut lvalue) => self.erase_regions_lvalue(lvalue),
+            Rvalue::Cast(_, ref mut operand, ref mut ty) => {
+                self.erase_regions_operand(operand);
+                *ty = self.tcx.erase_regions(ty);
+            }
+            Rvalue::BinaryOp(_, ref mut operand1, ref mut operand2) => {
+                self.erase_regions_operand(operand1);
+                self.erase_regions_operand(operand2);
+            }
+            Rvalue::UnaryOp(_, ref mut operand) => {
+                self.erase_regions_operand(operand);
+            }
+            Rvalue::Box(ref mut ty) => *ty = self.tcx.erase_regions(ty),
+            Rvalue::Aggregate(ref mut aggregate_kind, ref mut operands) => {
+                match *aggregate_kind {
+                    AggregateKind::Vec   |
+                    AggregateKind::Tuple => {},
+                    AggregateKind::Adt(_, _, ref mut substs) => {
+                        let erased = self.tcx.erase_regions(*substs);
+                        *substs = self.tcx.mk_substs(erased);
+                    }
+                    AggregateKind::Closure(def_id, ref mut closure_substs) => {
+                        let cloned = Box::new(closure_substs.clone());
+                        let ty = self.tcx.mk_closure_from_closure_substs(def_id,
+                                                                         cloned);
+                        let erased = self.tcx.erase_regions(&ty);
+                        *closure_substs = match erased.sty {
+                            ty::TyClosure(_, ref closure_substs) => &*closure_substs,
+                            _ => unreachable!()
+                        };
+                    }
+                }
+                for operand in &mut *operands {
+                    self.erase_regions_operand(operand);
+                }
+            }
+            Rvalue::Slice { ref mut input, .. } => {
+                self.erase_regions_lvalue(input);
+            }
+            Rvalue::InlineAsm(_) => {},
+        }
+    }
+
+    fn erase_regions_constant(&mut self, constant: &mut Constant<'tcx>) {
+        constant.ty = self.tcx.erase_regions(&constant.ty);
+        match constant.literal {
+            Literal::Item { ref mut substs, .. } => {
+                *substs = self.tcx.mk_substs(self.tcx.erase_regions(substs));
+            }
+            Literal::Value { .. } => { /* nothing to do */ }
+        }
+    }
+
+    fn erase_regions_return_ty(&mut self, fn_output: &mut ty::FnOutput<'tcx>) {
+        match *fn_output {
+            ty::FnConverging(ref mut ty) => {
+                *ty = self.tcx.erase_regions(ty);
+            },
+            ty::FnDiverging => {}
+        }
+    }
+
+    fn erase_regions_tys<'b, T>(&mut self, tys: T)
+        where T: Iterator<Item = &'b mut ty::Ty<'tcx>>,
+              'tcx: 'b
+    {
+        for ty in tys {
+            *ty = self.tcx.erase_regions(ty);
+        }
+    }
+}
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index bee6d4d7ddd..9bec934143f 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -9,10 +9,11 @@
 // except according to those terms.
 
 pub mod simplify_cfg;
+pub mod erase_regions;
 mod util;
 
 use repr::Mir;
 
-pub trait MirPass {
-    fn run_on_mir(&mut self, mir: &mut Mir);
+pub trait MirPass<'tcx> {
+    fn run_on_mir(&mut self, mir: &mut Mir<'tcx>);
 }
diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs
index 71dd2f077fe..ee9dcbf1203 100644
--- a/src/librustc_mir/transform/simplify_cfg.rs
+++ b/src/librustc_mir/transform/simplify_cfg.rs
@@ -120,8 +120,8 @@ impl SimplifyCfg {
     }
 }
 
-impl MirPass for SimplifyCfg {
-    fn run_on_mir(&mut self, mir: &mut Mir) {
+impl<'tcx> MirPass<'tcx> for SimplifyCfg {
+    fn run_on_mir(&mut self, mir: &mut Mir<'tcx>) {
         let mut changed = true;
         while changed {
             changed = self.simplify_branches(mir);
diff --git a/src/librustc_trans/trans/mir/constant.rs b/src/librustc_trans/trans/mir/constant.rs
index 8c0d8b10bfe..9af5bb43318 100644
--- a/src/librustc_trans/trans/mir/constant.rs
+++ b/src/librustc_trans/trans/mir/constant.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use middle::ty::Ty;
+use middle::ty::{Ty, HasTypeFlags};
 use rustc::middle::const_eval::ConstVal;
 use rustc_mir::repr as mir;
 use trans::consts::{self, TrueConst};
@@ -63,6 +63,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 unimplemented!()
             }
         };
+
+        assert!(!ty.has_erasable_regions());
+
         OperandRef {
             ty: ty,
             val: val
diff --git a/src/librustc_trans/trans/mir/lvalue.rs b/src/librustc_trans/trans/mir/lvalue.rs
index ff80451d2b1..1f39a2aa048 100644
--- a/src/librustc_trans/trans/mir/lvalue.rs
+++ b/src/librustc_trans/trans/mir/lvalue.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use llvm::ValueRef;
-use rustc::middle::ty::{self, Ty};
+use rustc::middle::ty::{self, Ty, HasTypeFlags};
 use rustc_mir::repr as mir;
 use rustc_mir::tcx::LvalueTy;
 use trans::adt;
@@ -45,6 +45,7 @@ impl<'tcx> LvalueRef<'tcx> {
                         name: &str)
                         -> LvalueRef<'tcx>
     {
+        assert!(!ty.has_erasable_regions());
         let lltemp = base::alloc_ty(bcx, ty, name);
         LvalueRef::new_sized(lltemp, LvalueTy::from_ty(ty))
     }
diff --git a/src/librustc_trans/trans/mir/operand.rs b/src/librustc_trans/trans/mir/operand.rs
index 63abdfe2dd9..75d7b574382 100644
--- a/src/librustc_trans/trans/mir/operand.rs
+++ b/src/librustc_trans/trans/mir/operand.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use llvm::ValueRef;
-use rustc::middle::ty::Ty;
+use rustc::middle::ty::{Ty, HasTypeFlags};
 use rustc_mir::repr as mir;
 use trans::base;
 use trans::common::{self, Block};
@@ -122,6 +122,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     }
                     datum::ByRef => OperandValue::Ref(tr_lvalue.llval)
                 };
+
+                assert!(!ty.has_erasable_regions());
+
                 OperandRef {
                     val: val,
                     ty: ty
diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs
index f2dd155595a..8ca64e866a0 100644
--- a/src/test/run-make/execution-engine/test.rs
+++ b/src/test/run-make/execution-engine/test.rs
@@ -231,7 +231,7 @@ fn compile_program(input: &str, sysroot: PathBuf)
         driver::phase_3_run_analysis_passes(
             &sess, ast_map, &arenas, &id, MakeGlobMap::No, |tcx, mir_map, analysis| {
 
-            let trans = driver::phase_4_translate_to_llvm(tcx, &mir_map, analysis);
+            let trans = driver::phase_4_translate_to_llvm(tcx, mir_map, analysis);
 
             let crates = tcx.sess.cstore.get_used_crates(RequireDynamic);