Make move out computation lazy
This commit is contained in:
parent
685fb54317
commit
373fc932aa
@ -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)
|
||||
|
@ -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;
|
||||
@ -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> {
|
||||
@ -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();
|
||||
@ -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);
|
||||
@ -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) {
|
||||
@ -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,
|
||||
|
@ -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;
|
||||
@ -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
|
||||
@ -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,
|
||||
}
|
||||
@ -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);
|
||||
};
|
||||
}
|
||||
@ -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| {
|
||||
|
@ -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};
|
||||
|
||||
@ -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,
|
||||
@ -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,
|
||||
);
|
||||
@ -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:
|
||||
//
|
||||
@ -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.
|
||||
}
|
||||
@ -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:
|
||||
//
|
||||
@ -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.
|
||||
}
|
||||
|
@ -22,13 +22,13 @@ use super::MoveDataParamEnv;
|
||||
|
||||
use util::elaborate_drops::DropFlagState;
|
||||
|
||||
use super::move_paths::{HasMoveData, MoveData, MoveOutIndex, MovePathIndex, InitIndex};
|
||||
use super::move_paths::{HasMoveData, MoveData, MovePathIndex, InitIndex};
|
||||
use super::move_paths::{LookupResult, InitKind};
|
||||
use super::{BitDenotation, BlockSets, InitialFlow};
|
||||
|
||||
use super::drop_flag_effects_for_function_entry;
|
||||
use super::drop_flag_effects_for_location;
|
||||
use super::{on_lookup_result_bits, for_location_inits};
|
||||
use super::on_lookup_result_bits;
|
||||
|
||||
mod storage_liveness;
|
||||
|
||||
@ -211,40 +211,6 @@ impl<'a, 'gcx, 'tcx: 'a> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, '
|
||||
fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
|
||||
}
|
||||
|
||||
/// `MovingOutStatements` tracks the statements that perform moves out
|
||||
/// of particular places. More precisely, it tracks whether the
|
||||
/// *effect* of such moves (namely, the uninitialization of the
|
||||
/// place in question) can reach some point in the control-flow of
|
||||
/// the function, or if that effect is "killed" by some intervening
|
||||
/// operation reinitializing that place.
|
||||
///
|
||||
/// The resulting dataflow is a more enriched version of
|
||||
/// `MaybeUninitializedPlaces`. Both structures on their own only tell
|
||||
/// you if a place *might* be uninitialized at a given point in the
|
||||
/// control flow. But `MovingOutStatements` also includes the added
|
||||
/// data of *which* particular statement causing the deinitialization
|
||||
/// that the borrow checker's error message may need to report.
|
||||
#[allow(dead_code)]
|
||||
pub struct MovingOutStatements<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
mir: &'a Mir<'tcx>,
|
||||
mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx: 'tcx, 'tcx: 'a> MovingOutStatements<'a, 'gcx, 'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
mir: &'a Mir<'tcx>,
|
||||
mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>)
|
||||
-> Self
|
||||
{
|
||||
MovingOutStatements { tcx: tcx, mir: mir, mdpe: mdpe }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for MovingOutStatements<'a, 'gcx, 'tcx> {
|
||||
fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
|
||||
}
|
||||
|
||||
/// `EverInitializedPlaces` tracks all places that might have ever been
|
||||
/// initialized upon reaching a particular point in the control flow
|
||||
/// for a function, without an intervening `Storage Dead`.
|
||||
@ -488,83 +454,6 @@ impl<'a, 'gcx, 'tcx> BitDenotation for DefinitelyInitializedPlaces<'a, 'gcx, 'tc
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> BitDenotation for MovingOutStatements<'a, 'gcx, 'tcx> {
|
||||
type Idx = MoveOutIndex;
|
||||
fn name() -> &'static str { "moving_out" }
|
||||
fn bits_per_block(&self) -> usize {
|
||||
self.move_data().moves.len()
|
||||
}
|
||||
|
||||
fn start_block_effect(&self, _sets: &mut IdxSet<MoveOutIndex>) {
|
||||
// no move-statements have been executed prior to function
|
||||
// execution, so this method has no effect on `_sets`.
|
||||
}
|
||||
|
||||
fn statement_effect(&self,
|
||||
sets: &mut BlockSets<MoveOutIndex>,
|
||||
location: Location) {
|
||||
let (tcx, mir, move_data) = (self.tcx, self.mir, self.move_data());
|
||||
let stmt = &mir[location.block].statements[location.statement_index];
|
||||
let loc_map = &move_data.loc_map;
|
||||
let path_map = &move_data.path_map;
|
||||
|
||||
match 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.
|
||||
mir::StatementKind::StorageDead(_) => {}
|
||||
_ => {
|
||||
debug!("stmt {:?} at loc {:?} moves out of move_indexes {:?}",
|
||||
stmt, location, &loc_map[location]);
|
||||
// Every path deinitialized by a *particular move*
|
||||
// has corresponding bit, "gen'ed" (i.e. set)
|
||||
// here, in dataflow vector
|
||||
sets.gen_all_and_assert_dead(&loc_map[location]);
|
||||
}
|
||||
}
|
||||
|
||||
for_location_inits(tcx, mir, move_data, location,
|
||||
|mpi| sets.kill_all(&path_map[mpi]));
|
||||
}
|
||||
|
||||
fn terminator_effect(&self,
|
||||
sets: &mut BlockSets<MoveOutIndex>,
|
||||
location: Location)
|
||||
{
|
||||
let (tcx, mir, move_data) = (self.tcx, self.mir, self.move_data());
|
||||
let term = mir[location.block].terminator();
|
||||
let loc_map = &move_data.loc_map;
|
||||
let path_map = &move_data.path_map;
|
||||
|
||||
debug!("terminator {:?} at loc {:?} moves out of move_indexes {:?}",
|
||||
term, location, &loc_map[location]);
|
||||
sets.gen_all_and_assert_dead(&loc_map[location]);
|
||||
|
||||
for_location_inits(tcx, mir, move_data, location,
|
||||
|mpi| sets.kill_all(&path_map[mpi]));
|
||||
}
|
||||
|
||||
fn propagate_call_return(&self,
|
||||
in_out: &mut IdxSet<MoveOutIndex>,
|
||||
_call_bb: mir::BasicBlock,
|
||||
_dest_bb: mir::BasicBlock,
|
||||
dest_place: &mir::Place) {
|
||||
let move_data = self.move_data();
|
||||
let bits_per_block = self.bits_per_block();
|
||||
|
||||
let path_map = &move_data.path_map;
|
||||
on_lookup_result_bits(self.tcx,
|
||||
self.mir,
|
||||
move_data,
|
||||
move_data.rev_lookup.find(dest_place),
|
||||
|mpi| for moi in &path_map[mpi] {
|
||||
assert!(moi.index() < bits_per_block);
|
||||
in_out.remove(&moi);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> BitDenotation for EverInitializedPlaces<'a, 'gcx, 'tcx> {
|
||||
type Idx = InitIndex;
|
||||
fn name() -> &'static str { "ever_init" }
|
||||
@ -682,13 +571,6 @@ impl<'a, 'gcx, 'tcx> BitwiseOperator for DefinitelyInitializedPlaces<'a, 'gcx, '
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> BitwiseOperator for MovingOutStatements<'a, 'gcx, 'tcx> {
|
||||
#[inline]
|
||||
fn join(&self, pred1: Word, pred2: Word) -> Word {
|
||||
pred1 | pred2 // moves from both preds are in scope
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> BitwiseOperator for EverInitializedPlaces<'a, 'gcx, 'tcx> {
|
||||
#[inline]
|
||||
fn join(&self, pred1: Word, pred2: Word) -> Word {
|
||||
@ -727,13 +609,6 @@ impl<'a, 'gcx, 'tcx> InitialFlow for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InitialFlow for MovingOutStatements<'a, 'gcx, 'tcx> {
|
||||
#[inline]
|
||||
fn bottom_value() -> bool {
|
||||
false // bottom = no loans in scope by default
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InitialFlow for EverInitializedPlaces<'a, 'gcx, 'tcx> {
|
||||
#[inline]
|
||||
fn bottom_value() -> bool {
|
||||
|
@ -28,7 +28,7 @@ use std::usize;
|
||||
|
||||
pub use self::impls::{MaybeStorageLive};
|
||||
pub use self::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
|
||||
pub use self::impls::{DefinitelyInitializedPlaces, MovingOutStatements};
|
||||
pub use self::impls::DefinitelyInitializedPlaces;
|
||||
pub use self::impls::EverInitializedPlaces;
|
||||
pub use self::impls::borrows::Borrows;
|
||||
pub use self::impls::HaveBeenBorrowedLocals;
|
||||
@ -38,7 +38,7 @@ pub(crate) use self::drop_flag_effects::*;
|
||||
use self::move_paths::MoveData;
|
||||
|
||||
mod at_location;
|
||||
mod drop_flag_effects;
|
||||
pub mod drop_flag_effects;
|
||||
mod graphviz;
|
||||
mod impls;
|
||||
pub mod move_paths;
|
||||
@ -511,18 +511,6 @@ impl<'a, E:Idx> BlockSets<'a, E> {
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_all_and_assert_dead<I>(&mut self, i: I)
|
||||
where I: IntoIterator,
|
||||
I::Item: Borrow<E>
|
||||
{
|
||||
for j in i {
|
||||
let j = j.borrow();
|
||||
let retval = self.gen_set.add(j);
|
||||
self.kill_set.remove(j);
|
||||
assert!(retval);
|
||||
}
|
||||
}
|
||||
|
||||
fn kill(&mut self, e: &E) {
|
||||
self.gen_set.remove(e);
|
||||
self.kill_set.add(e);
|
||||
|
@ -1,9 +1,6 @@
|
||||
error[E0382]: use of moved value: `foo.x`
|
||||
--> $DIR/fields-move.rs:28:9
|
||||
|
|
||||
LL | $foo.x
|
||||
| ------ value moved here
|
||||
...
|
||||
LL | $foo.x //~ ERROR use of moved value: `foo.x`
|
||||
| ^^^^^^ value used here after move
|
||||
...
|
||||
@ -28,14 +25,9 @@ LL | assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved val
|
||||
error[E0382]: use of moved value: `foo.x`
|
||||
--> $DIR/fields-move.rs:39:42
|
||||
|
|
||||
LL | $foo.x
|
||||
| ------ value moved here
|
||||
...
|
||||
LL | $foo.x //~ ERROR use of moved value: `foo.x`
|
||||
| ------ value moved here
|
||||
...
|
||||
LL | assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x`
|
||||
| ----- value moved here
|
||||
LL | assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x`
|
||||
| ^^^^^ value used here after move
|
||||
|
|
||||
|
Loading…
Reference in New Issue
Block a user