diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 318ae704089..e44e3936885 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -26,13 +26,6 @@ impl<'tcx> CFG<'tcx> { &mut self.basic_blocks[blk.index()] } - pub fn end_point(&self, block: BasicBlock) -> ExecutionPoint { - ExecutionPoint { - block: block, - statement: self.block_data(block).statements.len() as u32, - } - } - pub fn start_new_block(&mut self) -> BasicBlock { let node_index = self.basic_blocks.len(); self.basic_blocks.push(BasicBlockData::new(Terminator::Diverge)); diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index e351215276a..3f3bceef1eb 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -70,7 +70,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { this.cfg.push_assign(block, expr_span, &result, rvalue); // schedule a shallow free of that memory, lest we unwind: - let extent = this.extent_of_innermost_scope().unwrap(); + let extent = this.extent_of_innermost_scope(); this.schedule_drop(expr_span, extent, DropKind::Free, &result, value_ty); // initialize the box contents: diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 57c6db79c52..7d79e90b3f1 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -206,7 +206,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { } ExprKind::Return { value } => { unpack!(block = this.into(&Lvalue::ReturnPointer, block, value)); - let extent = this.extent_of_outermost_scope().unwrap(); + let extent = this.extent_of_outermost_scope(); this.exit_scope(expr_span, extent, block, END_BLOCK); this.cfg.start_new_block().unit() } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index cc8549de26a..cc6155844bc 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -42,7 +42,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { // suitable extent for all of the bindings in this match. It's // easiest to do this up front because some of these arms may // be unreachable or reachable multiple times. - let var_extent = self.extent_of_innermost_scope().unwrap(); + let var_extent = self.extent_of_innermost_scope(); for arm in &arms { self.declare_bindings(var_extent, &arm.patterns[0]); } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index eb03727d9b2..f67c2920ba3 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -19,7 +19,6 @@ use syntax::codemap::Span; struct Builder<'a, 'tcx: 'a> { hir: Cx<'a, 'tcx>, - extents: FnvHashMap<CodeExtent, Vec<GraphExtent>>, cfg: CFG<'tcx>, scopes: Vec<scope::Scope<'tcx>>, loop_scopes: Vec<scope::LoopScope>, @@ -92,7 +91,6 @@ pub fn construct<'a,'tcx>(mut hir: Cx<'a,'tcx>, let mut builder = Builder { hir: hir, cfg: cfg, - extents: FnvHashMap(), scopes: vec![], loop_scopes: vec![], temp_decls: temp_decls, @@ -117,7 +115,6 @@ pub fn construct<'a,'tcx>(mut hir: Cx<'a,'tcx>, Mir { basic_blocks: builder.cfg.basic_blocks, - extents: builder.extents, var_decls: builder.var_decls, arg_decls: arg_decls, temp_decls: builder.temp_decls, diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index cecd610ff72..987424f4ac7 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -94,7 +94,6 @@ use syntax::codemap::Span; pub struct Scope<'tcx> { extent: CodeExtent, - exits: Vec<ExecutionPoint>, drops: Vec<(DropKind, Span, Lvalue<'tcx>)>, cached_block: Option<BasicBlock>, } @@ -116,7 +115,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { -> BlockAnd<R> where F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R> { - let extent = self.extent_of_innermost_scope().unwrap(); + let extent = self.extent_of_innermost_scope(); let loop_scope = LoopScope { extent: extent.clone(), continue_block: loop_block, @@ -128,61 +127,51 @@ impl<'a,'tcx> Builder<'a,'tcx> { r } - /// Start a scope. The closure `f` should translate the contents - /// of the scope. See module comment for more details. - pub fn in_scope<F, R>(&mut self, extent: CodeExtent, block: BasicBlock, f: F) -> BlockAnd<R> + /// Convenience wrapper that pushes a scope and then executes `f` + /// to build its contents, popping the scope afterwards. + pub fn in_scope<F, R>(&mut self, extent: CodeExtent, mut block: BasicBlock, f: F) -> BlockAnd<R> where F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R> { debug!("in_scope(extent={:?}, block={:?})", extent, block); + self.push_scope(extent, block); + let rv = unpack!(block = f(self)); + assert_eq!(self.extent_of_innermost_scope(), extent); + self.pop_scope(block); + debug!("in_scope: exiting extent={:?} block={:?}", extent, block); + block.and(rv) + } - let start_point = self.cfg.end_point(block); + /// Push a scope onto the stack. You can then build code in this + /// scope and call `pop_scope` afterwards. Note that these two + /// calls must be paired; using `in_scope` as a convenience + /// wrapper maybe preferable. + pub fn push_scope(&mut self, extent: CodeExtent, block: BasicBlock) { + debug!("push_scope({:?}, {:?})", extent, block); // push scope, execute `f`, then pop scope again self.scopes.push(Scope { extent: extent.clone(), drops: vec![], - exits: vec![], cached_block: None, }); - let BlockAnd(fallthrough_block, rv) = f(self); - let mut scope = self.scopes.pop().unwrap(); + } + + /// Pops the innermost scope, adding any drops onto the end of + /// `block` that are needed. This must match 1-to-1 with + /// `push_scope`. + pub fn pop_scope(&mut self, block: BasicBlock) { + debug!("pop_scope({:?})", block); + let scope = self.scopes.pop().unwrap(); // add in any drops needed on the fallthrough path (any other // exiting paths, such as those that arise from `break`, will // have drops already) for (kind, span, lvalue) in scope.drops { - self.cfg.push_drop(fallthrough_block, span, kind, &lvalue); - } - - // add the implicit fallthrough edge - scope.exits.push(self.cfg.end_point(fallthrough_block)); - - // compute the extent from start to finish and store it in the graph - let graph_extent = self.graph_extent(start_point, scope.exits); - self.extents.entry(extent) - .or_insert(vec![]) - .push(graph_extent); - - debug!("in_scope: exiting extent={:?} fallthrough_block={:?}", extent, fallthrough_block); - fallthrough_block.and(rv) - } - - /// Creates a graph extent (SEME region) from an entry point and - /// exit points. - fn graph_extent(&self, entry: ExecutionPoint, exits: Vec<ExecutionPoint>) -> GraphExtent { - if exits.len() == 1 && entry.block == exits[0].block { - GraphExtent { - entry: entry, - exit: GraphExtentExit::Statement(exits[0].statement), - } - } else { - GraphExtent { - entry: entry, - exit: GraphExtentExit::Points(exits), - } + self.cfg.push_drop(block, span, kind, &lvalue); } } + /// Finds the loop scope for a given label. This is used for /// resolving `break` and `continue`. pub fn find_loop_scope(&mut self, @@ -232,8 +221,6 @@ impl<'a,'tcx> Builder<'a,'tcx> { for &(kind, drop_span, ref lvalue) in &scope.drops { self.cfg.push_drop(block, drop_span, kind, lvalue); } - - scope.exits.push(self.cfg.end_point(block)); } self.cfg.terminate(block, Terminator::Goto { target: target }); @@ -272,12 +259,12 @@ impl<'a,'tcx> Builder<'a,'tcx> { } } - pub fn extent_of_innermost_scope(&self) -> Option<CodeExtent> { - self.scopes.last().map(|scope| scope.extent) + pub fn extent_of_innermost_scope(&self) -> CodeExtent { + self.scopes.last().map(|scope| scope.extent).unwrap() } - pub fn extent_of_outermost_scope(&self) -> Option<CodeExtent> { - self.scopes.first().map(|scope| scope.extent) + pub fn extent_of_outermost_scope(&self) -> CodeExtent { + self.scopes.first().map(|scope| scope.extent).unwrap() } } diff --git a/src/librustc_mir/repr.rs b/src/librustc_mir/repr.rs index 19b9e87701c..dad8961a788 100644 --- a/src/librustc_mir/repr.rs +++ b/src/librustc_mir/repr.rs @@ -10,11 +10,9 @@ use rustc::middle::const_eval::ConstVal; use rustc::middle::def_id::DefId; -use rustc::middle::region::CodeExtent; use rustc::middle::subst::Substs; use rustc::middle::ty::{AdtDef, ClosureSubsts, FnOutput, Region, Ty}; use rustc_back::slice; -use rustc_data_structures::fnv::FnvHashMap; use rustc_front::hir::InlineAsm; use syntax::ast::Name; use syntax::codemap::Span; @@ -156,48 +154,6 @@ pub struct ArgDecl<'tcx> { pub ty: Ty<'tcx>, } -/////////////////////////////////////////////////////////////////////////// -// Graph extents - -/// A moment in the flow of execution. It corresponds to a point in -/// between two statements: -/// -/// BB[block]: -/// <--- if statement == 0 -/// STMT[0] -/// <--- if statement == 1 -/// STMT[1] -/// ... -/// <--- if statement == n-1 -/// STMT[n-1] -/// <--- if statement == n -/// -/// where the block has `n` statements. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct ExecutionPoint { - pub block: BasicBlock, - pub statement: u32, -} - -/// A single-entry-multiple-exit region in the graph. We build one of -/// these for every node-id during MIR construction. By construction -/// we are assured that the entry dominates all points within, and -/// that, for every interior point X, it is postdominated by some exit. -pub struct GraphExtent { - pub entry: ExecutionPoint, - pub exit: GraphExtentExit, -} - -pub enum GraphExtentExit { - /// `Statement(X)`: a very common special case covering a span - /// that is local to a single block. It starts at the entry point - /// and extends until the start of statement `X` (non-inclusive). - Statement(u32), - - /// The more general case where the exits are a set of points. - Points(Vec<ExecutionPoint>), -} - /////////////////////////////////////////////////////////////////////////// // BasicBlock