Skip to content

Commit

Permalink
Make move out computation lazy
Browse files Browse the repository at this point in the history
  • Loading branch information
spastorino committed Aug 30, 2018
1 parent 685fb54 commit 373fc93
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 189 deletions.
22 changes: 22 additions & 0 deletions src/librustc/mir/mod.rs
Expand Up @@ -203,6 +203,28 @@ impl<'tcx> Mir<'tcx> {
ReadGuard::map(self.predecessors(), |p| &p[bb])
}

#[inline]
pub fn predecessor_locations(&self, loc: Location) -> impl Iterator<Item = Location> + '_ {
let if_zero_locations = if loc.statement_index == 0 {
let predecessor_blocks = self.predecessors_for(loc.block);
let num_predecessor_blocks = predecessor_blocks.len();
Some((0 .. num_predecessor_blocks)
.map(move |i| predecessor_blocks[i])
.map(move |bb| self.terminator_loc(bb))
)
} else {
None
};

let if_not_zero_locations = if loc.statement_index == 0 {
None
} else {
Some(Location { block: loc.block, statement_index: loc.statement_index - 1 })
};

if_zero_locations.into_iter().flatten().chain(if_not_zero_locations)
}

#[inline]
pub fn dominators(&self) -> Dominators<BasicBlock> {
dominators(self)
Expand Down
90 changes: 82 additions & 8 deletions src/librustc_mir/borrow_check/error_reporting.rs
Expand Up @@ -15,6 +15,7 @@ use rustc::mir::{BindingForm, BorrowKind, ClearCrossCrate, Field, Local};
use rustc::mir::{LocalDecl, LocalKind, Location, Operand, Place};
use rustc::mir::{ProjectionElem, Rvalue, Statement, StatementKind};
use rustc::ty;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::sync::Lrc;
use rustc_errors::DiagnosticBuilder;
Expand All @@ -24,8 +25,9 @@ use super::borrow_set::BorrowData;
use super::{Context, MirBorrowckCtxt};
use super::{InitializationRequiringAction, PrefixSet};

use dataflow::drop_flag_effects;
use dataflow::move_paths::MovePathIndex;
use dataflow::{FlowAtLocation, MovingOutStatements};
use dataflow::move_paths::indexes::MoveOutIndex;
use util::borrowck_errors::{BorrowckErrors, Origin};

impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Expand All @@ -35,17 +37,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
desired_action: InitializationRequiringAction,
(place, span): (&Place<'tcx>, Span),
mpi: MovePathIndex,
curr_move_out: &FlowAtLocation<MovingOutStatements<'_, 'gcx, 'tcx>>,
) {
let use_spans = self
.move_spans(place, context.loc)
.or_else(|| self.borrow_spans(span, context.loc));
let span = use_spans.args_or_use();

let mois = self.move_data.path_map[mpi]
.iter()
.filter(|moi| curr_move_out.contains(moi))
.collect::<Vec<_>>();
let mois = self.get_moved_indexes(context, mpi);
debug!("report_use_of_moved_or_uninitialized: mois={:?}", mois);

if mois.is_empty() {
let root_place = self.prefixes(&place, PrefixSet::All).last().unwrap();
Expand Down Expand Up @@ -93,7 +92,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {

let mut is_loop_move = false;
for moi in &mois {
let move_out = self.move_data.moves[**moi];
let move_out = self.move_data.moves[*moi];
let moved_place = &self.move_data.move_paths[move_out.path].place;

let move_spans = self.move_spans(moved_place, move_out.source);
Expand Down Expand Up @@ -148,7 +147,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
};

if needs_note {
let mpi = self.move_data.moves[*mois[0]].path;
let mpi = self.move_data.moves[mois[0]].path;
let place = &self.move_data.move_paths[mpi].place;

if let Some(ty) = self.retrieve_type_for_place(place) {
Expand Down Expand Up @@ -521,6 +520,81 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
err
}

fn get_moved_indexes(
&mut self,
context: Context,
mpi: MovePathIndex,
) -> Vec<MoveOutIndex> {
let mir = self.mir;

let mut stack = Vec::new();
stack.extend(mir.predecessor_locations(context.loc));

let mut visited = FxHashSet();
let mut result = vec![];

'dfs:
while let Some(l) = stack.pop() {
debug!("report_use_of_moved_or_uninitialized: current_location={:?}", l);

if !visited.insert(l) {
continue;
}

// check for moves
let stmt_kind = mir[l.block].statements.get(l.statement_index).map(|s| &s.kind);
if let Some(StatementKind::StorageDead(..)) = stmt_kind {
// this analysis only tries to find moves explicitly
// written by the user, so we ignore the move-outs
// created by `StorageDead` and at the beginning
// of a function.
} else {
for moi in &self.move_data.loc_map[l] {
debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
if self.move_data.moves[*moi].path == mpi {
debug!("report_use_of_moved_or_uninitialized: found");
result.push(*moi);

// Strictly speaking, we could continue our DFS here. There may be
// other moves that can reach the point of error. But it is kind of
// confusing to highlight them.
//
// Example:
//
// ```
// let a = vec![];
// let b = a;
// let c = a;
// drop(a); // <-- current point of error
// ```
//
// Because we stop the DFS here, we only highlight `let c = a`,
// and not `let b = a`. We will of course also report an error at
// `let c = a` which highlights `let b = a` as the move.
continue 'dfs;
}
}
}

// check for inits
let mut any_match = false;
drop_flag_effects::for_location_inits(
self.tcx,
self.mir,
self.move_data,
l,
|m| if m == mpi { any_match = true; },
);
if any_match {
continue 'dfs;
}

stack.extend(mir.predecessor_locations(l));
}

result
}

pub(super) fn report_illegal_mutation_of_borrowed(
&mut self,
context: Context,
Expand Down
18 changes: 1 addition & 17 deletions src/librustc_mir/borrow_check/flows.rs
Expand Up @@ -24,7 +24,7 @@ use polonius_engine::Output;
use dataflow::move_paths::indexes::BorrowIndex;
use dataflow::move_paths::HasMoveData;
use dataflow::Borrows;
use dataflow::{EverInitializedPlaces, MovingOutStatements};
use dataflow::EverInitializedPlaces;
use dataflow::{FlowAtLocation, FlowsAtLocation};
use dataflow::MaybeUninitializedPlaces;
use either::Either;
Expand All @@ -35,7 +35,6 @@ use std::rc::Rc;
crate struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> {
borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
pub uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
pub move_outs: FlowAtLocation<MovingOutStatements<'b, 'gcx, 'tcx>>,
pub ever_inits: FlowAtLocation<EverInitializedPlaces<'b, 'gcx, 'tcx>>,

/// Polonius Output
Expand All @@ -46,14 +45,12 @@ impl<'b, 'gcx, 'tcx> Flows<'b, 'gcx, 'tcx> {
crate fn new(
borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
move_outs: FlowAtLocation<MovingOutStatements<'b, 'gcx, 'tcx>>,
ever_inits: FlowAtLocation<EverInitializedPlaces<'b, 'gcx, 'tcx>>,
polonius_output: Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
) -> Self {
Flows {
borrows,
uninits,
move_outs,
ever_inits,
polonius_output,
}
Expand All @@ -79,7 +76,6 @@ macro_rules! each_flow {
($this:ident, $meth:ident($arg:ident)) => {
FlowAtLocation::$meth(&mut $this.borrows, $arg);
FlowAtLocation::$meth(&mut $this.uninits, $arg);
FlowAtLocation::$meth(&mut $this.move_outs, $arg);
FlowAtLocation::$meth(&mut $this.ever_inits, $arg);
};
}
Expand Down Expand Up @@ -146,18 +142,6 @@ impl<'b, 'gcx, 'tcx> fmt::Display for Flows<'b, 'gcx, 'tcx> {
});
s.push_str("] ");

s.push_str("move_out: [");
let mut saw_one = false;
self.move_outs.each_state_bit(|mpi_move_out| {
if saw_one {
s.push_str(", ");
};
saw_one = true;
let move_out = &self.move_outs.operator().move_data().moves[mpi_move_out];
s.push_str(&format!("{:?}", move_out));
});
s.push_str("] ");

s.push_str("ever_init: [");
let mut saw_one = false;
self.ever_inits.each_state_bit(|mpi_ever_init| {
Expand Down
16 changes: 1 addition & 15 deletions src/librustc_mir/borrow_check/mod.rs
Expand Up @@ -43,7 +43,7 @@ use dataflow::DataflowResultsConsumer;
use dataflow::FlowAtLocation;
use dataflow::MoveDataParamEnv;
use dataflow::{do_dataflow, DebugFormatted};
use dataflow::{EverInitializedPlaces, MovingOutStatements};
use dataflow::EverInitializedPlaces;
use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
use util::borrowck_errors::{BorrowckErrors, Origin};

Expand Down Expand Up @@ -186,15 +186,6 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
MaybeUninitializedPlaces::new(tcx, mir, &mdpe),
|bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
));
let flow_move_outs = FlowAtLocation::new(do_dataflow(
tcx,
mir,
id,
&attributes,
&dead_unwinds,
MovingOutStatements::new(tcx, mir, &mdpe),
|bd, i| DebugFormatted::new(&bd.move_data().moves[i]),
));
let flow_ever_inits = FlowAtLocation::new(do_dataflow(
tcx,
mir,
Expand Down Expand Up @@ -268,7 +259,6 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
let mut state = Flows::new(
flow_borrows,
flow_uninits,
flow_move_outs,
flow_ever_inits,
polonius_output,
);
Expand Down Expand Up @@ -1617,7 +1607,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let place = self.base_path(place_span.0);

let maybe_uninits = &flow_state.uninits;
let curr_move_outs = &flow_state.move_outs;

// Bad scenarios:
//
Expand Down Expand Up @@ -1663,7 +1652,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
desired_action,
place_span,
mpi,
curr_move_outs,
);
return; // don't bother finding other problems.
}
Expand Down Expand Up @@ -1691,7 +1679,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let place = self.base_path(place_span.0);

let maybe_uninits = &flow_state.uninits;
let curr_move_outs = &flow_state.move_outs;

// Bad scenarios:
//
Expand Down Expand Up @@ -1727,7 +1714,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
desired_action,
place_span,
child_mpi,
curr_move_outs,
);
return; // don't bother finding other problems.
}
Expand Down

0 comments on commit 373fc93

Please sign in to comment.