Add EndRegion statement kind to MIR.

* Emit `EndRegion` for every code-extent for which we observe a
   borrow. To do this, we needed to thread source info back through
   to `fn in_scope`, which makes this commit a bit more painful than
   one might have expected.

 * There is `end_region` emission in `Builder::pop_scope` and in
   `Builder::exit_scope`; the first handles falling out of a scope
   normally, the second handles e.g. `break`.

 * Remove `EndRegion` statements during the erase_regions mir
   transformation.

 * Preallocate the terminator block, and throw an `Unreachable` marker
   on it from the outset. Then overwrite that Terminator as necessary
   on demand.

 * Instead of marking the scope as needs_cleanup after seeing a
   borrow, just treat every scope in the chain as being part of the
   diverge_block (after any *one* of them has separately signalled
   that it needs cleanup, e.g. due to having a destructor to run).

 * Allow for resume terminators to be patched when looking up drop flags.

   (In particular, `MirPatch::new` has an explicit code path,
   presumably previously unreachable, that patches up such resume
   terminators.)

 * Make `Scope` implement `Debug` trait.

 * Expanded a stray comment: we do not emit StorageDead on diverging
   paths, but that end behavior might not be desirable.
This commit is contained in:
Felix S. Klock II 2017-02-17 13:38:42 +01:00
parent 7c0c4cde80
commit 1d315cf7da
19 changed files with 94 additions and 10 deletions

View file

@ -226,6 +226,9 @@ for mir::StatementKind<'tcx> {
mir::StatementKind::StorageDead(ref lvalue) => {
lvalue.hash_stable(hcx, hasher);
}
mir::StatementKind::EndRegion(ref extents) => {
extents.hash_stable(hcx, hasher);
}
mir::StatementKind::Nop => {}
mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
asm.hash_stable(hcx, hasher);

View file

@ -12,6 +12,7 @@
use graphviz::IntoCow;
use middle::const_val::ConstVal;
use middle::region::CodeExtent;
use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators};
@ -804,6 +805,10 @@ pub enum StatementKind<'tcx> {
inputs: Vec<Operand<'tcx>>
},
/// Mark one terminating point of an extent (i.e. static region).
/// (The starting point(s) arise implicitly from borrows.)
EndRegion(CodeExtent),
/// No-op. Useful for deleting instructions without affecting statement indices.
Nop,
}
@ -813,6 +818,8 @@ impl<'tcx> Debug for Statement<'tcx> {
use self::StatementKind::*;
match self.kind {
Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv),
// (reuse lifetime rendering policy from ppaux.)
EndRegion(ref ce) => write!(fmt, "EndRegion({})", ty::ReScope(*ce)),
StorageLive(ref lv) => write!(fmt, "StorageLive({:?})", lv),
StorageDead(ref lv) => write!(fmt, "StorageDead({:?})", lv),
SetDiscriminant{lvalue: ref lv, variant_index: index} => {
@ -1472,6 +1479,13 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
outputs: outputs.fold_with(folder),
inputs: inputs.fold_with(folder)
},
// Note for future: If we want to expose the extents
// during the fold, we need to either generalize EndRegion
// to carry `[ty::Region]`, or extend the `TypeFolder`
// trait with a `fn fold_extent`.
EndRegion(ref extent) => EndRegion(extent.clone()),
Nop => Nop,
};
Statement {
@ -1490,6 +1504,13 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
StorageDead(ref lvalue) => lvalue.visit_with(visitor),
InlineAsm { ref outputs, ref inputs, .. } =>
outputs.visit_with(visitor) || inputs.visit_with(visitor),
// Note for future: If we want to expose the extents
// during the visit, we need to either generalize EndRegion
// to carry `[ty::Region]`, or extend the `TypeVisitor`
// trait with a `fn visit_extent`.
EndRegion(ref _extent) => false,
Nop => false,
}
}

View file

@ -325,6 +325,7 @@ macro_rules! make_mir_visitor {
ref $($mutability)* rvalue) => {
self.visit_assign(block, lvalue, rvalue, location);
}
StatementKind::EndRegion(_) => {}
StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
self.visit_lvalue(lvalue, LvalueContext::Store, location);
}