Skip to content

Commit

Permalink
inform constraint generation using maybe-init
Browse files Browse the repository at this point in the history
In particular, if we see a variable is DROP-LIVE, but it is not
MAYBE-INIT, then we can ignore the drop. This leavess attempt to use
more complex refinements of the idea (e.g., for subpaths or subfields)
to future work.
  • Loading branch information
Nashenas88 authored and nikomatsakis committed Nov 22, 2017
1 parent 6a4de7b commit 077c2a8
Show file tree
Hide file tree
Showing 20 changed files with 416 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ use rustc::ty::maps::Providers;
use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Local, Location, Lvalue};
use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue};
use rustc::mir::{Statement, StatementKind, Terminator, TerminatorKind};
use transform::nll;

use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_set::{self, IdxSetBuf};
Expand All @@ -40,6 +39,7 @@ use util::borrowck_errors::{BorrowckErrors, Origin};
use self::MutateMode::{JustWrite, WriteAndRead};
use self::ConsumeKind::Consume;

pub(crate) mod nll;

pub fn provide(providers: &mut Providers) {
*providers = Providers {
Expand Down Expand Up @@ -78,7 +78,21 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
.as_local_node_id(def_id)
.expect("do_mir_borrowck: non-local DefId");

let move_data: MoveData<'tcx> = match MoveData::gather_moves(input_mir, tcx, param_env) {
// Make our own copy of the MIR. This copy will be modified (in place) to
// contain non-lexical lifetimes. It will have a lifetime tied
// to the inference context.
let mut mir: Mir<'tcx> = input_mir.clone();
let free_regions = if !tcx.sess.opts.debugging_opts.nll {
None
} else {
let mir = &mut mir;

// Replace all regions with fresh inference variables.
Some(nll::replace_regions_in_mir(infcx, def_id, mir))
};
let mir = &mir;

let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx, param_env) {
Ok(move_data) => move_data,
Err((move_data, move_errors)) => {
for move_error in move_errors {
Expand Down Expand Up @@ -111,60 +125,55 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
}
};

// Make our own copy of the MIR. This copy will be modified (in place) to
// contain non-lexical lifetimes. It will have a lifetime tied
// to the inference context.
let mut mir: Mir<'tcx> = input_mir.clone();
let mir = &mut mir;

// If we are in non-lexical mode, compute the non-lexical lifetimes.
let opt_regioncx = if !tcx.sess.opts.debugging_opts.nll {
None
} else {
Some(nll::compute_regions(infcx, def_id, param_env, mir))
};

let mdpe = MoveDataParamEnv {
move_data: move_data,
param_env: param_env,
};
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
let flow_borrows = do_dataflow(
tcx,
mir,
id,
&attributes,
&dead_unwinds,
Borrows::new(tcx, mir, opt_regioncx.as_ref()),
|bd, i| bd.location(i),
);
let flow_inits = do_dataflow(
let mut flow_inits = FlowInProgress::new(do_dataflow(
tcx,
mir,
id,
&attributes,
&dead_unwinds,
MaybeInitializedLvals::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().move_paths[i],
);
let flow_uninits = do_dataflow(
));
let flow_uninits = FlowInProgress::new(do_dataflow(
tcx,
mir,
id,
&attributes,
&dead_unwinds,
MaybeUninitializedLvals::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().move_paths[i],
);
let flow_move_outs = do_dataflow(
));
let flow_move_outs = FlowInProgress::new(do_dataflow(
tcx,
mir,
id,
&attributes,
&dead_unwinds,
MovingOutStatements::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().moves[i],
);
));

// If we are in non-lexical mode, compute the non-lexical lifetimes.
let opt_regioncx = if let Some(free_regions) = free_regions {
Some(nll::compute_regions(
infcx,
def_id,
free_regions,
mir,
param_env,
&mut flow_inits,
&mdpe.move_data,
))
} else {
assert!(!tcx.sess.opts.debugging_opts.nll);
None
};
let flow_inits = flow_inits; // remove mut

let mut mbcx = MirBorrowckCtxt {
tcx: tcx,
Expand All @@ -175,6 +184,16 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
storage_drop_or_dead_error_reported: FxHashSet(),
};

let flow_borrows = FlowInProgress::new(do_dataflow(
tcx,
mir,
id,
&attributes,
&dead_unwinds,
Borrows::new(tcx, mir, opt_regioncx),
|bd, i| bd.location(i),
));

let mut state = InProgress::new(flow_borrows, flow_inits, flow_uninits, flow_move_outs);

mbcx.analyze_results(&mut state); // entry point for DataflowResultsConsumer
Expand Down Expand Up @@ -2103,17 +2122,17 @@ impl ContextKind {
}

impl<'b, 'gcx, 'tcx> InProgress<'b, 'gcx, 'tcx> {
pub(super) fn new(
borrows: DataflowResults<Borrows<'b, 'gcx, 'tcx>>,
inits: DataflowResults<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
uninits: DataflowResults<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>,
move_out: DataflowResults<MovingOutStatements<'b, 'gcx, 'tcx>>,
fn new(
borrows: FlowInProgress<Borrows<'b, 'gcx, 'tcx>>,
inits: FlowInProgress<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
uninits: FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>,
move_outs: FlowInProgress<MovingOutStatements<'b, 'gcx, 'tcx>>,
) -> Self {
InProgress {
borrows: FlowInProgress::new(borrows),
inits: FlowInProgress::new(inits),
uninits: FlowInProgress::new(uninits),
move_outs: FlowInProgress::new(move_out),
borrows,
inits,
uninits,
move_outs,
}
}

Expand Down Expand Up @@ -2203,8 +2222,11 @@ impl<'b, 'gcx, 'tcx> InProgress<'b, 'gcx, 'tcx> {
}
}

impl<'b, 'gcx, 'tcx> FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>> {
fn has_any_child_of(&self, mpi: MovePathIndex) -> Option<MovePathIndex> {
impl<'tcx, T> FlowInProgress<T>
where
T: HasMoveData<'tcx> + BitDenotation<Idx = MovePathIndex>,
{
fn has_any_child_of(&self, mpi: T::Idx) -> Option<T::Idx> {
let move_data = self.base_results.operator().move_data();

let mut todo = vec![mpi];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,54 @@ use rustc::hir;
use rustc::mir::{Location, Lvalue, Mir, Rvalue};
use rustc::mir::visit::Visitor;
use rustc::mir::Lvalue::Projection;
use rustc::mir::{LvalueProjection, ProjectionElem};
use rustc::mir::{LvalueProjection, ProjectionElem, Local};
use rustc::infer::InferCtxt;
use rustc::traits::{self, ObligationCause};
use rustc::ty::{self, Ty};
use rustc::ty::fold::TypeFoldable;
use rustc::util::common::ErrorReported;
use rustc_data_structures::fx::FxHashSet;
use syntax::codemap::DUMMY_SP;
use borrow_check::FlowInProgress;
use dataflow::MaybeInitializedLvals;
use dataflow::move_paths::{MoveData, HasMoveData};

use super::LivenessResults;
use super::ToRegionVid;
use super::region_infer::RegionInferenceContext;

pub(super) fn generate_constraints<'a, 'gcx, 'tcx>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
regioncx: &mut RegionInferenceContext<'tcx>,
mir: &Mir<'tcx>,
param_env: ty::ParamEnv<'tcx>,
liveness: &LivenessResults,
flow_inits: &mut FlowInProgress<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
) {
ConstraintGeneration {
infcx,
regioncx,
mir,
liveness,
param_env,
flow_inits,
move_data,
}.add_constraints();
}

struct ConstraintGeneration<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
regioncx: &'cx mut RegionInferenceContext<'tcx>,
mir: &'cx Mir<'tcx>,
liveness: &'cx LivenessResults,
/// 'cg = the duration of the constraint generation process itself.
struct ConstraintGeneration<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> {
infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>,
regioncx: &'cg mut RegionInferenceContext<'tcx>,
mir: &'cg Mir<'tcx>,
liveness: &'cg LivenessResults,
param_env: ty::ParamEnv<'tcx>,
flow_inits: &'cg mut FlowInProgress<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
move_data: &'cg MoveData<'tcx>,
}

impl<'cx, 'gcx, 'tcx> ConstraintGeneration<'cx, 'gcx, 'tcx> {
impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
fn add_constraints(&mut self) {
self.add_liveness_constraints();
self.add_borrow_constraints();
Expand All @@ -73,14 +83,51 @@ impl<'cx, 'gcx, 'tcx> ConstraintGeneration<'cx, 'gcx, 'tcx> {
}
});

self.liveness
.drop
.simulate_block(self.mir, bb, |location, live_locals| {
for live_local in live_locals.iter() {
let mut all_live_locals: Vec<(Location, Vec<Local>)> = vec![];
self.liveness.drop.simulate_block(self.mir, bb, |location, live_locals| {
all_live_locals.push((location, live_locals.iter().collect()));
});
debug!("add_liveness_constraints: all_live_locals={:#?}", all_live_locals);

let terminator_index = self.mir.basic_blocks()[bb].statements.len();
self.flow_inits.reset_to_entry_of(bb);
while let Some((location, live_locals)) = all_live_locals.pop() {
for live_local in live_locals {
debug!("add_liveness_constraints: location={:?} live_local={:?}", location,
live_local);

self.flow_inits.each_state_bit(|mpi_init| {
debug!("add_liveness_constraints: location={:?} initialized={:?}",
location,
&self.flow_inits
.base_results
.operator()
.move_data()
.move_paths[mpi_init]);
});

let mpi = self.move_data.rev_lookup.find_local(live_local);
if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
debug!("add_liveness_constraints: mpi={:?} has initialized child {:?}",
self.move_data.move_paths[mpi],
self.move_data.move_paths[initialized_child]);

let live_local_ty = self.mir.local_decls[live_local].ty;
self.add_drop_live_constraint(live_local_ty, location);
}
});
}

if location.statement_index == terminator_index {
debug!("add_liveness_constraints: reconstruct_terminator_effect from {:#?}",
location);
self.flow_inits.reconstruct_terminator_effect(location);
} else {
debug!("add_liveness_constraints: reconstruct_statement_effect from {:#?}",
location);
self.flow_inits.reconstruct_statement_effect(location);
}
self.flow_inits.apply_local_effect();
}
}
}

Expand Down Expand Up @@ -212,7 +259,7 @@ impl<'cx, 'gcx, 'tcx> ConstraintGeneration<'cx, 'gcx, 'tcx> {
}
}

impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cx, 'gcx, 'tcx> {
impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx, 'tcx> {
fn visit_rvalue(&mut self,
rvalue: &Rvalue<'tcx>,
location: Location) {
Expand Down
Loading

0 comments on commit 077c2a8

Please sign in to comment.