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 or the MIT license +// , 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>, + '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);