From 811b874716210f0e4135cbaa489f8b2857bbb031 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 26 Feb 2016 18:05:50 +0200 Subject: [PATCH] Add Pass manager for MIR --- src/librustc/dep_graph/mod.rs | 1 + src/librustc/mir/mir_map.rs | 22 ------- src/librustc/mir/repr.rs | 2 +- src/librustc/mir/transform.rs | 63 +++++++++++++++++- src/librustc/session/mod.rs | 6 +- src/librustc_driver/driver.rs | 28 ++++---- src/librustc_mir/mir_map.rs | 61 ++--------------- src/librustc_mir/transform/erase_regions.rs | 18 +++-- src/librustc_mir/transform/mod.rs | 2 +- src/librustc_mir/transform/no_landing_pads.rs | 13 ++-- ...r_dead_blocks.rs => remove_dead_blocks.rs} | 65 ++++++++++--------- src/librustc_mir/transform/simplify_cfg.rs | 56 +++------------- src/librustc_mir/transform/type_check.rs | 37 ++++++----- src/librustc_plugin/registry.rs | 6 +- src/test/auxiliary/dummy_mir_pass.rs | 9 +-- 15 files changed, 177 insertions(+), 212 deletions(-) rename src/librustc_mir/transform/{clear_dead_blocks.rs => remove_dead_blocks.rs} (53%) diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 2fad161652f69..3a04b48bb83a4 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -70,6 +70,7 @@ pub enum DepNode { IntrinsicCheck(DefId), MatchCheck(DefId), MirMapConstruction(DefId), + MirPasses, BorrowCheck(DefId), RvalueCheck(DefId), Reachability, diff --git a/src/librustc/mir/mir_map.rs b/src/librustc/mir/mir_map.rs index 933621b765f93..1a34699aff491 100644 --- a/src/librustc/mir/mir_map.rs +++ b/src/librustc/mir/mir_map.rs @@ -8,31 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use dep_graph::DepNode; use util::nodemap::NodeMap; use mir::repr::Mir; -use mir::transform::MirPass; -use middle::ty::{self, TyCtxt}; -use middle::infer; pub struct MirMap<'tcx> { pub map: NodeMap>, } - -impl<'tcx> MirMap<'tcx> { - pub fn run_passes(&mut self, passes: &mut [Box], tcx: &TyCtxt<'tcx>) { - if passes.is_empty() { return; } - - for (&id, mir) in &mut self.map { - let did = tcx.map.local_def_id(id); - let _task = tcx.dep_graph.in_task(DepNode::MirMapConstruction(did)); - - let param_env = ty::ParameterEnvironment::for_item(tcx, id); - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env)); - - for pass in &mut *passes { - pass.run_on_mir(mir, &infcx) - } - } - } -} diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index ce7b1ceb35540..348b496112ca0 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -207,7 +207,7 @@ impl Debug for BasicBlock { } /////////////////////////////////////////////////////////////////////////// -// BasicBlock and Terminator +// BasicBlockData and Terminator #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct BasicBlockData<'tcx> { diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index cc417f5a99ea6..5f09fe042a57a 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -8,9 +8,66 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use mir::mir_map::MirMap; use mir::repr::Mir; -use middle::infer::InferCtxt; +use middle::ty::TyCtxt; -pub trait MirPass { - fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, infcx: &InferCtxt<'a, 'tcx>); +/// Various information about pass. +pub trait Pass { + // fn name() for printouts of various sorts? + // fn should_run(Session) to check if pass should run? +} + +/// A pass which inspects the whole MirMap. +pub trait MirMapPass<'tcx>: Pass { + fn run_pass(&mut self, cx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>); +} + +pub trait MirPass<'tcx>: Pass { + fn run_pass(&mut self, cx: &TyCtxt<'tcx>, map: &mut Mir<'tcx>); +} + +impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T { + fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>) { + for (_, mir) in &mut map.map { + MirPass::run_pass(self, tcx, mir); + } + } +} + +/// A manager for MIR passes. +pub struct Passes { + passes: Vec MirMapPass<'tcx>>>, + plugin_passes: Vec MirMapPass<'tcx>>> +} + +impl Passes { + pub fn new() -> Passes { + let passes = Passes { + passes: Vec::new(), + plugin_passes: Vec::new() + }; + passes + } + + pub fn run_passes<'tcx>(&mut self, pcx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>) { + for pass in &mut self.plugin_passes { + pass.run_pass(pcx, map); + } + for pass in &mut self.passes { + pass.run_pass(pcx, map); + } + } + + /// Pushes a built-in pass. + pub fn push_pass(&mut self, pass: Box MirMapPass<'a>>) { + self.passes.push(pass); + } +} + +/// Copies the plugin passes. +impl ::std::iter::Extend MirMapPass<'a>>> for Passes { + fn extend MirMapPass<'a>>>>(&mut self, it: I) { + self.plugin_passes.extend(it); + } } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index d2f8d3f09fd7c..b198eda181208 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -13,7 +13,7 @@ use middle::cstore::CrateStore; use middle::dependency_format; use session::search_paths::PathKind; use util::nodemap::{NodeMap, FnvHashMap}; -use mir::transform::MirPass; +use mir::transform as mir_pass; use syntax::ast::{NodeId, NodeIdAssigner, Name}; use syntax::codemap::{Span, MultiSpan}; @@ -60,7 +60,7 @@ pub struct Session { pub lint_store: RefCell, pub lints: RefCell>>, pub plugin_llvm_passes: RefCell>, - pub plugin_mir_passes: RefCell>>, + pub mir_passes: RefCell, pub plugin_attributes: RefCell>, pub crate_types: RefCell>, pub dependency_formats: RefCell, @@ -477,7 +477,7 @@ pub fn build_session_(sopts: config::Options, lint_store: RefCell::new(lint::LintStore::new()), lints: RefCell::new(NodeMap()), plugin_llvm_passes: RefCell::new(Vec::new()), - plugin_mir_passes: RefCell::new(Vec::new()), + mir_passes: RefCell::new(mir_pass::Passes::new()), plugin_attributes: RefCell::new(Vec::new()), crate_types: RefCell::new(Vec::new()), dependency_formats: RefCell::new(FnvHashMap()), diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9c1be4c9f2f3e..d6bbb22c203c8 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::dep_graph::DepGraph; +use rustc::dep_graph::{DepGraph, DepNode}; use rustc::front; use rustc::front::map as hir_map; use rustc_mir as mir; @@ -561,7 +561,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, } *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; - *sess.plugin_mir_passes.borrow_mut() = mir_passes; + sess.mir_passes.borrow_mut().extend(mir_passes); *sess.plugin_attributes.borrow_mut() = attributes.clone(); })); @@ -861,9 +861,20 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, "MIR dump", || mir::mir_map::build_mir_for_crate(tcx)); - time(time_passes, - "MIR passes", - || mir_map.run_passes(&mut sess.plugin_mir_passes.borrow_mut(), tcx)); + time(time_passes, "MIR passes", || { + let _task = tcx.dep_graph.in_task(DepNode::MirPasses); + let mut passes = sess.mir_passes.borrow_mut(); + // Push all the built-in passes. + passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks); + passes.push_pass(box mir::transform::type_check::TypeckMir); + passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg); + // Late passes + passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); + passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks); + passes.push_pass(box mir::transform::erase_regions::EraseRegions); + // And run everything. + passes.run_passes(tcx, &mut mir_map); + }); time(time_passes, "borrow checking", @@ -912,9 +923,8 @@ 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: &TyCtxt<'tcx>, - mut mir_map: MirMap<'tcx>, + mir_map: MirMap<'tcx>, analysis: ty::CrateAnalysis) -> trans::CrateTranslation { let time_passes = tcx.sess.time_passes(); @@ -923,10 +933,6 @@ pub fn phase_4_translate_to_llvm<'tcx>(tcx: &TyCtxt<'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", diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 96828628888be..400035a15de75 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -20,16 +20,10 @@ extern crate syntax; extern crate rustc_front; use build; -use graphviz; -use pretty; -use transform::{clear_dead_blocks, simplify_cfg, type_check}; -use transform::{no_landing_pads}; use rustc::dep_graph::DepNode; use rustc::mir::repr::Mir; use hair::cx::Cx; -use std::fs::File; -use rustc::mir::transform::MirPass; use rustc::mir::mir_map::MirMap; use rustc::middle::infer; use rustc::middle::region::CodeExtentData; @@ -136,61 +130,16 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> { body: &'tcx hir::Block, span: Span, id: ast::NodeId) { - let (prefix, implicit_arg_tys) = match fk { - intravisit::FnKind::Closure => - (format!("{}-", id), vec![closure_self_ty(&self.tcx, id, body.id)]), - _ => - (format!(""), vec![]), + let implicit_arg_tys = if let intravisit::FnKind::Closure = fk { + vec![closure_self_ty(&self.tcx, id, body.id)] + } else { + vec![] }; let param_env = ty::ParameterEnvironment::for_item(self.tcx, id); - let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env)); - match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) { - Ok(mut mir) => { - clear_dead_blocks::ClearDeadBlocks::new().run_on_mir(&mut mir, &infcx); - type_check::TypeckMir::new().run_on_mir(&mut mir, &infcx); - no_landing_pads::NoLandingPads.run_on_mir(&mut mir, &infcx); - if self.tcx.sess.opts.mir_opt_level > 0 { - simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir, &infcx); - } - let meta_item_list = self.attr - .iter() - .flat_map(|a| a.meta_item_list()) - .flat_map(|l| l.iter()); - for item in meta_item_list { - if item.check_name("graphviz") || item.check_name("pretty") { - match item.value_str() { - Some(s) => { - let filename = format!("{}{}", prefix, s); - let result = File::create(&filename).and_then(|ref mut output| { - if item.check_name("graphviz") { - graphviz::write_mir_graphviz(&mir, output) - } else { - pretty::write_mir_pretty(&mir, output) - } - }); - - if let Err(e) = result { - self.tcx.sess.span_fatal( - item.span, - &format!("Error writing MIR {} results to `{}`: {}", - item.name(), filename, e)); - } - } - None => { - self.tcx.sess.span_err( - item.span, - &format!("{} attribute requires a path", item.name())); - } - } - } - } - - let previous = self.map.map.insert(id, mir); - assert!(previous.is_none()); - } + Ok(mir) => assert!(self.map.map.insert(id, mir).is_none()), Err(ErrorReported) => {} } diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 53d88709add9d..2bab0168c5232 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -15,13 +15,7 @@ use rustc::middle::ty::{self, TyCtxt}; use rustc::mir::repr::*; use rustc::mir::visit::MutVisitor; -use rustc::mir::mir_map::MirMap; - -pub fn erase_regions<'tcx>(tcx: &TyCtxt<'tcx>, mir_map: &mut MirMap<'tcx>) { - for (_, mir) in &mut mir_map.map { - EraseRegionsVisitor::new(tcx).visit_mir(mir); - } -} +use rustc::mir::transform::{MirPass, Pass}; struct EraseRegionsVisitor<'a, 'tcx: 'a> { tcx: &'a TyCtxt<'tcx>, @@ -123,3 +117,13 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> { self.super_constant(constant); } } + +pub struct EraseRegions; + +impl Pass for EraseRegions {} + +impl<'tcx> MirPass<'tcx> for EraseRegions { + fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, mir: &mut Mir<'tcx>) { + EraseRegionsVisitor::new(tcx).visit_mir(mir); + } +} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index adca68114fd01..57690caeccb37 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub mod clear_dead_blocks; +pub mod remove_dead_blocks; pub mod simplify_cfg; pub mod erase_regions; pub mod no_landing_pads; diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index e2c93bd4e8751..c08f45a8ec4e3 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -11,10 +11,10 @@ //! This pass removes the unwind branch of all the terminators when the no-landing-pads option is //! specified. -use rustc::middle::infer; +use rustc::middle::ty::TyCtxt; use rustc::mir::repr::*; use rustc::mir::visit::MutVisitor; -use rustc::mir::transform::MirPass; +use rustc::mir::transform::{Pass, MirPass}; pub struct NoLandingPads; @@ -40,11 +40,12 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads { } } -impl MirPass for NoLandingPads { - fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, - infcx: &infer::InferCtxt<'a, 'tcx>) { - if infcx.tcx.sess.no_landing_pads() { +impl<'tcx> MirPass<'tcx> for NoLandingPads { + fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, mir: &mut Mir<'tcx>) { + if tcx.sess.no_landing_pads() { self.visit_mir(mir); } } } + +impl Pass for NoLandingPads {} diff --git a/src/librustc_mir/transform/clear_dead_blocks.rs b/src/librustc_mir/transform/remove_dead_blocks.rs similarity index 53% rename from src/librustc_mir/transform/clear_dead_blocks.rs rename to src/librustc_mir/transform/remove_dead_blocks.rs index b35d8c08f5dc1..308e257c20d09 100644 --- a/src/librustc_mir/transform/clear_dead_blocks.rs +++ b/src/librustc_mir/transform/remove_dead_blocks.rs @@ -32,50 +32,55 @@ //! this pass just replaces the blocks with empty "return" blocks //! and does not renumber anything. -use rustc::middle::infer; +use rustc_data_structures::bitvec::BitVector; +use rustc::middle::ty::TyCtxt; use rustc::mir::repr::*; -use rustc::mir::transform::MirPass; +use rustc::mir::transform::{Pass, MirPass}; -pub struct ClearDeadBlocks; - -impl ClearDeadBlocks { - pub fn new() -> ClearDeadBlocks { - ClearDeadBlocks - } - - fn clear_dead_blocks(&self, mir: &mut Mir) { - let mut seen = vec![false; mir.basic_blocks.len()]; +pub struct RemoveDeadBlocks; +impl<'tcx> MirPass<'tcx> for RemoveDeadBlocks { + fn run_pass(&mut self, _: &TyCtxt<'tcx>, mir: &mut Mir<'tcx>) { + let mut seen = BitVector::new(mir.basic_blocks.len()); // These blocks are always required. - seen[START_BLOCK.index()] = true; - seen[END_BLOCK.index()] = true; + seen.insert(START_BLOCK.index()); + seen.insert(END_BLOCK.index()); - let mut worklist = vec![START_BLOCK]; + let mut worklist = Vec::with_capacity(4); + worklist.push(START_BLOCK); while let Some(bb) = worklist.pop() { for succ in mir.basic_block_data(bb).terminator().successors().iter() { - if !seen[succ.index()] { - seen[succ.index()] = true; + if seen.insert(succ.index()) { worklist.push(*succ); } } } + retain_basic_blocks(mir, &seen); + } +} - for (n, (block, seen)) in mir.basic_blocks.iter_mut().zip(seen).enumerate() { - if !seen { - info!("clearing block #{}: {:?}", n, block); - *block = BasicBlockData { - statements: vec![], - terminator: Some(Terminator::Return), - is_cleanup: false - }; - } +impl Pass for RemoveDeadBlocks {} + +/// Mass removal of basic blocks to keep the ID-remapping cheap. +fn retain_basic_blocks(mir: &mut Mir, keep: &BitVector) { + let num_blocks = mir.basic_blocks.len(); + + let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); + let mut used_blocks = 0; + for alive_index in keep.iter() { + replacements[alive_index] = BasicBlock::new(used_blocks); + if alive_index != used_blocks { + // Swap the next alive block data with the current available slot. Since alive_index is + // non-decreasing this is a valid operation. + mir.basic_blocks.swap(alive_index, used_blocks); } + used_blocks += 1; } -} + mir.basic_blocks.truncate(used_blocks); -impl MirPass for ClearDeadBlocks { - fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &infer::InferCtxt<'a, 'tcx>) - { - self.clear_dead_blocks(mir); + for bb in mir.all_basic_blocks() { + for target in mir.basic_block_data_mut(bb).terminator_mut().successors_mut() { + *target = replacements[target.index()]; + } } } diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs index 785e6db57a538..85f36df7ced8f 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify_cfg.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc_data_structures::bitvec::BitVector; use rustc::middle::const_eval::ConstVal; -use rustc::middle::infer; +use rustc::middle::ty::TyCtxt; use rustc::mir::repr::*; -use rustc::mir::transform::MirPass; +use rustc::mir::transform::{MirPass, Pass}; + +use super::remove_dead_blocks::RemoveDeadBlocks; pub struct SimplifyCfg; @@ -21,26 +22,7 @@ impl SimplifyCfg { SimplifyCfg } - fn remove_dead_blocks(&self, mir: &mut Mir) { - let mut seen = BitVector::new(mir.basic_blocks.len()); - // These blocks are always required. - seen.insert(START_BLOCK.index()); - seen.insert(END_BLOCK.index()); - - let mut worklist = Vec::with_capacity(4); - worklist.push(START_BLOCK); - while let Some(bb) = worklist.pop() { - for succ in mir.basic_block_data(bb).terminator().successors().iter() { - if seen.insert(succ.index()) { - worklist.push(*succ); - } - } - } - retain_basic_blocks(mir, &seen); - } - fn remove_goto_chains(&self, mir: &mut Mir) -> bool { - // Find the target at the end of the jump chain, return None if there is a loop fn final_target(mir: &Mir, mut target: BasicBlock) -> Option { // Keep track of already seen blocks to detect loops @@ -118,39 +100,17 @@ impl SimplifyCfg { } } -impl MirPass for SimplifyCfg { - fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &infer::InferCtxt<'a, 'tcx>) { +impl<'tcx> MirPass<'tcx> for SimplifyCfg { + fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, mir: &mut Mir<'tcx>) { let mut changed = true; while changed { changed = self.simplify_branches(mir); changed |= self.remove_goto_chains(mir); - self.remove_dead_blocks(mir); + RemoveDeadBlocks.run_pass(tcx, mir); } // FIXME: Should probably be moved into some kind of pass manager mir.basic_blocks.shrink_to_fit(); } } -/// Mass removal of basic blocks to keep the ID-remapping cheap. -fn retain_basic_blocks(mir: &mut Mir, keep: &BitVector) { - let num_blocks = mir.basic_blocks.len(); - - let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); - let mut used_blocks = 0; - for alive_index in keep.iter() { - replacements[alive_index] = BasicBlock::new(used_blocks); - if alive_index != used_blocks { - // Swap the next alive block data with the current available slot. Since alive_index is - // non-decreasing this is a valid operation. - mir.basic_blocks.swap(alive_index, used_blocks); - } - used_blocks += 1; - } - mir.basic_blocks.truncate(used_blocks); - - for bb in mir.all_basic_blocks() { - for target in mir.basic_block_data_mut(bb).terminator_mut().successors_mut() { - *target = replacements[target.index()]; - } - } -} +impl Pass for SimplifyCfg {} diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index bf22c7b0b8b34..21b3566418cb2 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -16,8 +16,9 @@ use rustc::middle::traits; use rustc::middle::ty::{self, Ty, TyCtxt}; use rustc::middle::ty::fold::TypeFoldable; use rustc::mir::repr::*; +use rustc::mir::mir_map::MirMap; use rustc::mir::tcx::LvalueTy; -use rustc::mir::transform::MirPass; +use rustc::mir::transform::{MirMapPass, Pass}; use rustc::mir::visit::{self, Visitor}; use syntax::codemap::{Span, DUMMY_SP}; @@ -572,27 +573,29 @@ impl TypeckMir { } } -impl MirPass for TypeckMir { - fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, infcx: &InferCtxt<'a, 'tcx>) - { - if infcx.tcx.sess.err_count() > 0 { +impl<'tcx> MirMapPass<'tcx> for TypeckMir { + fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>) { + if tcx.sess.err_count() > 0 { // compiling a broken program can obviously result in a // broken MIR, so try not to report duplicate errors. return; } - - let mut checker = TypeChecker::new(infcx); - - { - let mut verifier = TypeVerifier::new(&mut checker, mir); - verifier.visit_mir(mir); - if verifier.errors_reported { - // don't do further checks to avoid ICEs - return; + for (&id, mir) in &mut map.map { + let param_env = ty::ParameterEnvironment::for_item(tcx, id); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env)); + let mut checker = TypeChecker::new(&infcx); + { + let mut verifier = TypeVerifier::new(&mut checker, mir); + verifier.visit_mir(mir); + if verifier.errors_reported { + // don't do further checks to avoid ICEs + continue; + } } + checker.typeck_mir(mir); + checker.verify_obligations(mir); } - - checker.typeck_mir(mir); - checker.verify_obligations(mir); } } + +impl Pass for TypeckMir {} diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index a51fd58db88dd..3cfd6a76dda63 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -13,7 +13,7 @@ use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint}; use rustc::session::Session; -use rustc::mir::transform::MirPass; +use rustc::mir::transform::MirMapPass; use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT}; use syntax::ext::base::{IdentTT, MultiModifier, MultiDecorator}; @@ -56,7 +56,7 @@ pub struct Registry<'a> { pub late_lint_passes: Vec, #[doc(hidden)] - pub mir_passes: Vec>, + pub mir_passes: Vec MirMapPass<'pcx>>>, #[doc(hidden)] pub lint_groups: HashMap<&'static str, Vec>, @@ -141,7 +141,7 @@ impl<'a> Registry<'a> { } /// Register a MIR pass - pub fn register_mir_pass(&mut self, pass: Box) { + pub fn register_mir_pass(&mut self, pass: Box MirMapPass<'pcx>>) { self.mir_passes.push(pass); } diff --git a/src/test/auxiliary/dummy_mir_pass.rs b/src/test/auxiliary/dummy_mir_pass.rs index 16ef965e0dbd5..aec5165f6cfdd 100644 --- a/src/test/auxiliary/dummy_mir_pass.rs +++ b/src/test/auxiliary/dummy_mir_pass.rs @@ -18,17 +18,18 @@ extern crate rustc_front; extern crate rustc_plugin; extern crate syntax; -use rustc::mir::transform::MirPass; +use rustc::mir::transform::{self, MirPass}; use rustc::mir::repr::{Mir, Literal}; use rustc::mir::visit::MutVisitor; -use rustc::middle::infer::InferCtxt; +use rustc::middle::ty; use rustc::middle::const_eval::ConstVal; use rustc_plugin::Registry; struct Pass; -impl MirPass for Pass { - fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &InferCtxt<'a, 'tcx>) { +impl transform::Pass for Pass {} +impl<'tcx> MirPass<'tcx> for Pass { + fn run_pass(&mut self, _: &ty::ctxt<'tcx>, mir: &mut Mir<'tcx>) { Visitor.visit_mir(mir) } }