diff options
| author | Dylan MacKenzie <ecstaticmorse@gmail.com> | 2020-01-20 15:14:24 -0800 |
|---|---|---|
| committer | Dylan MacKenzie <ecstaticmorse@gmail.com> | 2020-02-10 13:03:08 -0800 |
| commit | ce3f37b42ba25ab6fe2f401135be847a0351fbbe (patch) | |
| tree | 42772fa33fb47325f0d20feb7d11d29499b2c608 | |
| parent | 702096da17254239d09e1095b060c083322b8ac2 (diff) | |
| download | rust-ce3f37b42ba25ab6fe2f401135be847a0351fbbe.tar.gz rust-ce3f37b42ba25ab6fe2f401135be847a0351fbbe.zip | |
Use new dataflow interface for initialization/borrows analyses
| -rw-r--r-- | src/librustc_mir/dataflow/impls/borrows.rs | 88 | ||||
| -rw-r--r-- | src/librustc_mir/dataflow/impls/mod.rs | 215 |
2 files changed, 195 insertions, 108 deletions
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index f94ee67f2be..151ae28bae2 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -10,7 +10,8 @@ use crate::borrow_check::{ places_conflict, BorrowData, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid, }; -use crate::dataflow::{BitDenotation, BottomValue, GenKillSet}; +use crate::dataflow::generic::{self, GenKill}; +use crate::dataflow::BottomValue; use std::rc::Rc; @@ -172,7 +173,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { /// That means they went out of a nonlexical scope fn kill_loans_out_of_scope_at_location( &self, - trans: &mut GenKillSet<BorrowIndex>, + trans: &mut impl GenKill<BorrowIndex>, location: Location, ) { // NOTE: The state associated with a given `location` @@ -187,16 +188,21 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { // region, then setting that gen-bit will override any // potential kill introduced here. if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) { - trans.kill_all(indices); + trans.kill_all(indices.iter().copied()); } } /// Kill any borrows that conflict with `place`. - fn kill_borrows_on_place(&self, trans: &mut GenKillSet<BorrowIndex>, place: &Place<'tcx>) { + fn kill_borrows_on_place(&self, trans: &mut impl GenKill<BorrowIndex>, place: &Place<'tcx>) { debug!("kill_borrows_on_place: place={:?}", place); - let other_borrows_of_local = - self.borrow_set.local_map.get(&place.local).into_iter().flat_map(|bs| bs.into_iter()); + let other_borrows_of_local = self + .borrow_set + .local_map + .get(&place.local) + .into_iter() + .flat_map(|bs| bs.into_iter()) + .copied(); // If the borrowed place is a local with no projections, all other borrows of this // local must conflict. This is purely an optimization so we don't have to call @@ -212,7 +218,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { // pair of array indices are unequal, so that when `places_conflict` returns true, we // will be assured that two places being compared definitely denotes the same sets of // locations. - let definitely_conflicting_borrows = other_borrows_of_local.filter(|&&i| { + let definitely_conflicting_borrows = other_borrows_of_local.filter(|&i| { places_conflict( self.tcx, self.body, @@ -226,36 +232,41 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { } } -impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> { +impl<'tcx> generic::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { type Idx = BorrowIndex; - fn name() -> &'static str { - "borrows" - } - fn bits_per_block(&self) -> usize { + + const NAME: &'static str = "borrows"; + + fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { self.borrow_set.borrows.len() * 2 } - fn start_block_effect(&self, _entry_set: &mut BitSet<Self::Idx>) { + fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet<Self::Idx>) { // no borrows of code region_scopes have been taken prior to // function execution, so this method has no effect. } - fn before_statement_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) { - debug!("Borrows::before_statement_effect trans: {:?} location: {:?}", trans, location); - self.kill_loans_out_of_scope_at_location(trans, location); + fn pretty_print_idx(&self, w: &mut impl std::io::Write, idx: Self::Idx) -> std::io::Result<()> { + write!(w, "{:?}", self.location(idx)) } +} - fn statement_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) { - debug!("Borrows::statement_effect: trans={:?} location={:?}", trans, location); - - let block = &self.body.basic_blocks().get(location.block).unwrap_or_else(|| { - panic!("could not find block at location {:?}", location); - }); - let stmt = block.statements.get(location.statement_index).unwrap_or_else(|| { - panic!("could not find statement at location {:?}"); - }); +impl<'tcx> generic::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { + fn before_statement_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + _statement: &mir::Statement<'tcx>, + location: Location, + ) { + self.kill_loans_out_of_scope_at_location(trans, location); + } - debug!("Borrows::statement_effect: stmt={:?}", stmt); + fn statement_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + stmt: &mir::Statement<'tcx>, + location: Location, + ) { match stmt.kind { mir::StatementKind::Assign(box (ref lhs, ref rhs)) => { if let mir::Rvalue::Ref(_, _, ref place) = *rhs { @@ -301,18 +312,29 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> { } } - fn before_terminator_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) { - debug!("Borrows::before_terminator_effect: trans={:?} location={:?}", trans, location); + fn before_terminator_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { self.kill_loans_out_of_scope_at_location(trans, location); } - fn terminator_effect(&self, _: &mut GenKillSet<Self::Idx>, _: Location) {} + fn terminator_effect( + &self, + _: &mut impl GenKill<Self::Idx>, + _: &mir::Terminator<'tcx>, + _: Location, + ) { + } - fn propagate_call_return( + fn call_return_effect( &self, - _in_out: &mut BitSet<BorrowIndex>, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, + _trans: &mut impl GenKill<Self::Idx>, + _block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], _dest_place: &mir::Place<'tcx>, ) { } diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index 6b66406338d..5b2264c2a65 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -11,8 +11,9 @@ use super::MoveDataParamEnv; use crate::util::elaborate_drops::DropFlagState; +use super::generic::{AnalysisDomain, GenKill, GenKillAnalysis}; use super::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex}; -use super::{BitDenotation, BottomValue, GenKillSet}; +use super::{BottomValue, GenKillSet}; use super::drop_flag_effects_for_function_entry; use super::drop_flag_effects_for_location; @@ -216,6 +217,7 @@ impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { /// } /// ``` pub struct EverInitializedPlaces<'a, 'tcx> { + #[allow(dead_code)] tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>, @@ -235,7 +237,7 @@ impl<'a, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, 'tcx> { impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { fn update_bits( - trans: &mut GenKillSet<MovePathIndex>, + trans: &mut impl GenKill<MovePathIndex>, path: MovePathIndex, state: DropFlagState, ) { @@ -248,7 +250,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { fn update_bits( - trans: &mut GenKillSet<MovePathIndex>, + trans: &mut impl GenKill<MovePathIndex>, path: MovePathIndex, state: DropFlagState, ) { @@ -261,7 +263,7 @@ impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { fn update_bits( - trans: &mut GenKillSet<MovePathIndex>, + trans: &mut impl GenKill<MovePathIndex>, path: MovePathIndex, state: DropFlagState, ) { @@ -272,39 +274,56 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { } } -impl<'a, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { +impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { type Idx = MovePathIndex; - fn name() -> &'static str { - "maybe_init" - } - fn bits_per_block(&self) -> usize { + + const NAME: &'static str = "maybe_init"; + + fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { self.move_data().move_paths.len() } - fn start_block_effect(&self, entry_set: &mut BitSet<MovePathIndex>) { + fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) { drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { assert!(s == DropFlagState::Present); - entry_set.insert(path); + state.insert(path); }); } - fn statement_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) { + fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> { + write!(w, "{}", self.move_data().move_paths[mpi]) + } +} + +impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { + fn statement_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + _statement: &mir::Statement<'tcx>, + location: Location, + ) { drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { Self::update_bits(trans, path, s) }) } - fn terminator_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) { + fn terminator_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { Self::update_bits(trans, path, s) }) } - fn propagate_call_return( + fn call_return_effect( &self, - in_out: &mut BitSet<MovePathIndex>, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, + trans: &mut impl GenKill<Self::Idx>, + _block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], dest_place: &mir::Place<'tcx>, ) { // when a call returns successfully, that means we need to set @@ -315,50 +334,67 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { self.move_data(), self.move_data().rev_lookup.find(dest_place.as_ref()), |mpi| { - in_out.insert(mpi); + trans.gen(mpi); }, ); } } -impl<'a, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> { +impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { type Idx = MovePathIndex; - fn name() -> &'static str { - "maybe_uninit" - } - fn bits_per_block(&self) -> usize { + + const NAME: &'static str = "maybe_uninit"; + + fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { self.move_data().move_paths.len() } // sets on_entry bits for Arg places - fn start_block_effect(&self, entry_set: &mut BitSet<MovePathIndex>) { + fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) { // set all bits to 1 (uninit) before gathering counterevidence - assert!(self.bits_per_block() == entry_set.domain_size()); - entry_set.insert_all(); + assert!(self.bits_per_block(body) == state.domain_size()); + state.insert_all(); drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { assert!(s == DropFlagState::Present); - entry_set.remove(path); + state.remove(path); }); } - fn statement_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) { + fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> { + write!(w, "{}", self.move_data().move_paths[mpi]) + } +} + +impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { + fn statement_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + _statement: &mir::Statement<'tcx>, + location: Location, + ) { drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { Self::update_bits(trans, path, s) }) } - fn terminator_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) { + fn terminator_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { Self::update_bits(trans, path, s) }) } - fn propagate_call_return( + fn call_return_effect( &self, - in_out: &mut BitSet<MovePathIndex>, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, + trans: &mut impl GenKill<Self::Idx>, + _block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], dest_place: &mir::Place<'tcx>, ) { // when a call returns successfully, that means we need to set @@ -369,48 +405,65 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> { self.move_data(), self.move_data().rev_lookup.find(dest_place.as_ref()), |mpi| { - in_out.remove(mpi); + trans.kill(mpi); }, ); } } -impl<'a, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { +impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { type Idx = MovePathIndex; - fn name() -> &'static str { - "definite_init" - } - fn bits_per_block(&self) -> usize { + + const NAME: &'static str = "definite_init"; + + fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { self.move_data().move_paths.len() } // sets on_entry bits for Arg places - fn start_block_effect(&self, entry_set: &mut BitSet<MovePathIndex>) { - entry_set.clear(); + fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) { + state.clear(); drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { assert!(s == DropFlagState::Present); - entry_set.insert(path); + state.insert(path); }); } - fn statement_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) { + fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> { + write!(w, "{}", self.move_data().move_paths[mpi]) + } +} + +impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { + fn statement_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + _statement: &mir::Statement<'tcx>, + location: Location, + ) { drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { Self::update_bits(trans, path, s) }) } - fn terminator_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) { + fn terminator_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { Self::update_bits(trans, path, s) }) } - fn propagate_call_return( + fn call_return_effect( &self, - in_out: &mut BitSet<MovePathIndex>, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, + trans: &mut impl GenKill<Self::Idx>, + _block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], dest_place: &mir::Place<'tcx>, ) { // when a call returns successfully, that means we need to set @@ -421,30 +474,36 @@ impl<'a, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { self.move_data(), self.move_data().rev_lookup.find(dest_place.as_ref()), |mpi| { - in_out.insert(mpi); + trans.gen(mpi); }, ); } } -impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> { +impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { type Idx = InitIndex; - fn name() -> &'static str { - "ever_init" - } - fn bits_per_block(&self) -> usize { + + const NAME: &'static str = "ever_init"; + + fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { self.move_data().inits.len() } - fn start_block_effect(&self, entry_set: &mut BitSet<InitIndex>) { - for arg_init in 0..self.body.arg_count { - entry_set.insert(InitIndex::new(arg_init)); + fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) { + for arg_init in 0..body.arg_count { + state.insert(InitIndex::new(arg_init)); } } +} - fn statement_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) { - let (_, body, move_data) = (self.tcx, self.body, self.move_data()); - let stmt = &body[location.block].statements[location.statement_index]; +impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { + fn statement_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + stmt: &mir::Statement<'tcx>, + location: Location, + ) { + let move_data = self.move_data(); let init_path_map = &move_data.init_path_map; let init_loc_map = &move_data.init_loc_map; let rev_lookup = &move_data.rev_lookup; @@ -453,7 +512,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> { "statement {:?} at loc {:?} initializes move_indexes {:?}", stmt, location, &init_loc_map[location] ); - trans.gen_all(&init_loc_map[location]); + trans.gen_all(init_loc_map[location].iter().copied()); match stmt.kind { mir::StatementKind::StorageDead(local) => { @@ -464,13 +523,18 @@ impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> { "stmt {:?} at loc {:?} clears the ever initialized status of {:?}", stmt, location, &init_path_map[move_path_index] ); - trans.kill_all(&init_path_map[move_path_index]); + trans.kill_all(init_path_map[move_path_index].iter().copied()); } _ => {} } } - fn terminator_effect(&self, trans: &mut GenKillSet<Self::Idx>, location: Location) { + fn terminator_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { let (body, move_data) = (self.body, self.move_data()); let term = body[location.block].terminator(); let init_loc_map = &move_data.init_loc_map; @@ -479,28 +543,29 @@ impl<'a, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'tcx> { term, location, &init_loc_map[location] ); trans.gen_all( - init_loc_map[location].iter().filter(|init_index| { - move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly - }), + init_loc_map[location] + .iter() + .filter(|init_index| { + move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly + }) + .copied(), ); } - fn propagate_call_return( + fn call_return_effect( &self, - in_out: &mut BitSet<InitIndex>, - call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, + trans: &mut impl GenKill<Self::Idx>, + block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], _dest_place: &mir::Place<'tcx>, ) { let move_data = self.move_data(); - let bits_per_block = self.bits_per_block(); let init_loc_map = &move_data.init_loc_map; - let call_loc = - Location { block: call_bb, statement_index: self.body[call_bb].statements.len() }; + let call_loc = self.body.terminator_loc(block); for init_index in &init_loc_map[call_loc] { - assert!(init_index.index() < bits_per_block); - in_out.insert(*init_index); + trans.gen(*init_index); } } } |
