pub struct Scope<'tcx> {
extent: CodeExtent,
- exits: Vec<ExecutionPoint>,
drops: Vec<(DropKind, Span, Lvalue<'tcx>)>,
cached_block: Option<BasicBlock>,
}
-> 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,
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);
+ self.cfg.push_drop(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),
- }
- }
- }
/// Finds the loop scope for a given label. This is used for
/// resolving `break` and `continue`.
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 });
}
}
- 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()
}
}
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;
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