Skip to content

Commit d59af53

Browse files
committed
Initial attempt at refining liveness with "maybe initialized" analysis
1 parent 2ffd2e0 commit d59af53

File tree

7 files changed

+97
-83
lines changed

7 files changed

+97
-83
lines changed

src/librustc_mir/borrow_check.rs renamed to src/librustc_mir/borrow_check/mod.rs

Lines changed: 61 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Lvalue, Local}
1818
use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue};
1919
use rustc::mir::{Statement, StatementKind, Terminator, TerminatorKind};
2020
use rustc::mir::transform::MirSource;
21-
use transform::nll;
2221

2322
use rustc_data_structures::indexed_set::{self, IdxSetBuf};
2423
use rustc_data_structures::indexed_vec::{Idx};
@@ -38,6 +37,7 @@ use util::borrowck_errors::{BorrowckErrors, Origin};
3837
use self::MutateMode::{JustWrite, WriteAndRead};
3938
use self::ConsumeKind::{Consume};
4039

40+
pub(crate) mod nll;
4141

4242
pub fn provide(providers: &mut Providers) {
4343
*providers = Providers {
@@ -77,7 +77,16 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
7777

7878
let id = src.item_id();
7979

80-
let move_data: MoveData<'tcx> = match MoveData::gather_moves(input_mir, tcx, param_env) {
80+
// Make our own copy of the MIR. This copy will be modified (in place) to
81+
// contain non-lexical lifetimes. It will have a lifetime tied
82+
// to the inference context.
83+
let mut mir: Mir<'tcx> = input_mir.clone();
84+
let mir = &mut mir;
85+
86+
// Replace all regions with fresh inference variables.
87+
let num_region_variables = nll::renumber::renumber_mir(infcx, mir);
88+
89+
let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx, param_env) {
8190
Ok(move_data) => move_data,
8291
Err((move_data, move_errors)) => {
8392
for move_error in move_errors {
@@ -105,31 +114,22 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
105114
}
106115
};
107116

108-
// Make our own copy of the MIR. This copy will be modified (in place) to
109-
// contain non-lexical lifetimes. It will have a lifetime tied
110-
// to the inference context.
111-
let mut mir: Mir<'tcx> = input_mir.clone();
112-
let mir = &mut mir;
117+
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
118+
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
119+
let flow_inits = FlowInProgress::new(do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
120+
MaybeInitializedLvals::new(tcx, mir, &mdpe),
121+
|bd, i| &bd.move_data().move_paths[i]));
122+
let flow_uninits = FlowInProgress::new(do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
123+
MaybeUninitializedLvals::new(tcx, mir, &mdpe),
124+
|bd, i| &bd.move_data().move_paths[i]));
113125

114126
// If we are in non-lexical mode, compute the non-lexical lifetimes.
115127
let opt_regioncx = if !tcx.sess.opts.debugging_opts.nll {
116128
None
117129
} else {
118-
Some(nll::compute_regions(infcx, src, param_env, mir))
130+
Some(nll::compute_regions(infcx, src, param_env, mir, num_region_variables, &flow_inits, &mdpe.move_data))
119131
};
120132

121-
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
122-
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
123-
let flow_borrows = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
124-
Borrows::new(tcx, mir, opt_regioncx.as_ref()),
125-
|bd, i| bd.location(i));
126-
let flow_inits = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
127-
MaybeInitializedLvals::new(tcx, mir, &mdpe),
128-
|bd, i| &bd.move_data().move_paths[i]);
129-
let flow_uninits = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
130-
MaybeUninitializedLvals::new(tcx, mir, &mdpe),
131-
|bd, i| &bd.move_data().move_paths[i]);
132-
133133
let mut mbcx = MirBorrowckCtxt {
134134
tcx: tcx,
135135
mir: mir,
@@ -138,6 +138,10 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
138138
param_env: param_env,
139139
};
140140

141+
let flow_borrows = FlowInProgress::new(do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
142+
Borrows::new(tcx, mir, opt_regioncx.as_ref()),
143+
|bd, i| bd.location(i)));
144+
141145
let mut state = InProgress::new(flow_borrows,
142146
flow_inits,
143147
flow_uninits);
@@ -1401,14 +1405,14 @@ impl ContextKind {
14011405
}
14021406

14031407
impl<'b, 'gcx, 'tcx> InProgress<'b, 'gcx, 'tcx> {
1404-
pub(super) fn new(borrows: DataflowResults<Borrows<'b, 'gcx, 'tcx>>,
1405-
inits: DataflowResults<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
1406-
uninits: DataflowResults<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>)
1408+
fn new(borrows: FlowInProgress<Borrows<'b, 'gcx, 'tcx>>,
1409+
inits: FlowInProgress<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
1410+
uninits: FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>)
14071411
-> Self {
14081412
InProgress {
1409-
borrows: FlowInProgress::new(borrows),
1410-
inits: FlowInProgress::new(inits),
1411-
uninits: FlowInProgress::new(uninits),
1413+
borrows,
1414+
inits,
1415+
uninits,
14121416
}
14131417
}
14141418

@@ -1474,35 +1478,42 @@ impl<'b, 'gcx, 'tcx> InProgress<'b, 'gcx, 'tcx> {
14741478
}
14751479
}
14761480

1477-
impl<'b, 'gcx, 'tcx> FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>> {
1478-
fn has_any_child_of(&self, mpi: MovePathIndex) -> Option<MovePathIndex> {
1479-
let move_data = self.base_results.operator().move_data();
1480-
1481-
let mut todo = vec![mpi];
1482-
let mut push_siblings = false; // don't look at siblings of original `mpi`.
1483-
while let Some(mpi) = todo.pop() {
1484-
if self.curr_state.contains(&mpi) {
1485-
return Some(mpi);
1486-
}
1487-
let move_path = &move_data.move_paths[mpi];
1488-
if let Some(child) = move_path.first_child {
1489-
todo.push(child);
1490-
}
1491-
if push_siblings {
1492-
if let Some(sibling) = move_path.next_sibling {
1493-
todo.push(sibling);
1481+
macro_rules! has_any_child_of_impl {
1482+
($MaybeTLvals:ident) => {
1483+
impl<'b, 'gcx, 'tcx> FlowInProgress<$MaybeTLvals<'b, 'gcx, 'tcx>> {
1484+
fn has_any_child_of(&self, mpi: MovePathIndex) -> Option<MovePathIndex> {
1485+
let move_data = self.base_results.operator().move_data();
1486+
1487+
let mut todo = vec![mpi];
1488+
let mut push_siblings = false; // don't look at siblings of original `mpi`.
1489+
while let Some(mpi) = todo.pop() {
1490+
if self.curr_state.contains(&mpi) {
1491+
return Some(mpi);
1492+
}
1493+
let move_path = &move_data.move_paths[mpi];
1494+
if let Some(child) = move_path.first_child {
1495+
todo.push(child);
1496+
}
1497+
if push_siblings {
1498+
if let Some(sibling) = move_path.next_sibling {
1499+
todo.push(sibling);
1500+
}
1501+
} else {
1502+
// after we've processed the original `mpi`, we should
1503+
// always traverse the siblings of any of its
1504+
// children.
1505+
push_siblings = true;
1506+
}
14941507
}
1495-
} else {
1496-
// after we've processed the original `mpi`, we should
1497-
// always traverse the siblings of any of its
1498-
// children.
1499-
push_siblings = true;
1508+
return None;
15001509
}
15011510
}
1502-
return None;
1503-
}
1511+
};
15041512
}
15051513

1514+
has_any_child_of_impl!(MaybeInitializedLvals);
1515+
has_any_child_of_impl!(MaybeUninitializedLvals);
1516+
15061517
impl<BD> FlowInProgress<BD> where BD: BitDenotation {
15071518
fn each_state_bit<F>(&self, f: F) where F: FnMut(BD::Idx) {
15081519
self.curr_state.each_bit(self.base_results.operator().bits_per_block(), f)

src/librustc_mir/transform/nll/constraint_generation.rs renamed to src/librustc_mir/borrow_check/nll/constraint_generation.rs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ use rustc::ty::fold::TypeFoldable;
2121
use rustc::util::common::ErrorReported;
2222
use rustc_data_structures::fx::FxHashSet;
2323
use syntax::codemap::DUMMY_SP;
24+
use borrow_check::FlowInProgress;
25+
use dataflow::MaybeInitializedLvals;
26+
use dataflow::move_paths::{MoveData, LookupResult};
2427

2528
use super::LivenessResults;
2629
use super::ToRegionVid;
@@ -32,25 +35,31 @@ pub(super) fn generate_constraints<'a, 'gcx, 'tcx>(
3235
mir: &Mir<'tcx>,
3336
mir_source: MirSource,
3437
liveness: &LivenessResults,
38+
flow_inits: &FlowInProgress<MaybeInitializedLvals<'a, 'gcx, 'tcx>>,
39+
move_data: &MoveData<'tcx>,
3540
) {
3641
ConstraintGeneration {
3742
infcx,
3843
regioncx,
3944
mir,
4045
liveness,
4146
mir_source,
47+
flow_inits,
48+
move_data,
4249
}.add_constraints();
4350
}
4451

45-
struct ConstraintGeneration<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
46-
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
47-
regioncx: &'cx mut RegionInferenceContext<'tcx>,
48-
mir: &'cx Mir<'tcx>,
49-
liveness: &'cx LivenessResults,
52+
struct ConstraintGeneration<'a, 'cx: 'a, 'gcx: 'tcx, 'tcx: 'cx> {
53+
infcx: &'a InferCtxt<'cx, 'gcx, 'tcx>,
54+
regioncx: &'a mut RegionInferenceContext<'tcx>,
55+
mir: &'a Mir<'tcx>,
56+
liveness: &'a LivenessResults,
5057
mir_source: MirSource,
58+
flow_inits: &'a FlowInProgress<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
59+
move_data: &'a MoveData<'tcx>,
5160
}
5261

53-
impl<'cx, 'gcx, 'tcx> ConstraintGeneration<'cx, 'gcx, 'tcx> {
62+
impl<'a, 'cx, 'gcx, 'tcx> ConstraintGeneration<'a, 'cx, 'gcx, 'tcx> {
5463
fn add_constraints(&mut self) {
5564
self.add_liveness_constraints();
5665
self.add_borrow_constraints();
@@ -78,8 +87,12 @@ impl<'cx, 'gcx, 'tcx> ConstraintGeneration<'cx, 'gcx, 'tcx> {
7887
.drop
7988
.simulate_block(self.mir, bb, |location, live_locals| {
8089
for live_local in live_locals.iter() {
81-
let live_local_ty = self.mir.local_decls[live_local].ty;
82-
self.add_drop_live_constraint(live_local_ty, location);
90+
if let LookupResult::Exact(mpi) = self.move_data.rev_lookup.find(&Lvalue::Local(live_local)) {
91+
if self.flow_inits.has_any_child_of(mpi).is_some() {
92+
let live_local_ty = self.mir.local_decls[live_local].ty;
93+
self.add_drop_live_constraint(live_local_ty, location);
94+
}
95+
}
8396
}
8497
});
8598
}
@@ -215,7 +228,7 @@ impl<'cx, 'gcx, 'tcx> ConstraintGeneration<'cx, 'gcx, 'tcx> {
215228
}
216229
}
217230

218-
impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cx, 'gcx, 'tcx> {
231+
impl<'a, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'a, 'cx, 'gcx, 'tcx> {
219232
fn visit_rvalue(&mut self,
220233
rvalue: &Rvalue<'tcx>,
221234
location: Location) {

src/librustc_mir/transform/nll/mod.rs renamed to src/librustc_mir/borrow_check/nll/mod.rs

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ use rustc::util::nodemap::FxHashMap;
1616
use std::collections::BTreeSet;
1717
use transform::type_check;
1818
use util::liveness::{self, LivenessMode, LivenessResult, LocalSet};
19+
use borrow_check::FlowInProgress;
20+
use dataflow::MaybeInitializedLvals;
21+
use dataflow::move_paths::MoveData;
1922

2023
use util as mir_util;
2124
use self::mir_util::PassWhere;
@@ -27,33 +30,20 @@ mod free_regions;
2730
pub(crate) mod region_infer;
2831
use self::region_infer::RegionInferenceContext;
2932

30-
mod renumber;
33+
pub(super) mod renumber;
3134

3235
/// Computes the (non-lexical) regions from the input MIR.
3336
///
3437
/// This may result in errors being reported.
35-
pub fn compute_regions<'a, 'gcx, 'tcx>(
38+
pub(super) fn compute_regions<'a, 'gcx, 'tcx>(
3639
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
3740
source: MirSource,
41+
mir: &Mir<'tcx>,
3842
param_env: ty::ParamEnv<'gcx>,
39-
mir: &mut Mir<'tcx>,
40-
) -> RegionInferenceContext<'tcx> {
41-
// Compute named region information.
42-
let free_regions = &free_regions::free_regions(infcx, source);
43-
44-
// Replace all regions with fresh inference variables.
45-
renumber::renumber_mir(infcx, free_regions, mir);
46-
47-
// Run the MIR type-checker.
48-
let body_id = source.item_id();
49-
let constraint_sets = &type_check::type_check(infcx, body_id, param_env, mir);
50-
51-
// Create the region inference context, taking ownership of the region inference
52-
// data that was contained in `infcx`.
53-
let var_origins = infcx.take_region_var_origins();
54-
let mut regioncx = RegionInferenceContext::new(var_origins, free_regions, mir);
55-
subtype_constraint_generation::generate(&mut regioncx, free_regions, mir, constraint_sets);
56-
43+
num_region_variables: usize,
44+
flow_inits: &FlowInProgress<MaybeInitializedLvals<'a, 'gcx, 'tcx>>,
45+
move_data: &MoveData<'tcx>,
46+
) -> RegionInferenceContext {
5747
// Compute what is live where.
5848
let liveness = &LivenessResults {
5949
regular: liveness::liveness_of_locals(
@@ -74,7 +64,8 @@ pub fn compute_regions<'a, 'gcx, 'tcx>(
7464
};
7565

7666
// Generate non-subtyping constraints.
77-
constraint_generation::generate_constraints(infcx, &mut regioncx, &mir, source, liveness);
67+
constraint_generation::generate_constraints(infcx, &mut regioncx, &mir, source, liveness,
68+
flow_inits, move_data);
7869

7970
// Solve the region constraints.
8071
regioncx.solve(infcx, &mir);

src/librustc_mir/dataflow/impls/borrows.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ use rustc_data_structures::indexed_vec::{IndexVec};
2121

2222
use dataflow::{BitDenotation, BlockSets, DataflowOperator};
2323
pub use dataflow::indexes::BorrowIndex;
24-
use transform::nll::region_infer::RegionInferenceContext;
25-
use transform::nll::ToRegionVid;
24+
use borrow_check::nll::region_infer::RegionInferenceContext;
25+
use borrow_check::nll::ToRegionVid;
2626

2727
use syntax_pos::Span;
2828

src/librustc_mir/transform/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ pub mod instcombine;
4343
pub mod copy_prop;
4444
pub mod generator;
4545
pub mod inline;
46-
pub mod nll;
4746

4847
pub(crate) fn provide(providers: &mut Providers) {
4948
self::qualify_consts::provide(providers);

0 commit comments

Comments
 (0)