1
Fork 0

groundwork refactoring of gather_moves

This commit is contained in:
Ariel Ben-Yehuda 2016-06-11 23:47:28 +03:00 committed by Ariel Ben-Yehuda
parent 89500e9341
commit eb19cd6575
8 changed files with 494 additions and 722 deletions

View file

@ -1243,7 +1243,7 @@ impl<'a, 'b> GraphSuccessors<'b> for Mir<'a> {
type Iter = IntoIter<BasicBlock>;
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Ord, PartialOrd)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct Location {
/// the location is within this block
pub block: BasicBlock,
@ -1253,3 +1253,8 @@ pub struct Location {
pub statement_index: usize,
}
impl fmt::Debug for Location {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{:?}[{}]", self.block, self.statement_index)
}
}

View file

@ -774,9 +774,6 @@ pub enum LvalueContext<'tcx> {
// Being borrowed
Borrow { region: &'tcx Region, kind: BorrowKind },
// Being sliced -- this should be same as being borrowed, probably
Slice { from_start: usize, from_end: usize },
// Used as base for another lvalue, e.g. `x` in `x.y`
Projection,

View file

@ -17,7 +17,7 @@ use super::super::MoveDataParamEnv;
use super::super::DropFlagState;
use super::super::drop_flag_effects_for_function_entry;
use super::super::drop_flag_effects_for_location;
use super::super::on_all_children_bits;
use super::super::on_lookup_result_bits;
use super::{BitDenotation, BlockSets, DataflowOperator};
@ -277,10 +277,9 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> {
dest_lval: &repr::Lvalue) {
// when a call returns successfully, that means we need to set
// the bits for that dest_lval to 1 (initialized).
let move_path_index = ctxt.move_data.rev_lookup.find(dest_lval);
on_all_children_bits(self.tcx, self.mir, &ctxt.move_data,
move_path_index,
|mpi| { in_out.add(&mpi); });
on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data,
ctxt.move_data.rev_lookup.find(dest_lval),
|mpi| { in_out.add(&mpi); });
}
}
@ -338,11 +337,10 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> {
_dest_bb: repr::BasicBlock,
dest_lval: &repr::Lvalue) {
// when a call returns successfully, that means we need to set
// the bits for that dest_lval to 1 (initialized).
let move_path_index = ctxt.move_data.rev_lookup.find(dest_lval);
on_all_children_bits(self.tcx, self.mir, &ctxt.move_data,
move_path_index,
|mpi| { in_out.remove(&mpi); });
// the bits for that dest_lval to 0 (initialized).
on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data,
ctxt.move_data.rev_lookup.find(dest_lval),
|mpi| { in_out.remove(&mpi); });
}
}
@ -400,10 +398,9 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> {
dest_lval: &repr::Lvalue) {
// when a call returns successfully, that means we need to set
// the bits for that dest_lval to 1 (initialized).
let move_path_index = ctxt.move_data.rev_lookup.find(dest_lval);
on_all_children_bits(self.tcx, self.mir, &ctxt.move_data,
move_path_index,
|mpi| { in_out.add(&mpi); });
on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data,
ctxt.move_data.rev_lookup.find(dest_lval),
|mpi| { in_out.add(&mpi); });
}
}
@ -448,11 +445,10 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> {
// assigning into this `lvalue` kills all
// MoveOuts from it, and *also* all MoveOuts
// for children and associated fragment sets.
let move_path_index = rev_lookup.find(lvalue);
on_all_children_bits(tcx,
on_lookup_result_bits(tcx,
mir,
move_data,
move_path_index,
rev_lookup.find(lvalue),
|mpi| for moi in &path_map[mpi] {
assert!(moi.index() < bits_per_block);
sets.kill_set.add(&moi);
@ -489,18 +485,17 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> {
_dest_bb: repr::BasicBlock,
dest_lval: &repr::Lvalue) {
let move_data = &ctxt.move_data;
let move_path_index = move_data.rev_lookup.find(dest_lval);
let bits_per_block = self.bits_per_block(ctxt);
let path_map = &move_data.path_map;
on_all_children_bits(self.tcx,
self.mir,
move_data,
move_path_index,
|mpi| for moi in &path_map[mpi] {
assert!(moi.index() < bits_per_block);
in_out.remove(&moi);
});
on_lookup_result_bits(self.tcx,
self.mir,
move_data,
move_data.rev_lookup.find(dest_lval),
|mpi| for moi in &path_map[mpi] {
assert!(moi.index() < bits_per_block);
in_out.remove(&moi);
});
}
}

View file

@ -16,7 +16,7 @@ use rustc::ty::{self, TyCtxt};
use rustc::mir::repr::{self, Mir};
use rustc_data_structures::indexed_vec::Idx;
use super::super::gather_moves::{MovePathIndex};
use super::super::gather_moves::{MovePathIndex, LookupResult};
use super::super::MoveDataParamEnv;
use super::BitDenotation;
use super::DataflowResults;
@ -116,20 +116,26 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
repr::BorrowKind::Shared,
ref peeking_at_lval) = *rvalue {
// Okay, our search is over.
let peek_mpi = move_data.rev_lookup.find(peeking_at_lval);
let bit_state = sets.on_entry.contains(&peek_mpi);
debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
lvalue, peeking_at_lval, bit_state);
if !bit_state {
tcx.sess.span_err(span, &format!("rustc_peek: bit not set"));
match move_data.rev_lookup.find(peeking_at_lval) {
LookupResult::Exact(peek_mpi) => {
let bit_state = sets.on_entry.contains(&peek_mpi);
debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
lvalue, peeking_at_lval, bit_state);
if !bit_state {
tcx.sess.span_err(span, "rustc_peek: bit not set");
}
}
LookupResult::Parent(..) => {
tcx.sess.span_err(span, "rustc_peek: argument untracked");
}
}
return;
} else {
// Our search should have been over, but the input
// does not match expectations of `rustc_peek` for
// this sanity_check.
let msg = &format!("rustc_peek: argument expression \
must be immediate borrow of form `&expr`");
let msg = "rustc_peek: argument expression \
must be immediate borrow of form `&expr`";
tcx.sess.span_err(span, msg);
}
}

View file

@ -9,10 +9,11 @@
// except according to those terms.
use indexed_set::IdxSetBuf;
use super::gather_moves::{MoveData, MovePathIndex, MovePathContent};
use super::gather_moves::{MoveData, MovePathIndex, LookupResult};
use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
use super::dataflow::{DataflowResults};
use super::{drop_flag_effects_for_location, on_all_children_bits};
use super::on_lookup_result_bits;
use super::{DropFlagState, MoveDataParamEnv};
use super::patch::MirPatch;
use rustc::ty::{self, Ty, TyCtxt};
@ -42,7 +43,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
}
let id = src.item_id();
let param_env = ty::ParameterEnvironment::for_item(tcx, id);
let move_data = MoveData::gather_moves(mir, tcx);
let move_data = MoveData::gather_moves(mir, tcx, &param_env);
let elaborate_patch = {
let mir = &*mir;
let env = MoveDataParamEnv {
@ -184,31 +185,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
fn path_needs_drop(&self, path: MovePathIndex) -> bool
{
match self.move_data().move_paths[path].content {
MovePathContent::Lvalue(ref lvalue) => {
let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx);
debug!("path_needs_drop({:?}, {:?} : {:?})", path, lvalue, ty);
let lvalue = &self.move_data().move_paths[path].lvalue;
let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx);
debug!("path_needs_drop({:?}, {:?} : {:?})", path, lvalue, ty);
self.tcx.type_needs_drop_given_env(ty, self.param_env())
}
_ => false
}
}
/// Returns whether this lvalue is tracked by drop elaboration. This
/// includes all lvalues, except these (1.) behind references or arrays,
/// or (2.) behind ADT's with a Drop impl.
fn lvalue_is_tracked(&self, lv: &Lvalue<'tcx>) -> bool
{
// `lvalue_contents_drop_state_cannot_differ` only compares
// the `lv` to its immediate contents, while this recursively
// follows parent chain formed by `base` of each projection.
if let &Lvalue::Projection(ref data) = lv {
!super::lvalue_contents_drop_state_cannot_differ(self.tcx, self.mir, &data.base) &&
self.lvalue_is_tracked(&data.base)
} else {
true
}
self.tcx.type_needs_drop_given_env(ty, self.param_env())
}
fn collect_drop_flags(&mut self)
@ -221,19 +202,29 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
_ => continue
};
if !self.lvalue_is_tracked(location) {
continue
}
let init_data = self.initialization_data_at(Location {
block: bb,
statement_index: data.statements.len()
});
let path = self.move_data().rev_lookup.find(location);
debug!("collect_drop_flags: {:?}, lv {:?} (index {:?})",
debug!("collect_drop_flags: {:?}, lv {:?} ({:?})",
bb, location, path);
let path = match path {
LookupResult::Exact(e) => e,
LookupResult::Parent(None) => continue,
LookupResult::Parent(Some(parent)) => {
let (_maybe_live, maybe_dead) = init_data.state(parent);
if maybe_dead {
span_bug!(terminator.source_info.span,
"drop of untracked, uninitialized value {:?}, lv {:?} ({:?})",
bb, location, path);
}
continue
}
};
on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| {
if self.path_needs_drop(child) {
let (maybe_live, maybe_dead) = init_data.state(child);
@ -257,20 +248,27 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
match terminator.kind {
TerminatorKind::Drop { ref location, target, unwind } => {
let init_data = self.initialization_data_at(loc);
let path = self.move_data().rev_lookup.find(location);
self.elaborate_drop(&DropCtxt {
source_info: terminator.source_info,
is_cleanup: data.is_cleanup,
init_data: &init_data,
lvalue: location,
path: path,
succ: target,
unwind: if data.is_cleanup {
None
} else {
Some(Option::unwrap_or(unwind, resume_block))
match self.move_data().rev_lookup.find(location) {
LookupResult::Exact(path) => {
self.elaborate_drop(&DropCtxt {
source_info: terminator.source_info,
is_cleanup: data.is_cleanup,
init_data: &init_data,
lvalue: location,
path: path,
succ: target,
unwind: if data.is_cleanup {
None
} else {
Some(Option::unwrap_or(unwind, resume_block))
}
}, bb);
}
}, bb);
LookupResult::Parent(..) => {
span_bug!(terminator.source_info.span,
"drop of untracked value {:?}", bb);
}
}
}
TerminatorKind::DropAndReplace { ref location, ref value,
target, unwind } =>
@ -336,35 +334,37 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
is_cleanup: data.is_cleanup,
});
if !self.lvalue_is_tracked(location) {
// drop and replace behind a pointer/array/whatever. The location
// must be initialized.
debug!("elaborate_drop_and_replace({:?}) - untracked", terminator);
self.patch.patch_terminator(bb, TerminatorKind::Drop {
location: location.clone(),
target: target,
unwind: Some(unwind)
});
} else {
debug!("elaborate_drop_and_replace({:?}) - tracked", terminator);
let init_data = self.initialization_data_at(loc);
let path = self.move_data().rev_lookup.find(location);
match self.move_data().rev_lookup.find(location) {
LookupResult::Exact(path) => {
debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path);
let init_data = self.initialization_data_at(loc);
self.elaborate_drop(&DropCtxt {
source_info: terminator.source_info,
is_cleanup: data.is_cleanup,
init_data: &init_data,
lvalue: location,
path: path,
succ: target,
unwind: Some(unwind)
}, bb);
on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| {
self.set_drop_flag(Location { block: target, statement_index: 0 },
child, DropFlagState::Present);
self.set_drop_flag(Location { block: unwind, statement_index: 0 },
child, DropFlagState::Present);
});
self.elaborate_drop(&DropCtxt {
source_info: terminator.source_info,
is_cleanup: data.is_cleanup,
init_data: &init_data,
lvalue: location,
path: path,
succ: target,
unwind: Some(unwind)
}, bb);
on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| {
self.set_drop_flag(Location { block: target, statement_index: 0 },
child, DropFlagState::Present);
self.set_drop_flag(Location { block: unwind, statement_index: 0 },
child, DropFlagState::Present);
});
}
LookupResult::Parent(parent) => {
// drop and replace behind a pointer/array/whatever. The location
// must be initialized.
debug!("elaborate_drop_and_replace({:?}) - untracked {:?}", terminator, parent);
self.patch.patch_terminator(bb, TerminatorKind::Drop {
location: location.clone(),
target: target,
unwind: Some(unwind)
});
}
}
}
@ -446,10 +446,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
substs: &'tcx Substs<'tcx>)
-> Vec<(Lvalue<'tcx>, Option<MovePathIndex>)>
{
let move_paths = &self.move_data().move_paths;
variant.fields.iter().enumerate().map(|(i, f)| {
let subpath =
super::move_path_children_matching(move_paths, variant_path, |p| {
super::move_path_children_matching(self.move_data(), variant_path, |p| {
match p {
&Projection {
elem: ProjectionElem::Field(idx, _), ..
@ -580,7 +579,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
let fields = tys.iter().enumerate().map(|(i, &ty)| {
(c.lvalue.clone().field(Field::new(i), ty),
super::move_path_children_matching(
&self.move_data().move_paths, c.path, |proj| match proj {
self.move_data(), c.path, |proj| match proj {
&Projection {
elem: ProjectionElem::Field(f, _), ..
} => f.index() == i,
@ -598,7 +597,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
debug!("open_drop_for_box({:?}, {:?})", c, ty);
let interior_path = super::move_path_children_matching(
&self.move_data().move_paths, c.path, |proj| match proj {
self.move_data(), c.path, |proj| match proj {
&Projection { elem: ProjectionElem::Deref, .. } => true,
_ => false
}).unwrap();
@ -625,10 +624,8 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
variant_index: usize)
-> BasicBlock
{
let move_paths = &self.move_data().move_paths;
let subpath = super::move_path_children_matching(
move_paths, c.path, |proj| match proj {
self.move_data(), c.path, |proj| match proj {
&Projection {
elem: ProjectionElem::Downcast(_, idx), ..
} => idx == variant_index,
@ -942,7 +939,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
let loc = Location { block: tgt, statement_index: 0 };
let path = self.move_data().rev_lookup.find(lv);
on_all_children_bits(
on_lookup_result_bits(
self.tcx, self.mir, self.move_data(), path,
|child| self.set_drop_flag(loc, child, DropFlagState::Present)
);
@ -1011,7 +1008,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
let loc = Location { block: bb, statement_index: data.statements.len() };
let path = self.move_data().rev_lookup.find(lv);
on_all_children_bits(
on_lookup_result_bits(
self.tcx, self.mir, self.move_data(), path,
|child| self.set_drop_flag(loc, child, DropFlagState::Present)
);

File diff suppressed because it is too large Load diff

View file

@ -34,8 +34,7 @@ use self::dataflow::{DataflowOperator};
use self::dataflow::{Dataflow, DataflowAnalysis, DataflowResults};
use self::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
use self::dataflow::{DefinitelyInitializedLvals};
use self::gather_moves::{MoveData, MovePathIndex};
use self::gather_moves::{MovePathContent, MovePathData};
use self::gather_moves::{MoveData, MovePathIndex, LookupResult};
fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option<P<MetaItem>> {
for attr in attrs {
@ -78,8 +77,8 @@ pub fn borrowck_mir<'a, 'tcx: 'a>(
let tcx = bcx.tcx;
let move_data = MoveData::gather_moves(mir, tcx);
let param_env = ty::ParameterEnvironment::for_item(tcx, id);
let move_data = MoveData::gather_moves(mir, tcx, &param_env);
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
let flow_inits =
do_dataflow(tcx, mir, id, attributes, &mdpe, MaybeInitializedLvals::new(tcx, mir));
@ -211,23 +210,23 @@ impl DropFlagState {
}
}
fn move_path_children_matching<'tcx, F>(move_paths: &MovePathData<'tcx>,
fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>,
path: MovePathIndex,
mut cond: F)
-> Option<MovePathIndex>
where F: FnMut(&repr::LvalueProjection<'tcx>) -> bool
{
let mut next_child = move_paths[path].first_child;
let mut next_child = move_data.move_paths[path].first_child;
while let Some(child_index) = next_child {
match move_paths[child_index].content {
MovePathContent::Lvalue(repr::Lvalue::Projection(ref proj)) => {
match move_data.move_paths[child_index].lvalue {
repr::Lvalue::Projection(ref proj) => {
if cond(proj) {
return Some(child_index)
}
}
_ => {}
}
next_child = move_paths[child_index].next_sibling;
next_child = move_data.move_paths[child_index].next_sibling;
}
None
@ -272,6 +271,24 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
}
}
fn on_lookup_result_bits<'a, 'tcx, F>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>,
move_data: &MoveData<'tcx>,
lookup_result: LookupResult,
each_child: F)
where F: FnMut(MovePathIndex)
{
match lookup_result {
LookupResult::Parent(..) => {
// access to untracked value - do not touch children
}
LookupResult::Exact(e) => {
on_all_children_bits(tcx, mir, move_data, e, each_child)
}
}
}
fn on_all_children_bits<'a, 'tcx, F>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>,
@ -286,12 +303,8 @@ fn on_all_children_bits<'a, 'tcx, F>(
move_data: &MoveData<'tcx>,
path: MovePathIndex) -> bool
{
match move_data.move_paths[path].content {
MovePathContent::Lvalue(ref lvalue) => {
lvalue_contents_drop_state_cannot_differ(tcx, mir, lvalue)
}
_ => true
}
lvalue_contents_drop_state_cannot_differ(
tcx, mir, &move_data.move_paths[path].lvalue)
}
fn on_all_children_bits<'a, 'tcx, F>(
@ -327,10 +340,10 @@ fn drop_flag_effects_for_function_entry<'a, 'tcx, F>(
let move_data = &ctxt.move_data;
for (arg, _) in mir.arg_decls.iter_enumerated() {
let lvalue = repr::Lvalue::Arg(arg);
let move_path_index = move_data.rev_lookup.find(&lvalue);
on_all_children_bits(tcx, mir, move_data,
move_path_index,
|moi| callback(moi, DropFlagState::Present));
let lookup_result = move_data.rev_lookup.find(&lvalue);
on_lookup_result_bits(tcx, mir, move_data,
lookup_result,
|moi| callback(moi, DropFlagState::Present));
}
}
@ -352,11 +365,10 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>(
debug!("moving out of path {:?}", move_data.move_paths[path]);
// don't move out of non-Copy things
if let MovePathContent::Lvalue(ref lvalue) = move_data.move_paths[path].content {
let ty = lvalue.ty(mir, tcx).to_ty(tcx);
if !ty.moves_by_default(tcx, param_env, DUMMY_SP) {
continue;
}
let lvalue = &move_data.move_paths[path].lvalue;
let ty = lvalue.ty(mir, tcx).to_ty(tcx);
if !ty.moves_by_default(tcx, param_env, DUMMY_SP) {
continue;
}
on_all_children_bits(tcx, mir, move_data,
@ -372,9 +384,9 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>(
}
repr::StatementKind::Assign(ref lvalue, _) => {
debug!("drop_flag_effects: assignment {:?}", stmt);
on_all_children_bits(tcx, mir, move_data,
move_data.rev_lookup.find(lvalue),
|moi| callback(moi, DropFlagState::Present))
on_lookup_result_bits(tcx, mir, move_data,
move_data.rev_lookup.find(lvalue),
|moi| callback(moi, DropFlagState::Present))
}
repr::StatementKind::StorageLive(_) |
repr::StatementKind::StorageDead(_) => {}
@ -383,9 +395,9 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>(
debug!("drop_flag_effects: replace {:?}", block.terminator());
match block.terminator().kind {
repr::TerminatorKind::DropAndReplace { ref location, .. } => {
on_all_children_bits(tcx, mir, move_data,
move_data.rev_lookup.find(location),
|moi| callback(moi, DropFlagState::Present))
on_lookup_result_bits(tcx, mir, move_data,
move_data.rev_lookup.find(location),
|moi| callback(moi, DropFlagState::Present))
}
_ => {
// other terminators do not contain move-ins

View file

@ -180,7 +180,6 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
LvalueContext::Store |
LvalueContext::Inspect |
LvalueContext::Borrow { .. } |
LvalueContext::Slice { .. } |
LvalueContext::Projection => {
self.mark_as_lvalue(index);
}