Skip to content

Commit 0414594

Browse files
committed
Auto merge of #39409 - pnkfelix:mir-borrowck2, r=nikomatsakis
MIR EndRegion Statements (was MIR dataflow for Borrows) This PR adds an `EndRegion` statement to MIR (where the `EndRegion` statement is what terminates a borrow). An earlier version of the PR implemented a dataflow analysis on borrow expressions, but I am now factoring that into a follow-up PR so that reviewing this one is easier. (And also because there are some revisions I want to make to that dataflow code, but I want this PR to get out of WIP status...) This is a baby step towards MIR borrowck. I just want to get the review process going while I independently work on the remaining steps.
2 parents 5ce5126 + 11f4968 commit 0414594

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1047
-73
lines changed

src/librustc/ich/impls_mir.rs

+3
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ for mir::StatementKind<'tcx> {
226226
mir::StatementKind::StorageDead(ref lvalue) => {
227227
lvalue.hash_stable(hcx, hasher);
228228
}
229+
mir::StatementKind::EndRegion(ref extents) => {
230+
extents.hash_stable(hcx, hasher);
231+
}
229232
mir::StatementKind::Nop => {}
230233
mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
231234
asm.hash_stable(hcx, hasher);

src/librustc/mir/mod.rs

+38-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
1313
use graphviz::IntoCow;
1414
use middle::const_val::ConstVal;
15+
use middle::region::CodeExtent;
1516
use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr};
1617
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
1718
use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators};
@@ -804,6 +805,10 @@ pub enum StatementKind<'tcx> {
804805
inputs: Vec<Operand<'tcx>>
805806
},
806807

808+
/// Mark one terminating point of an extent (i.e. static region).
809+
/// (The starting point(s) arise implicitly from borrows.)
810+
EndRegion(CodeExtent),
811+
807812
/// No-op. Useful for deleting instructions without affecting statement indices.
808813
Nop,
809814
}
@@ -813,6 +818,8 @@ impl<'tcx> Debug for Statement<'tcx> {
813818
use self::StatementKind::*;
814819
match self.kind {
815820
Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv),
821+
// (reuse lifetime rendering policy from ppaux.)
822+
EndRegion(ref ce) => write!(fmt, "EndRegion({})", ty::ReScope(*ce)),
816823
StorageLive(ref lv) => write!(fmt, "StorageLive({:?})", lv),
817824
StorageDead(ref lv) => write!(fmt, "StorageDead({:?})", lv),
818825
SetDiscriminant{lvalue: ref lv, variant_index: index} => {
@@ -1176,12 +1183,22 @@ impl<'tcx> Debug for Rvalue<'tcx> {
11761183
UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a),
11771184
Discriminant(ref lval) => write!(fmt, "discriminant({:?})", lval),
11781185
NullaryOp(ref op, ref t) => write!(fmt, "{:?}({:?})", op, t),
1179-
Ref(_, borrow_kind, ref lv) => {
1186+
Ref(region, borrow_kind, ref lv) => {
11801187
let kind_str = match borrow_kind {
11811188
BorrowKind::Shared => "",
11821189
BorrowKind::Mut | BorrowKind::Unique => "mut ",
11831190
};
1184-
write!(fmt, "&{}{:?}", kind_str, lv)
1191+
1192+
// When identifying regions, add trailing space if
1193+
// necessary.
1194+
let region = if ppaux::identify_regions() {
1195+
let mut region = format!("{}", region);
1196+
if region.len() > 0 { region.push(' '); }
1197+
region
1198+
} else {
1199+
"".to_owned()
1200+
};
1201+
write!(fmt, "&{}{}{:?}", region, kind_str, lv)
11851202
}
11861203

11871204
Aggregate(ref kind, ref lvs) => {
@@ -1224,7 +1241,11 @@ impl<'tcx> Debug for Rvalue<'tcx> {
12241241

12251242
AggregateKind::Closure(def_id, _) => ty::tls::with(|tcx| {
12261243
if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
1227-
let name = format!("[closure@{:?}]", tcx.hir.span(node_id));
1244+
let name = if tcx.sess.opts.debugging_opts.span_free_formats {
1245+
format!("[closure@{:?}]", node_id)
1246+
} else {
1247+
format!("[closure@{:?}]", tcx.hir.span(node_id))
1248+
};
12281249
let mut struct_fmt = fmt.debug_struct(&name);
12291250

12301251
tcx.with_freevars(node_id, |freevars| {
@@ -1458,6 +1479,13 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
14581479
outputs: outputs.fold_with(folder),
14591480
inputs: inputs.fold_with(folder)
14601481
},
1482+
1483+
// Note for future: If we want to expose the extents
1484+
// during the fold, we need to either generalize EndRegion
1485+
// to carry `[ty::Region]`, or extend the `TypeFolder`
1486+
// trait with a `fn fold_extent`.
1487+
EndRegion(ref extent) => EndRegion(extent.clone()),
1488+
14611489
Nop => Nop,
14621490
};
14631491
Statement {
@@ -1476,6 +1504,13 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
14761504
StorageDead(ref lvalue) => lvalue.visit_with(visitor),
14771505
InlineAsm { ref outputs, ref inputs, .. } =>
14781506
outputs.visit_with(visitor) || inputs.visit_with(visitor),
1507+
1508+
// Note for future: If we want to expose the extents
1509+
// during the visit, we need to either generalize EndRegion
1510+
// to carry `[ty::Region]`, or extend the `TypeVisitor`
1511+
// trait with a `fn visit_extent`.
1512+
EndRegion(ref _extent) => false,
1513+
14791514
Nop => false,
14801515
}
14811516
}

src/librustc/mir/visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ macro_rules! make_mir_visitor {
325325
ref $($mutability)* rvalue) => {
326326
self.visit_assign(block, lvalue, rvalue, location);
327327
}
328+
StatementKind::EndRegion(_) => {}
328329
StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
329330
self.visit_lvalue(lvalue, LvalueContext::Store, location);
330331
}

src/librustc/session/config.rs

+4
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
893893
DB_OPTIONS, db_type_desc, dbsetters,
894894
verbose: bool = (false, parse_bool, [UNTRACKED],
895895
"in general, enable more debug printouts"),
896+
span_free_formats: bool = (false, parse_bool, [UNTRACKED],
897+
"when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
898+
identify_regions: bool = (false, parse_bool, [UNTRACKED],
899+
"make unnamed regions display as '# (where # is some non-ident unique id)"),
896900
time_passes: bool = (false, parse_bool, [UNTRACKED],
897901
"measure time of each rustc pass"),
898902
count_llvm_insns: bool = (false, parse_bool,

src/librustc/util/ppaux.rs

+28-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use hir::BodyId;
1112
use hir::def_id::DefId;
1213
use hir::map::definitions::DefPathData;
14+
use middle::region::{CodeExtent, BlockRemainder};
1315
use ty::subst::{self, Subst};
1416
use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
1517
use ty::{TyBool, TyChar, TyAdt};
@@ -32,6 +34,10 @@ pub fn verbose() -> bool {
3234
ty::tls::with(|tcx| tcx.sess.verbose())
3335
}
3436

37+
pub fn identify_regions() -> bool {
38+
ty::tls::with(|tcx| tcx.sess.opts.debugging_opts.identify_regions)
39+
}
40+
3541
fn fn_sig(f: &mut fmt::Formatter,
3642
inputs: &[Ty],
3743
variadic: bool,
@@ -519,6 +525,23 @@ impl fmt::Display for ty::RegionKind {
519525
ty::ReSkolemized(_, br) => {
520526
write!(f, "{}", br)
521527
}
528+
ty::ReScope(code_extent) if identify_regions() => {
529+
match code_extent {
530+
CodeExtent::Misc(node_id) =>
531+
write!(f, "'{}mce", node_id.as_u32()),
532+
CodeExtent::CallSiteScope(BodyId { node_id }) =>
533+
write!(f, "'{}cce", node_id.as_u32()),
534+
CodeExtent::ParameterScope(BodyId { node_id }) =>
535+
write!(f, "'{}pce", node_id.as_u32()),
536+
CodeExtent::DestructionScope(node_id) =>
537+
write!(f, "'{}dce", node_id.as_u32()),
538+
CodeExtent::Remainder(BlockRemainder { block, first_statement_index }) =>
539+
write!(f, "'{}_{}rce", block, first_statement_index),
540+
}
541+
}
542+
ty::ReVar(region_vid) if identify_regions() => {
543+
write!(f, "'{}rv", region_vid.index)
544+
}
522545
ty::ReScope(_) |
523546
ty::ReVar(_) |
524547
ty::ReErased => Ok(()),
@@ -789,7 +812,11 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
789812
write!(f, "[closure")?;
790813

791814
if let Some(node_id) = tcx.hir.as_local_node_id(did) {
792-
write!(f, "@{:?}", tcx.hir.span(node_id))?;
815+
if tcx.sess.opts.debugging_opts.span_free_formats {
816+
write!(f, "@{:?}", node_id)?;
817+
} else {
818+
write!(f, "@{:?}", tcx.hir.span(node_id))?;
819+
}
793820
let mut sep = " ";
794821
tcx.with_freevars(node_id, |freevars| {
795822
for (freevar, upvar_ty) in freevars.iter().zip(upvar_tys) {

src/librustc_borrowck/borrowck/mir/dataflow/impls.rs

+1
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> {
474474
mir::StatementKind::StorageLive(_) |
475475
mir::StatementKind::StorageDead(_) |
476476
mir::StatementKind::InlineAsm { .. } |
477+
mir::StatementKind::EndRegion(_) |
477478
mir::StatementKind::Nop => {}
478479
}
479480
}

src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
105105
mir::StatementKind::StorageLive(_) |
106106
mir::StatementKind::StorageDead(_) |
107107
mir::StatementKind::InlineAsm { .. } |
108+
mir::StatementKind::EndRegion(_) |
108109
mir::StatementKind::Nop => continue,
109110
mir::StatementKind::SetDiscriminant{ .. } =>
110111
span_bug!(stmt.source_info.span,

src/librustc_borrowck/borrowck/mir/elaborate_drops.rs

+5
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
594594
assert!(self.patch.is_patched(bb));
595595
allow_initializations = false;
596596
}
597+
TerminatorKind::Resume => {
598+
// It is possible for `Resume` to be patched
599+
// (in particular it can be patched to be replaced with
600+
// a Goto; see `MirPatch::new`).
601+
}
597602
_ => {
598603
assert!(!self.patch.is_patched(bb));
599604
}

src/librustc_borrowck/borrowck/mir/gather_moves.rs

+1
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
413413
"SetDiscriminant should not exist during borrowck");
414414
}
415415
StatementKind::InlineAsm { .. } |
416+
StatementKind::EndRegion(_) |
416417
StatementKind::Nop => {}
417418
}
418419
}

src/librustc_borrowck/borrowck/mir/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>(
394394
mir::StatementKind::StorageLive(_) |
395395
mir::StatementKind::StorageDead(_) |
396396
mir::StatementKind::InlineAsm { .. } |
397+
mir::StatementKind::EndRegion(_) |
397398
mir::StatementKind::Nop => {}
398399
},
399400
None => {

src/librustc_driver/driver.rs

+3
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,9 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
914914
let mut passes = Passes::new();
915915
passes.push_hook(mir::transform::dump_mir::DumpMir);
916916

917+
// Remove all `EndRegion` statements that are not involved in borrows.
918+
passes.push_pass(MIR_CONST, mir::transform::clean_end_regions::CleanEndRegions);
919+
917920
// What we need to do constant evaluation.
918921
passes.push_pass(MIR_CONST, mir::transform::simplify::SimplifyCfg::new("initial"));
919922
passes.push_pass(MIR_CONST, mir::transform::type_check::TypeckMir);

src/librustc_mir/build/block.rs

+34-25
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
2121
ast_block: &'tcx hir::Block,
2222
source_info: SourceInfo)
2323
-> BlockAnd<()> {
24-
let Block { extent, span, stmts, expr, targeted_by_break } = self.hir.mirror(ast_block);
25-
self.in_scope(extent, block, move |this| {
26-
if targeted_by_break {
27-
// This is a `break`-able block (currently only `catch { ... }`)
28-
let exit_block = this.cfg.start_new_block();
29-
let block_exit = this.in_breakable_scope(None, exit_block,
30-
destination.clone(), |this| {
24+
let Block { extent, opt_destruction_extent, span, stmts, expr, targeted_by_break } =
25+
self.hir.mirror(ast_block);
26+
self.in_opt_scope(opt_destruction_extent.map(|de|(de, source_info)), block, move |this| {
27+
this.in_scope((extent, source_info), block, move |this| {
28+
if targeted_by_break {
29+
// This is a `break`-able block (currently only `catch { ... }`)
30+
let exit_block = this.cfg.start_new_block();
31+
let block_exit = this.in_breakable_scope(
32+
None, exit_block, destination.clone(), |this| {
33+
this.ast_block_stmts(destination, block, span, stmts, expr)
34+
});
35+
this.cfg.terminate(unpack!(block_exit), source_info,
36+
TerminatorKind::Goto { target: exit_block });
37+
exit_block.unit()
38+
} else {
3139
this.ast_block_stmts(destination, block, span, stmts, expr)
32-
});
33-
this.cfg.terminate(unpack!(block_exit), source_info,
34-
TerminatorKind::Goto { target: exit_block });
35-
exit_block.unit()
36-
} else {
37-
this.ast_block_stmts(destination, block, span, stmts, expr)
38-
}
40+
}
41+
})
3942
})
4043
}
4144

@@ -66,14 +69,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
6669
// First we build all the statements in the block.
6770
let mut let_extent_stack = Vec::with_capacity(8);
6871
let outer_visibility_scope = this.visibility_scope;
72+
let source_info = this.source_info(span);
6973
for stmt in stmts {
70-
let Stmt { span: _, kind } = this.hir.mirror(stmt);
74+
let Stmt { span, kind, opt_destruction_extent } = this.hir.mirror(stmt);
7175
match kind {
7276
StmtKind::Expr { scope, expr } => {
73-
unpack!(block = this.in_scope(scope, block, |this| {
74-
let expr = this.hir.mirror(expr);
75-
this.stmt_expr(block, expr)
76-
}));
77+
unpack!(block = this.in_opt_scope(
78+
opt_destruction_extent.map(|de|(de, source_info)), block, |this| {
79+
this.in_scope((scope, source_info), block, |this| {
80+
let expr = this.hir.mirror(expr);
81+
this.stmt_expr(block, expr)
82+
})
83+
}));
7784
}
7885
StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => {
7986
let tcx = this.hir.tcx();
@@ -89,10 +96,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
8996

9097
// Evaluate the initializer, if present.
9198
if let Some(init) = initializer {
92-
unpack!(block = this.in_scope(init_scope, block, move |this| {
93-
// FIXME #30046 ^~~~
94-
this.expr_into_pattern(block, pattern, init)
95-
}));
99+
unpack!(block = this.in_opt_scope(
100+
opt_destruction_extent.map(|de|(de, source_info)), block, move |this| {
101+
this.in_scope((init_scope, source_info), block, move |this| {
102+
// FIXME #30046 ^~~~
103+
this.expr_into_pattern(block, pattern, init)
104+
})
105+
}));
96106
} else {
97107
this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| {
98108
this.storage_live_binding(block, node, span);
@@ -112,13 +122,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
112122
if let Some(expr) = expr {
113123
unpack!(block = this.into(destination, block, expr));
114124
} else {
115-
let source_info = this.source_info(span);
116125
this.cfg.push_assign_unit(block, source_info, destination);
117126
}
118127
// Finally, we pop all the let scopes before exiting out from the scope of block
119128
// itself.
120129
for extent in let_extent_stack.into_iter().rev() {
121-
unpack!(block = this.pop_scope(extent, block));
130+
unpack!(block = this.pop_scope((extent, source_info), block));
122131
}
123132
// Restore the original visibility scope.
124133
this.visibility_scope = outer_visibility_scope;

src/librustc_mir/build/cfg.rs

+11
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//! Routines for manipulating the control-flow graph.
1515
1616
use build::CFG;
17+
use rustc::middle::region::CodeExtent;
1718
use rustc::mir::*;
1819

1920
impl<'tcx> CFG<'tcx> {
@@ -43,6 +44,16 @@ impl<'tcx> CFG<'tcx> {
4344
self.block_data_mut(block).statements.push(statement);
4445
}
4546

47+
pub fn push_end_region(&mut self,
48+
block: BasicBlock,
49+
source_info: SourceInfo,
50+
extent: CodeExtent) {
51+
self.push(block, Statement {
52+
source_info: source_info,
53+
kind: StatementKind::EndRegion(extent),
54+
});
55+
}
56+
4657
pub fn push_assign(&mut self,
4758
block: BasicBlock,
4859
source_info: SourceInfo,

src/librustc_mir/build/expr/as_lvalue.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
4040
let source_info = this.source_info(expr_span);
4141
match expr.kind {
4242
ExprKind::Scope { extent, value } => {
43-
this.in_scope(extent, block, |this| this.as_lvalue(block, value))
43+
this.in_scope((extent, source_info), block, |this| this.as_lvalue(block, value))
4444
}
4545
ExprKind::Field { lhs, name } => {
4646
let lvalue = unpack!(block = this.as_lvalue(block, lhs));

src/librustc_mir/build/expr/as_operand.rs

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
5656
let this = self;
5757

5858
if let ExprKind::Scope { extent, value } = expr.kind {
59+
let source_info = this.source_info(expr.span);
60+
let extent = (extent, source_info);
5961
return this.in_scope(extent, block, |this| {
6062
this.as_operand(block, scope, value)
6163
});

src/librustc_mir/build/expr/as_rvalue.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
5959

6060
match expr.kind {
6161
ExprKind::Scope { extent, value } => {
62+
let extent = (extent, source_info);
6263
this.in_scope(extent, block, |this| this.as_rvalue(block, scope, value))
6364
}
6465
ExprKind::Repeat { value, count } => {
@@ -99,7 +100,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
99100
// to start, malloc some memory of suitable type (thus far, uninitialized):
100101
let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
101102
this.cfg.push_assign(block, source_info, &result, box_);
102-
this.in_scope(value_extents, block, |this| {
103+
this.in_scope((value_extents, source_info), block, |this| {
103104
// schedule a shallow free of that memory, lest we unwind:
104105
this.schedule_box_free(expr_span, value_extents, &result, value.ty);
105106
// initialize the box contents:

0 commit comments

Comments
 (0)