1
Fork 0

Rollup merge of #133938 - nnethercote:rustc_mir_dataflow-renamings, r=oli-obk

`rustc_mir_dataflow` cleanups, including some renamings

Some opinionated commits in this collection, let's see how we go.

r? `@cjgillot`
This commit is contained in:
Matthias Krüger 2024-12-13 17:25:29 +01:00 committed by GitHub
commit c6ebe6fe3b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 362 additions and 424 deletions

View file

@ -8,7 +8,10 @@ use rustc_middle::mir::{
}; };
use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_middle::ty::{RegionVid, TyCtxt};
use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::fmt::DebugWithContext;
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces}; use rustc_mir_dataflow::impls::{
EverInitializedPlaces, EverInitializedPlacesDomain, MaybeUninitializedPlaces,
MaybeUninitializedPlacesDomain,
};
use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice, SwitchIntEdgeEffects}; use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice, SwitchIntEdgeEffects};
use tracing::debug; use tracing::debug;
@ -24,7 +27,7 @@ pub(crate) struct Borrowck<'a, 'tcx> {
} }
impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
type Domain = BorrowckDomain<'a, 'tcx>; type Domain = BorrowckDomain;
const NAME: &'static str = "borrowck"; const NAME: &'static str = "borrowck";
@ -41,48 +44,48 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
unreachable!(); unreachable!();
} }
fn apply_before_statement_effect( fn apply_early_statement_effect(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
stmt: &mir::Statement<'tcx>, stmt: &mir::Statement<'tcx>,
loc: Location, loc: Location,
) { ) {
self.borrows.apply_before_statement_effect(&mut state.borrows, stmt, loc); self.borrows.apply_early_statement_effect(&mut state.borrows, stmt, loc);
self.uninits.apply_before_statement_effect(&mut state.uninits, stmt, loc); self.uninits.apply_early_statement_effect(&mut state.uninits, stmt, loc);
self.ever_inits.apply_before_statement_effect(&mut state.ever_inits, stmt, loc); self.ever_inits.apply_early_statement_effect(&mut state.ever_inits, stmt, loc);
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
stmt: &mir::Statement<'tcx>, stmt: &mir::Statement<'tcx>,
loc: Location, loc: Location,
) { ) {
self.borrows.apply_statement_effect(&mut state.borrows, stmt, loc); self.borrows.apply_primary_statement_effect(&mut state.borrows, stmt, loc);
self.uninits.apply_statement_effect(&mut state.uninits, stmt, loc); self.uninits.apply_primary_statement_effect(&mut state.uninits, stmt, loc);
self.ever_inits.apply_statement_effect(&mut state.ever_inits, stmt, loc); self.ever_inits.apply_primary_statement_effect(&mut state.ever_inits, stmt, loc);
} }
fn apply_before_terminator_effect( fn apply_early_terminator_effect(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
term: &mir::Terminator<'tcx>, term: &mir::Terminator<'tcx>,
loc: Location, loc: Location,
) { ) {
self.borrows.apply_before_terminator_effect(&mut state.borrows, term, loc); self.borrows.apply_early_terminator_effect(&mut state.borrows, term, loc);
self.uninits.apply_before_terminator_effect(&mut state.uninits, term, loc); self.uninits.apply_early_terminator_effect(&mut state.uninits, term, loc);
self.ever_inits.apply_before_terminator_effect(&mut state.ever_inits, term, loc); self.ever_inits.apply_early_terminator_effect(&mut state.ever_inits, term, loc);
} }
fn apply_terminator_effect<'mir>( fn apply_primary_terminator_effect<'mir>(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
term: &'mir mir::Terminator<'tcx>, term: &'mir mir::Terminator<'tcx>,
loc: Location, loc: Location,
) -> TerminatorEdges<'mir, 'tcx> { ) -> TerminatorEdges<'mir, 'tcx> {
self.borrows.apply_terminator_effect(&mut state.borrows, term, loc); self.borrows.apply_primary_terminator_effect(&mut state.borrows, term, loc);
self.uninits.apply_terminator_effect(&mut state.uninits, term, loc); self.uninits.apply_primary_terminator_effect(&mut state.uninits, term, loc);
self.ever_inits.apply_terminator_effect(&mut state.ever_inits, term, loc); self.ever_inits.apply_primary_terminator_effect(&mut state.ever_inits, term, loc);
// This return value doesn't matter. It's only used by `iterate_to_fixpoint`, which this // This return value doesn't matter. It's only used by `iterate_to_fixpoint`, which this
// analysis doesn't use. // analysis doesn't use.
@ -110,14 +113,14 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
} }
} }
impl JoinSemiLattice for BorrowckDomain<'_, '_> { impl JoinSemiLattice for BorrowckDomain {
fn join(&mut self, _other: &Self) -> bool { fn join(&mut self, _other: &Self) -> bool {
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use. // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
unreachable!(); unreachable!();
} }
} }
impl<'tcx, C> DebugWithContext<C> for BorrowckDomain<'_, 'tcx> impl<'tcx, C> DebugWithContext<C> for BorrowckDomain
where where
C: rustc_mir_dataflow::move_paths::HasMoveData<'tcx>, C: rustc_mir_dataflow::move_paths::HasMoveData<'tcx>,
{ {
@ -160,10 +163,10 @@ where
/// The transient state of the dataflow analyses used by the borrow checker. /// The transient state of the dataflow analyses used by the borrow checker.
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct BorrowckDomain<'a, 'tcx> { pub(crate) struct BorrowckDomain {
pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain, pub(crate) borrows: BorrowsDomain,
pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain, pub(crate) uninits: MaybeUninitializedPlacesDomain,
pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain, pub(crate) ever_inits: EverInitializedPlacesDomain,
} }
rustc_index::newtype_index! { rustc_index::newtype_index! {
@ -503,7 +506,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
/// That means they went out of a nonlexical scope /// That means they went out of a nonlexical scope
fn kill_loans_out_of_scope_at_location( fn kill_loans_out_of_scope_at_location(
&self, &self,
trans: &mut <Self as Analysis<'tcx>>::Domain, state: &mut <Self as Analysis<'tcx>>::Domain,
location: Location, location: Location,
) { ) {
// NOTE: The state associated with a given `location` // NOTE: The state associated with a given `location`
@ -518,14 +521,14 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
// region, then setting that gen-bit will override any // region, then setting that gen-bit will override any
// potential kill introduced here. // potential kill introduced here.
if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) { if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) {
trans.kill_all(indices.iter().copied()); state.kill_all(indices.iter().copied());
} }
} }
/// Kill any borrows that conflict with `place`. /// Kill any borrows that conflict with `place`.
fn kill_borrows_on_place( fn kill_borrows_on_place(
&self, &self,
trans: &mut <Self as Analysis<'tcx>>::Domain, state: &mut <Self as Analysis<'tcx>>::Domain,
place: Place<'tcx>, place: Place<'tcx>,
) { ) {
debug!("kill_borrows_on_place: place={:?}", place); debug!("kill_borrows_on_place: place={:?}", place);
@ -543,7 +546,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
// `places_conflict` for every borrow. // `places_conflict` for every borrow.
if place.projection.is_empty() { if place.projection.is_empty() {
if !self.body.local_decls[place.local].is_ref_to_static() { if !self.body.local_decls[place.local].is_ref_to_static() {
trans.kill_all(other_borrows_of_local); state.kill_all(other_borrows_of_local);
} }
return; return;
} }
@ -562,10 +565,12 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
) )
}); });
trans.kill_all(definitely_conflicting_borrows); state.kill_all(definitely_conflicting_borrows);
} }
} }
type BorrowsDomain = BitSet<BorrowIndex>;
/// Forward dataflow computation of the set of borrows that are in scope at a particular location. /// Forward dataflow computation of the set of borrows that are in scope at a particular location.
/// - we gen the introduced loans /// - we gen the introduced loans
/// - we kill loans on locals going out of (regular) scope /// - we kill loans on locals going out of (regular) scope
@ -574,7 +579,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
/// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of /// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of
/// `a.b.c` when `a` is overwritten. /// `a.b.c` when `a` is overwritten.
impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
type Domain = BitSet<BorrowIndex>; type Domain = BorrowsDomain;
const NAME: &'static str = "borrows"; const NAME: &'static str = "borrows";
@ -588,18 +593,18 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
// function execution, so this method has no effect. // function execution, so this method has no effect.
} }
fn apply_before_statement_effect( fn apply_early_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>, _statement: &mir::Statement<'tcx>,
location: Location, location: Location,
) { ) {
self.kill_loans_out_of_scope_at_location(trans, location); self.kill_loans_out_of_scope_at_location(state, location);
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
stmt: &mir::Statement<'tcx>, stmt: &mir::Statement<'tcx>,
location: Location, location: Location,
) { ) {
@ -617,18 +622,18 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
panic!("could not find BorrowIndex for location {location:?}"); panic!("could not find BorrowIndex for location {location:?}");
}); });
trans.gen_(index); state.gen_(index);
} }
// Make sure there are no remaining borrows for variables // Make sure there are no remaining borrows for variables
// that are assigned over. // that are assigned over.
self.kill_borrows_on_place(trans, *lhs); self.kill_borrows_on_place(state, *lhs);
} }
mir::StatementKind::StorageDead(local) => { mir::StatementKind::StorageDead(local) => {
// Make sure there are no remaining borrows for locals that // Make sure there are no remaining borrows for locals that
// are gone out of scope. // are gone out of scope.
self.kill_borrows_on_place(trans, Place::from(*local)); self.kill_borrows_on_place(state, Place::from(*local));
} }
mir::StatementKind::FakeRead(..) mir::StatementKind::FakeRead(..)
@ -646,18 +651,18 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
} }
} }
fn apply_before_terminator_effect( fn apply_early_terminator_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_terminator: &mir::Terminator<'tcx>, _terminator: &mir::Terminator<'tcx>,
location: Location, location: Location,
) { ) {
self.kill_loans_out_of_scope_at_location(trans, location); self.kill_loans_out_of_scope_at_location(state, location);
} }
fn apply_terminator_effect<'mir>( fn apply_primary_terminator_effect<'mir>(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,
_location: Location, _location: Location,
) -> TerminatorEdges<'mir, 'tcx> { ) -> TerminatorEdges<'mir, 'tcx> {
@ -666,7 +671,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
if let mir::InlineAsmOperand::Out { place: Some(place), .. } if let mir::InlineAsmOperand::Out { place: Some(place), .. }
| mir::InlineAsmOperand::InOut { out_place: Some(place), .. } = *op | mir::InlineAsmOperand::InOut { out_place: Some(place), .. } = *op
{ {
self.kill_borrows_on_place(trans, place); self.kill_borrows_on_place(state, place);
} }
} }
} }

View file

@ -43,7 +43,7 @@ use rustc_mir_dataflow::impls::{
use rustc_mir_dataflow::move_paths::{ use rustc_mir_dataflow::move_paths::{
InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex, InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex,
}; };
use rustc_mir_dataflow::{Analysis, EntrySets, Results, ResultsVisitor, visit_results}; use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
use rustc_session::lint::builtin::UNUSED_MUT; use rustc_session::lint::builtin::UNUSED_MUT;
use rustc_span::{Span, Symbol}; use rustc_span::{Span, Symbol};
use smallvec::SmallVec; use smallvec::SmallVec;
@ -426,14 +426,14 @@ fn get_flow_results<'a, 'tcx>(
ever_inits: ever_inits.analysis, ever_inits: ever_inits.analysis,
}; };
assert_eq!(borrows.entry_sets.len(), uninits.entry_sets.len()); assert_eq!(borrows.entry_states.len(), uninits.entry_states.len());
assert_eq!(borrows.entry_sets.len(), ever_inits.entry_sets.len()); assert_eq!(borrows.entry_states.len(), ever_inits.entry_states.len());
let entry_sets: EntrySets<'_, Borrowck<'_, '_>> = let entry_states: EntryStates<'_, Borrowck<'_, '_>> =
itertools::izip!(borrows.entry_sets, uninits.entry_sets, ever_inits.entry_sets) itertools::izip!(borrows.entry_states, uninits.entry_states, ever_inits.entry_states)
.map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits }) .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
.collect(); .collect();
Results { analysis, entry_sets } Results { analysis, entry_states }
} }
pub(crate) struct BorrowckInferCtxt<'tcx> { pub(crate) struct BorrowckInferCtxt<'tcx> {
@ -600,10 +600,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
// 3. assignments do not affect things loaned out as immutable // 3. assignments do not affect things loaned out as immutable
// 4. moves do not affect things loaned out in any way // 4. moves do not affect things loaned out in any way
impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> { impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
fn visit_statement_before_primary_effect( fn visit_after_early_statement_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
stmt: &'a Statement<'tcx>, stmt: &'a Statement<'tcx>,
location: Location, location: Location,
) { ) {
@ -674,10 +674,10 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
} }
} }
fn visit_terminator_before_primary_effect( fn visit_after_early_terminator_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
term: &'a Terminator<'tcx>, term: &'a Terminator<'tcx>,
loc: Location, loc: Location,
) { ) {
@ -787,10 +787,10 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
} }
} }
fn visit_terminator_after_primary_effect( fn visit_after_primary_terminator_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
term: &'a Terminator<'tcx>, term: &'a Terminator<'tcx>,
loc: Location, loc: Location,
) { ) {
@ -983,7 +983,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
place_span: (Place<'tcx>, Span), place_span: (Place<'tcx>, Span),
kind: (AccessDepth, ReadOrWrite), kind: (AccessDepth, ReadOrWrite),
is_local_mutation_allowed: LocalMutationIsAllowed, is_local_mutation_allowed: LocalMutationIsAllowed,
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) { ) {
let (sd, rw) = kind; let (sd, rw) = kind;
@ -1032,7 +1032,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
place_span: (Place<'tcx>, Span), place_span: (Place<'tcx>, Span),
sd: AccessDepth, sd: AccessDepth,
rw: ReadOrWrite, rw: ReadOrWrite,
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) -> bool { ) -> bool {
let mut error_reported = false; let mut error_reported = false;
@ -1172,7 +1172,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
location: Location, location: Location,
place_span: (Place<'tcx>, Span), place_span: (Place<'tcx>, Span),
kind: AccessDepth, kind: AccessDepth,
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) { ) {
// Write of P[i] or *P requires P init'd. // Write of P[i] or *P requires P init'd.
self.check_if_assigned_path_is_moved(location, place_span, state); self.check_if_assigned_path_is_moved(location, place_span, state);
@ -1190,7 +1190,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
&mut self, &mut self,
location: Location, location: Location,
(rvalue, span): (&'a Rvalue<'tcx>, Span), (rvalue, span): (&'a Rvalue<'tcx>, Span),
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) { ) {
match rvalue { match rvalue {
&Rvalue::Ref(_ /*rgn*/, bk, place) => { &Rvalue::Ref(_ /*rgn*/, bk, place) => {
@ -1448,7 +1448,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
&mut self, &mut self,
location: Location, location: Location,
(operand, span): (&'a Operand<'tcx>, Span), (operand, span): (&'a Operand<'tcx>, Span),
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) { ) {
match *operand { match *operand {
Operand::Copy(place) => { Operand::Copy(place) => {
@ -1568,12 +1568,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
} }
} }
fn check_activations( fn check_activations(&mut self, location: Location, span: Span, state: &BorrowckDomain) {
&mut self,
location: Location,
span: Span,
state: &BorrowckDomain<'a, 'tcx>,
) {
// Two-phase borrow support: For each activation that is newly // Two-phase borrow support: For each activation that is newly
// generated at this statement, check if it interferes with // generated at this statement, check if it interferes with
// another borrow. // another borrow.
@ -1731,7 +1726,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
location: Location, location: Location,
desired_action: InitializationRequiringAction, desired_action: InitializationRequiringAction,
place_span: (PlaceRef<'tcx>, Span), place_span: (PlaceRef<'tcx>, Span),
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) { ) {
let maybe_uninits = &state.uninits; let maybe_uninits = &state.uninits;
@ -1836,7 +1831,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
location: Location, location: Location,
desired_action: InitializationRequiringAction, desired_action: InitializationRequiringAction,
place_span: (PlaceRef<'tcx>, Span), place_span: (PlaceRef<'tcx>, Span),
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) { ) {
let maybe_uninits = &state.uninits; let maybe_uninits = &state.uninits;
@ -1935,7 +1930,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
&mut self, &mut self,
location: Location, location: Location,
(place, span): (Place<'tcx>, Span), (place, span): (Place<'tcx>, Span),
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) { ) {
debug!("check_if_assigned_path_is_moved place: {:?}", place); debug!("check_if_assigned_path_is_moved place: {:?}", place);
@ -2001,7 +1996,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
location: Location, location: Location,
base: PlaceRef<'tcx>, base: PlaceRef<'tcx>,
span: Span, span: Span,
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) { ) {
// rust-lang/rust#21232: Until Rust allows reads from the // rust-lang/rust#21232: Until Rust allows reads from the
// initialized parts of partially initialized structs, we // initialized parts of partially initialized structs, we
@ -2092,7 +2087,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
(place, span): (Place<'tcx>, Span), (place, span): (Place<'tcx>, Span),
kind: ReadOrWrite, kind: ReadOrWrite,
is_local_mutation_allowed: LocalMutationIsAllowed, is_local_mutation_allowed: LocalMutationIsAllowed,
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
location: Location, location: Location,
) -> bool { ) -> bool {
debug!( debug!(
@ -2206,18 +2201,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
} }
} }
fn is_local_ever_initialized( fn is_local_ever_initialized(&self, local: Local, state: &BorrowckDomain) -> Option<InitIndex> {
&self,
local: Local,
state: &BorrowckDomain<'a, 'tcx>,
) -> Option<InitIndex> {
let mpi = self.move_data.rev_lookup.find_local(local)?; let mpi = self.move_data.rev_lookup.find_local(local)?;
let ii = &self.move_data.init_path_map[mpi]; let ii = &self.move_data.init_path_map[mpi];
ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied() ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied()
} }
/// Adds the place into the used mutable variables set /// Adds the place into the used mutable variables set
fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain<'a, 'tcx>) { fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain) {
match root_place { match root_place {
RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => { RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
// If the local may have been initialized, and it is now currently being // If the local may have been initialized, and it is now currently being

View file

@ -329,7 +329,7 @@ where
self.transfer_function(state).initialize_state(); self.transfer_function(state).initialize_state();
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
statement: &mir::Statement<'tcx>, statement: &mir::Statement<'tcx>,
@ -338,7 +338,7 @@ where
self.transfer_function(state).visit_statement(statement, location); self.transfer_function(state).visit_statement(statement, location);
} }
fn apply_terminator_effect<'mir>( fn apply_primary_terminator_effect<'mir>(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,

View file

@ -179,15 +179,15 @@ where
/// Advances the cursor to hold the dataflow state at `target` before its "primary" effect is /// Advances the cursor to hold the dataflow state at `target` before its "primary" effect is
/// applied. /// applied.
/// ///
/// The "before" effect at the target location *will be* applied. /// The "early" effect at the target location *will be* applied.
pub fn seek_before_primary_effect(&mut self, target: Location) { pub fn seek_before_primary_effect(&mut self, target: Location) {
self.seek_after(target, Effect::Before) self.seek_after(target, Effect::Early)
} }
/// Advances the cursor to hold the dataflow state at `target` after its "primary" effect is /// Advances the cursor to hold the dataflow state at `target` after its "primary" effect is
/// applied. /// applied.
/// ///
/// The "before" effect at the target location will be applied as well. /// The "early" effect at the target location will be applied as well.
pub fn seek_after_primary_effect(&mut self, target: Location) { pub fn seek_after_primary_effect(&mut self, target: Location) {
self.seek_after(target, Effect::Primary) self.seek_after(target, Effect::Primary)
} }
@ -222,12 +222,12 @@ where
#[rustfmt::skip] #[rustfmt::skip]
let next_effect = if A::Direction::IS_FORWARD { let next_effect = if A::Direction::IS_FORWARD {
self.pos.curr_effect_index.map_or_else( self.pos.curr_effect_index.map_or_else(
|| Effect::Before.at_index(0), || Effect::Early.at_index(0),
EffectIndex::next_in_forward_order, EffectIndex::next_in_forward_order,
) )
} else { } else {
self.pos.curr_effect_index.map_or_else( self.pos.curr_effect_index.map_or_else(
|| Effect::Before.at_index(block_data.statements.len()), || Effect::Early.at_index(block_data.statements.len()),
EffectIndex::next_in_backward_order, EffectIndex::next_in_backward_order,
) )
}; };

View file

@ -66,12 +66,12 @@ impl Direction for Backward {
{ {
let terminator = block_data.terminator(); let terminator = block_data.terminator();
let location = Location { block, statement_index: block_data.statements.len() }; let location = Location { block, statement_index: block_data.statements.len() };
analysis.apply_before_terminator_effect(state, terminator, location); analysis.apply_early_terminator_effect(state, terminator, location);
analysis.apply_terminator_effect(state, terminator, location); analysis.apply_primary_terminator_effect(state, terminator, location);
for (statement_index, statement) in block_data.statements.iter().enumerate().rev() { for (statement_index, statement) in block_data.statements.iter().enumerate().rev() {
let location = Location { block, statement_index }; let location = Location { block, statement_index };
analysis.apply_before_statement_effect(state, statement, location); analysis.apply_early_statement_effect(state, statement, location);
analysis.apply_statement_effect(state, statement, location); analysis.apply_primary_statement_effect(state, statement, location);
} }
let exit_state = state; let exit_state = state;
@ -159,14 +159,14 @@ impl Direction for Backward {
let location = Location { block, statement_index: from.statement_index }; let location = Location { block, statement_index: from.statement_index };
let terminator = block_data.terminator(); let terminator = block_data.terminator();
if from.effect == Effect::Before { if from.effect == Effect::Early {
analysis.apply_before_terminator_effect(state, terminator, location); analysis.apply_early_terminator_effect(state, terminator, location);
if to == Effect::Before.at_index(terminator_index) { if to == Effect::Early.at_index(terminator_index) {
return; return;
} }
} }
analysis.apply_terminator_effect(state, terminator, location); analysis.apply_primary_terminator_effect(state, terminator, location);
if to == Effect::Primary.at_index(terminator_index) { if to == Effect::Primary.at_index(terminator_index) {
return; return;
} }
@ -180,7 +180,7 @@ impl Direction for Backward {
let location = Location { block, statement_index: from.statement_index }; let location = Location { block, statement_index: from.statement_index };
let statement = &block_data.statements[from.statement_index]; let statement = &block_data.statements[from.statement_index];
analysis.apply_statement_effect(state, statement, location); analysis.apply_primary_statement_effect(state, statement, location);
if to == Effect::Primary.at_index(from.statement_index) { if to == Effect::Primary.at_index(from.statement_index) {
return; return;
} }
@ -188,7 +188,7 @@ impl Direction for Backward {
from.statement_index - 1 from.statement_index - 1
} }
Effect::Before => from.statement_index, Effect::Early => from.statement_index,
}; };
// Handle all statements between `first_unapplied_idx` and `to.statement_index`. // Handle all statements between `first_unapplied_idx` and `to.statement_index`.
@ -196,21 +196,21 @@ impl Direction for Backward {
for statement_index in (to.statement_index..next_effect).rev().map(|i| i + 1) { for statement_index in (to.statement_index..next_effect).rev().map(|i| i + 1) {
let location = Location { block, statement_index }; let location = Location { block, statement_index };
let statement = &block_data.statements[statement_index]; let statement = &block_data.statements[statement_index];
analysis.apply_before_statement_effect(state, statement, location); analysis.apply_early_statement_effect(state, statement, location);
analysis.apply_statement_effect(state, statement, location); analysis.apply_primary_statement_effect(state, statement, location);
} }
// Handle the statement at `to`. // Handle the statement at `to`.
let location = Location { block, statement_index: to.statement_index }; let location = Location { block, statement_index: to.statement_index };
let statement = &block_data.statements[to.statement_index]; let statement = &block_data.statements[to.statement_index];
analysis.apply_before_statement_effect(state, statement, location); analysis.apply_early_statement_effect(state, statement, location);
if to.effect == Effect::Before { if to.effect == Effect::Early {
return; return;
} }
analysis.apply_statement_effect(state, statement, location); analysis.apply_primary_statement_effect(state, statement, location);
} }
fn visit_results_in_block<'mir, 'tcx, A>( fn visit_results_in_block<'mir, 'tcx, A>(
@ -228,17 +228,17 @@ impl Direction for Backward {
let loc = Location { block, statement_index: block_data.statements.len() }; let loc = Location { block, statement_index: block_data.statements.len() };
let term = block_data.terminator(); let term = block_data.terminator();
results.analysis.apply_before_terminator_effect(state, term, loc); results.analysis.apply_early_terminator_effect(state, term, loc);
vis.visit_terminator_before_primary_effect(results, state, term, loc); vis.visit_after_early_terminator_effect(results, state, term, loc);
results.analysis.apply_terminator_effect(state, term, loc); results.analysis.apply_primary_terminator_effect(state, term, loc);
vis.visit_terminator_after_primary_effect(results, state, term, loc); vis.visit_after_primary_terminator_effect(results, state, term, loc);
for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() { for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
let loc = Location { block, statement_index }; let loc = Location { block, statement_index };
results.analysis.apply_before_statement_effect(state, stmt, loc); results.analysis.apply_early_statement_effect(state, stmt, loc);
vis.visit_statement_before_primary_effect(results, state, stmt, loc); vis.visit_after_early_statement_effect(results, state, stmt, loc);
results.analysis.apply_statement_effect(state, stmt, loc); results.analysis.apply_primary_statement_effect(state, stmt, loc);
vis.visit_statement_after_primary_effect(results, state, stmt, loc); vis.visit_after_primary_statement_effect(results, state, stmt, loc);
} }
vis.visit_block_start(state); vis.visit_block_start(state);
@ -294,13 +294,13 @@ impl Direction for Forward {
{ {
for (statement_index, statement) in block_data.statements.iter().enumerate() { for (statement_index, statement) in block_data.statements.iter().enumerate() {
let location = Location { block, statement_index }; let location = Location { block, statement_index };
analysis.apply_before_statement_effect(state, statement, location); analysis.apply_early_statement_effect(state, statement, location);
analysis.apply_statement_effect(state, statement, location); analysis.apply_primary_statement_effect(state, statement, location);
} }
let terminator = block_data.terminator(); let terminator = block_data.terminator();
let location = Location { block, statement_index: block_data.statements.len() }; let location = Location { block, statement_index: block_data.statements.len() };
analysis.apply_before_terminator_effect(state, terminator, location); analysis.apply_early_terminator_effect(state, terminator, location);
let edges = analysis.apply_terminator_effect(state, terminator, location); let edges = analysis.apply_primary_terminator_effect(state, terminator, location);
let exit_state = state; let exit_state = state;
match edges { match edges {
@ -368,21 +368,21 @@ impl Direction for Forward {
// after effect, do so now and start the loop below from the next statement. // after effect, do so now and start the loop below from the next statement.
let first_unapplied_index = match from.effect { let first_unapplied_index = match from.effect {
Effect::Before => from.statement_index, Effect::Early => from.statement_index,
Effect::Primary if from.statement_index == terminator_index => { Effect::Primary if from.statement_index == terminator_index => {
debug_assert_eq!(from, to); debug_assert_eq!(from, to);
let location = Location { block, statement_index: terminator_index }; let location = Location { block, statement_index: terminator_index };
let terminator = block_data.terminator(); let terminator = block_data.terminator();
analysis.apply_terminator_effect(state, terminator, location); analysis.apply_primary_terminator_effect(state, terminator, location);
return; return;
} }
Effect::Primary => { Effect::Primary => {
let location = Location { block, statement_index: from.statement_index }; let location = Location { block, statement_index: from.statement_index };
let statement = &block_data.statements[from.statement_index]; let statement = &block_data.statements[from.statement_index];
analysis.apply_statement_effect(state, statement, location); analysis.apply_primary_statement_effect(state, statement, location);
// If we only needed to apply the after effect of the statement at `idx`, we are // If we only needed to apply the after effect of the statement at `idx`, we are
// done. // done.
@ -399,8 +399,8 @@ impl Direction for Forward {
for statement_index in first_unapplied_index..to.statement_index { for statement_index in first_unapplied_index..to.statement_index {
let location = Location { block, statement_index }; let location = Location { block, statement_index };
let statement = &block_data.statements[statement_index]; let statement = &block_data.statements[statement_index];
analysis.apply_before_statement_effect(state, statement, location); analysis.apply_early_statement_effect(state, statement, location);
analysis.apply_statement_effect(state, statement, location); analysis.apply_primary_statement_effect(state, statement, location);
} }
// Handle the statement or terminator at `to`. // Handle the statement or terminator at `to`.
@ -408,17 +408,17 @@ impl Direction for Forward {
let location = Location { block, statement_index: to.statement_index }; let location = Location { block, statement_index: to.statement_index };
if to.statement_index == terminator_index { if to.statement_index == terminator_index {
let terminator = block_data.terminator(); let terminator = block_data.terminator();
analysis.apply_before_terminator_effect(state, terminator, location); analysis.apply_early_terminator_effect(state, terminator, location);
if to.effect == Effect::Primary { if to.effect == Effect::Primary {
analysis.apply_terminator_effect(state, terminator, location); analysis.apply_primary_terminator_effect(state, terminator, location);
} }
} else { } else {
let statement = &block_data.statements[to.statement_index]; let statement = &block_data.statements[to.statement_index];
analysis.apply_before_statement_effect(state, statement, location); analysis.apply_early_statement_effect(state, statement, location);
if to.effect == Effect::Primary { if to.effect == Effect::Primary {
analysis.apply_statement_effect(state, statement, location); analysis.apply_primary_statement_effect(state, statement, location);
} }
} }
} }
@ -438,18 +438,18 @@ impl Direction for Forward {
for (statement_index, stmt) in block_data.statements.iter().enumerate() { for (statement_index, stmt) in block_data.statements.iter().enumerate() {
let loc = Location { block, statement_index }; let loc = Location { block, statement_index };
results.analysis.apply_before_statement_effect(state, stmt, loc); results.analysis.apply_early_statement_effect(state, stmt, loc);
vis.visit_statement_before_primary_effect(results, state, stmt, loc); vis.visit_after_early_statement_effect(results, state, stmt, loc);
results.analysis.apply_statement_effect(state, stmt, loc); results.analysis.apply_primary_statement_effect(state, stmt, loc);
vis.visit_statement_after_primary_effect(results, state, stmt, loc); vis.visit_after_primary_statement_effect(results, state, stmt, loc);
} }
let loc = Location { block, statement_index: block_data.statements.len() }; let loc = Location { block, statement_index: block_data.statements.len() };
let term = block_data.terminator(); let term = block_data.terminator();
results.analysis.apply_before_terminator_effect(state, term, loc); results.analysis.apply_early_terminator_effect(state, term, loc);
vis.visit_terminator_before_primary_effect(results, state, term, loc); vis.visit_after_early_terminator_effect(results, state, term, loc);
results.analysis.apply_terminator_effect(state, term, loc); results.analysis.apply_primary_terminator_effect(state, term, loc);
vis.visit_terminator_after_primary_effect(results, state, term, loc); vis.visit_after_primary_terminator_effect(results, state, term, loc);
vis.visit_block_end(state); vis.visit_block_end(state);
} }

View file

@ -724,7 +724,7 @@ where
} }
} }
fn visit_statement_before_primary_effect( fn visit_after_early_statement_effect(
&mut self, &mut self,
results: &mut Results<'tcx, A>, results: &mut Results<'tcx, A>,
state: &A::Domain, state: &A::Domain,
@ -737,7 +737,7 @@ where
} }
} }
fn visit_statement_after_primary_effect( fn visit_after_primary_statement_effect(
&mut self, &mut self,
results: &mut Results<'tcx, A>, results: &mut Results<'tcx, A>,
state: &A::Domain, state: &A::Domain,
@ -748,7 +748,7 @@ where
self.prev_state.clone_from(state) self.prev_state.clone_from(state)
} }
fn visit_terminator_before_primary_effect( fn visit_after_early_terminator_effect(
&mut self, &mut self,
results: &mut Results<'tcx, A>, results: &mut Results<'tcx, A>,
state: &A::Domain, state: &A::Domain,
@ -761,7 +761,7 @@ where
} }
} }
fn visit_terminator_after_primary_effect( fn visit_after_primary_terminator_effect(
&mut self, &mut self,
results: &mut Results<'tcx, A>, results: &mut Results<'tcx, A>,
state: &A::Domain, state: &A::Domain,

View file

@ -38,10 +38,8 @@
//! [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram //! [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram
//! [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set //! [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set
use std::iter; use rustc_index::Idx;
use rustc_index::bit_set::{BitSet, MixedBitSet}; use rustc_index::bit_set::{BitSet, MixedBitSet};
use rustc_index::{Idx, IndexVec};
use crate::framework::BitSetExt; use crate::framework::BitSetExt;
@ -70,53 +68,6 @@ pub trait HasTop {
const TOP: Self; const TOP: Self;
} }
/// A `bool` is a "two-point" lattice with `true` as the top element and `false` as the bottom:
///
/// ```text
/// true
/// |
/// false
/// ```
impl JoinSemiLattice for bool {
fn join(&mut self, other: &Self) -> bool {
if let (false, true) = (*self, *other) {
*self = true;
return true;
}
false
}
}
impl HasBottom for bool {
const BOTTOM: Self = false;
fn is_bottom(&self) -> bool {
!self
}
}
impl HasTop for bool {
const TOP: Self = true;
}
/// A tuple (or list) of lattices is itself a lattice whose least upper bound is the concatenation
/// of the least upper bounds of each element of the tuple (or list).
///
/// In other words:
/// (A₀, A₁, ..., Aₙ) (B₀, B₁, ..., Bₙ) = (A₀B₀, A₁B₁, ..., AₙBₙ)
impl<I: Idx, T: JoinSemiLattice> JoinSemiLattice for IndexVec<I, T> {
fn join(&mut self, other: &Self) -> bool {
assert_eq!(self.len(), other.len());
let mut changed = false;
for (a, b) in iter::zip(self, other) {
changed |= a.join(b);
}
changed
}
}
/// A `BitSet` represents the lattice formed by the powerset of all possible values of /// A `BitSet` represents the lattice formed by the powerset of all possible values of
/// the index type `T` ordered by inclusion. Equivalently, it is a tuple of "two-point" lattices, /// the index type `T` ordered by inclusion. Equivalently, it is a tuple of "two-point" lattices,
/// one for each possible value of `T`. /// one for each possible value of `T`.
@ -197,18 +148,6 @@ impl<T> MaybeReachable<T> {
} }
} }
impl<T> HasBottom for MaybeReachable<T> {
const BOTTOM: Self = MaybeReachable::Unreachable;
fn is_bottom(&self) -> bool {
matches!(self, Self::Unreachable)
}
}
impl<T: HasTop> HasTop for MaybeReachable<T> {
const TOP: Self = MaybeReachable::Reachable(T::TOP);
}
impl<S> MaybeReachable<S> { impl<S> MaybeReachable<S> {
/// Return whether the current state contains the given element. If the state is unreachable, /// Return whether the current state contains the given element. If the state is unreachable,
/// it does no contain anything. /// it does no contain anything.

View file

@ -56,7 +56,7 @@ mod visitor;
pub use self::cursor::ResultsCursor; pub use self::cursor::ResultsCursor;
pub use self::direction::{Backward, Direction, Forward}; pub use self::direction::{Backward, Direction, Forward};
pub use self::lattice::{JoinSemiLattice, MaybeReachable}; pub use self::lattice::{JoinSemiLattice, MaybeReachable};
pub use self::results::{EntrySets, Results}; pub use self::results::{EntryStates, Results};
pub use self::visitor::{ResultsVisitor, visit_results}; pub use self::visitor::{ResultsVisitor, visit_results};
/// Analysis domains are all bitsets of various kinds. This trait holds /// Analysis domains are all bitsets of various kinds. This trait holds
@ -122,8 +122,23 @@ pub trait Analysis<'tcx> {
// `resume`). It's not obvious how to handle `yield` points in coroutines, however. // `resume`). It's not obvious how to handle `yield` points in coroutines, however.
fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain); fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain);
/// Updates the current dataflow state with an "early" effect, i.e. one
/// that occurs immediately before the given statement.
///
/// This method is useful if the consumer of the results of this analysis only needs to observe
/// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule,
/// analyses should not implement this without also implementing
/// `apply_primary_statement_effect`.
fn apply_early_statement_effect(
&mut self,
_state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>,
_location: Location,
) {
}
/// Updates the current dataflow state with the effect of evaluating a statement. /// Updates the current dataflow state with the effect of evaluating a statement.
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
statement: &mir::Statement<'tcx>, statement: &mir::Statement<'tcx>,
@ -131,15 +146,16 @@ pub trait Analysis<'tcx> {
); );
/// Updates the current dataflow state with an effect that occurs immediately *before* the /// Updates the current dataflow state with an effect that occurs immediately *before* the
/// given statement. /// given terminator.
/// ///
/// This method is useful if the consumer of the results of this analysis only needs to observe /// This method is useful if the consumer of the results of this analysis needs only to observe
/// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule, /// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
/// analyses should not implement this without also implementing `apply_statement_effect`. /// analyses should not implement this without also implementing
fn apply_before_statement_effect( /// `apply_primary_terminator_effect`.
fn apply_early_terminator_effect(
&mut self, &mut self,
_state: &mut Self::Domain, _state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>, _terminator: &mir::Terminator<'tcx>,
_location: Location, _location: Location,
) { ) {
} }
@ -150,7 +166,7 @@ pub trait Analysis<'tcx> {
/// in this function. That should go in `apply_call_return_effect`. For example, in the /// in this function. That should go in `apply_call_return_effect`. For example, in the
/// `InitializedPlaces` analyses, the return place for a function call is not marked as /// `InitializedPlaces` analyses, the return place for a function call is not marked as
/// initialized here. /// initialized here.
fn apply_terminator_effect<'mir>( fn apply_primary_terminator_effect<'mir>(
&mut self, &mut self,
_state: &mut Self::Domain, _state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,
@ -159,27 +175,13 @@ pub trait Analysis<'tcx> {
terminator.edges() terminator.edges()
} }
/// Updates the current dataflow state with an effect that occurs immediately *before* the
/// given terminator.
///
/// This method is useful if the consumer of the results of this analysis needs only to observe
/// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
/// analyses should not implement this without also implementing `apply_terminator_effect`.
fn apply_before_terminator_effect(
&mut self,
_state: &mut Self::Domain,
_terminator: &mir::Terminator<'tcx>,
_location: Location,
) {
}
/* Edge-specific effects */ /* Edge-specific effects */
/// Updates the current dataflow state with the effect of a successful return from a `Call` /// Updates the current dataflow state with the effect of a successful return from a `Call`
/// terminator. /// terminator.
/// ///
/// This is separate from `apply_terminator_effect` to properly track state across unwind /// This is separate from `apply_primary_terminator_effect` to properly track state across
/// edges. /// unwind edges.
fn apply_call_return_effect( fn apply_call_return_effect(
&mut self, &mut self,
_state: &mut Self::Domain, _state: &mut Self::Domain,
@ -234,11 +236,12 @@ pub trait Analysis<'tcx> {
Self: Sized, Self: Sized,
Self::Domain: DebugWithContext<Self>, Self::Domain: DebugWithContext<Self>,
{ {
let mut entry_sets = let mut entry_states =
IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len()); IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len());
self.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]); self.initialize_start_block(body, &mut entry_states[mir::START_BLOCK]);
if Self::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != self.bottom_value(body) { if Self::Direction::IS_BACKWARD && entry_states[mir::START_BLOCK] != self.bottom_value(body)
{
bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
} }
@ -262,9 +265,9 @@ pub trait Analysis<'tcx> {
let mut state = self.bottom_value(body); let mut state = self.bottom_value(body);
while let Some(bb) = dirty_queue.pop() { while let Some(bb) = dirty_queue.pop() {
// Set the state to the entry state of the block. // Set the state to the entry state of the block.
// This is equivalent to `state = entry_sets[bb].clone()`, // This is equivalent to `state = entry_states[bb].clone()`,
// but it saves an allocation, thus improving compile times. // but it saves an allocation, thus improving compile times.
state.clone_from(&entry_sets[bb]); state.clone_from(&entry_states[bb]);
Self::Direction::apply_effects_in_block( Self::Direction::apply_effects_in_block(
&mut self, &mut self,
@ -273,7 +276,7 @@ pub trait Analysis<'tcx> {
bb, bb,
&body[bb], &body[bb],
|target: BasicBlock, state: &Self::Domain| { |target: BasicBlock, state: &Self::Domain| {
let set_changed = entry_sets[target].join(state); let set_changed = entry_states[target].join(state);
if set_changed { if set_changed {
dirty_queue.insert(target); dirty_queue.insert(target);
} }
@ -281,7 +284,7 @@ pub trait Analysis<'tcx> {
); );
} }
let mut results = Results { analysis: self, entry_sets }; let mut results = Results { analysis: self, entry_states };
if tcx.sess.opts.unstable_opts.dump_mir_dataflow { if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
let res = write_graphviz_results(tcx, body, &mut results, pass_name); let res = write_graphviz_results(tcx, body, &mut results, pass_name);
@ -358,11 +361,10 @@ impl<T, S: GenKill<T>> GenKill<T> for MaybeReachable<S> {
// NOTE: DO NOT CHANGE VARIANT ORDER. The derived `Ord` impls rely on the current order. // NOTE: DO NOT CHANGE VARIANT ORDER. The derived `Ord` impls rely on the current order.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Effect { enum Effect {
/// The "before" effect (e.g., `apply_before_statement_effect`) for a statement (or /// The "early" effect (e.g., `apply_early_statement_effect`) for a statement/terminator.
/// terminator). Early,
Before,
/// The "primary" effect (e.g., `apply_statement_effect`) for a statement (or terminator). /// The "primary" effect (e.g., `apply_primary_statement_effect`) for a statement/terminator.
Primary, Primary,
} }
@ -381,15 +383,15 @@ pub struct EffectIndex {
impl EffectIndex { impl EffectIndex {
fn next_in_forward_order(self) -> Self { fn next_in_forward_order(self) -> Self {
match self.effect { match self.effect {
Effect::Before => Effect::Primary.at_index(self.statement_index), Effect::Early => Effect::Primary.at_index(self.statement_index),
Effect::Primary => Effect::Before.at_index(self.statement_index + 1), Effect::Primary => Effect::Early.at_index(self.statement_index + 1),
} }
} }
fn next_in_backward_order(self) -> Self { fn next_in_backward_order(self) -> Self {
match self.effect { match self.effect {
Effect::Before => Effect::Primary.at_index(self.statement_index), Effect::Early => Effect::Primary.at_index(self.statement_index),
Effect::Primary => Effect::Before.at_index(self.statement_index - 1), Effect::Primary => Effect::Early.at_index(self.statement_index - 1),
} }
} }

View file

@ -6,7 +6,7 @@ use rustc_middle::mir::{BasicBlock, Body, traversal};
use super::{Analysis, ResultsCursor, ResultsVisitor, visit_results}; use super::{Analysis, ResultsCursor, ResultsVisitor, visit_results};
use crate::framework::cursor::ResultsHandle; use crate::framework::cursor::ResultsHandle;
pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>; pub type EntryStates<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
/// A dataflow analysis that has converged to fixpoint. It only holds the domain values at the /// A dataflow analysis that has converged to fixpoint. It only holds the domain values at the
/// entry of each basic block. Domain values in other parts of the block are recomputed on the fly /// entry of each basic block. Domain values in other parts of the block are recomputed on the fly
@ -17,7 +17,7 @@ where
A: Analysis<'tcx>, A: Analysis<'tcx>,
{ {
pub analysis: A, pub analysis: A,
pub entry_sets: EntrySets<'tcx, A>, pub entry_states: EntryStates<'tcx, A>,
} }
impl<'tcx, A> Results<'tcx, A> impl<'tcx, A> Results<'tcx, A>
@ -40,7 +40,7 @@ where
/// Gets the dataflow state for the given block. /// Gets the dataflow state for the given block.
pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain { pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain {
&self.entry_sets[block] &self.entry_states[block]
} }
pub fn visit_with<'mir>( pub fn visit_with<'mir>(

View file

@ -73,7 +73,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {
/// ///
/// The `102` in the block's entry set is derived from the basic block index and ensures that the /// The `102` in the block's entry set is derived from the basic block index and ensures that the
/// expected state is unique across all basic blocks. Remember, it is generated by /// expected state is unique across all basic blocks. Remember, it is generated by
/// `mock_entry_sets`, not from actually running `MockAnalysis` to fixpoint. /// `mock_entry_states`, not from actually running `MockAnalysis` to fixpoint.
struct MockAnalysis<'tcx, D> { struct MockAnalysis<'tcx, D> {
body: &'tcx mir::Body<'tcx>, body: &'tcx mir::Body<'tcx>,
dir: PhantomData<D>, dir: PhantomData<D>,
@ -90,7 +90,7 @@ impl<D: Direction> MockAnalysis<'_, D> {
ret ret
} }
fn mock_entry_sets(&self) -> IndexVec<BasicBlock, BitSet<usize>> { fn mock_entry_states(&self) -> IndexVec<BasicBlock, BitSet<usize>> {
let empty = self.bottom_value(self.body); let empty = self.bottom_value(self.body);
let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks); let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks);
@ -104,7 +104,7 @@ impl<D: Direction> MockAnalysis<'_, D> {
/// Returns the index that should be added to the dataflow state at the given target. /// Returns the index that should be added to the dataflow state at the given target.
fn effect(&self, loc: EffectIndex) -> usize { fn effect(&self, loc: EffectIndex) -> usize {
let idx = match loc.effect { let idx = match loc.effect {
Effect::Before => loc.statement_index * 2, Effect::Early => loc.statement_index * 2,
Effect::Primary => loc.statement_index * 2 + 1, Effect::Primary => loc.statement_index * 2 + 1,
}; };
@ -128,14 +128,14 @@ impl<D: Direction> MockAnalysis<'_, D> {
let target = match target { let target = match target {
SeekTarget::BlockEntry { .. } => return ret, SeekTarget::BlockEntry { .. } => return ret,
SeekTarget::Before(loc) => Effect::Before.at_index(loc.statement_index), SeekTarget::Early(loc) => Effect::Early.at_index(loc.statement_index),
SeekTarget::After(loc) => Effect::Primary.at_index(loc.statement_index), SeekTarget::After(loc) => Effect::Primary.at_index(loc.statement_index),
}; };
let mut pos = if D::IS_FORWARD { let mut pos = if D::IS_FORWARD {
Effect::Before.at_index(0) Effect::Early.at_index(0)
} else { } else {
Effect::Before.at_index(self.body[block].statements.len()) Effect::Early.at_index(self.body[block].statements.len())
}; };
loop { loop {
@ -168,7 +168,17 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
unimplemented!("This is never called since `MockAnalysis` is never iterated to fixpoint"); unimplemented!("This is never called since `MockAnalysis` is never iterated to fixpoint");
} }
fn apply_statement_effect( fn apply_early_statement_effect(
&mut self,
state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>,
location: Location,
) {
let idx = self.effect(Effect::Early.at_index(location.statement_index));
assert!(state.insert(idx));
}
fn apply_primary_statement_effect(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>, _statement: &mir::Statement<'tcx>,
@ -178,17 +188,17 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
assert!(state.insert(idx)); assert!(state.insert(idx));
} }
fn apply_before_statement_effect( fn apply_early_terminator_effect(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>, _terminator: &mir::Terminator<'tcx>,
location: Location, location: Location,
) { ) {
let idx = self.effect(Effect::Before.at_index(location.statement_index)); let idx = self.effect(Effect::Early.at_index(location.statement_index));
assert!(state.insert(idx)); assert!(state.insert(idx));
} }
fn apply_terminator_effect<'mir>( fn apply_primary_terminator_effect<'mir>(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,
@ -198,22 +208,12 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
assert!(state.insert(idx)); assert!(state.insert(idx));
terminator.edges() terminator.edges()
} }
fn apply_before_terminator_effect(
&mut self,
state: &mut Self::Domain,
_terminator: &mir::Terminator<'tcx>,
location: Location,
) {
let idx = self.effect(Effect::Before.at_index(location.statement_index));
assert!(state.insert(idx));
}
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum SeekTarget { enum SeekTarget {
BlockEntry(BasicBlock), BlockEntry(BasicBlock),
Before(Location), Early(Location),
After(Location), After(Location),
} }
@ -223,7 +223,7 @@ impl SeekTarget {
match *self { match *self {
BlockEntry(block) => block, BlockEntry(block) => block,
Before(loc) | After(loc) => loc.block, Early(loc) | After(loc) => loc.block,
} }
} }
@ -235,7 +235,7 @@ impl SeekTarget {
.map(move |(i, kind)| { .map(move |(i, kind)| {
let loc = Location { block, statement_index: i }; let loc = Location { block, statement_index: i };
match kind { match kind {
0 => SeekTarget::Before(loc), 0 => SeekTarget::Early(loc),
1 => SeekTarget::After(loc), 1 => SeekTarget::After(loc),
_ => unreachable!(), _ => unreachable!(),
} }
@ -249,7 +249,7 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
let body = analysis.body; let body = analysis.body;
let mut cursor = let mut cursor =
Results { entry_sets: analysis.mock_entry_sets(), analysis }.into_results_cursor(body); Results { entry_states: analysis.mock_entry_states(), analysis }.into_results_cursor(body);
cursor.allow_unreachable(); cursor.allow_unreachable();
@ -262,7 +262,7 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
match targ { match targ {
BlockEntry(block) => cursor.seek_to_block_entry(block), BlockEntry(block) => cursor.seek_to_block_entry(block),
Before(loc) => cursor.seek_before_primary_effect(loc), Early(loc) => cursor.seek_before_primary_effect(loc),
After(loc) => cursor.seek_after_primary_effect(loc), After(loc) => cursor.seek_after_primary_effect(loc),
} }

View file

@ -35,9 +35,9 @@ where
{ {
fn visit_block_start(&mut self, _state: &A::Domain) {} fn visit_block_start(&mut self, _state: &A::Domain) {}
/// Called with the `before_statement_effect` of the given statement applied to `state` but not /// // njn: grep for "before", "primary", etc.
/// its `statement_effect`. /// Called after the "early" effect of the given statement is applied to `state`.
fn visit_statement_before_primary_effect( fn visit_after_early_statement_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, A>, _results: &mut Results<'tcx, A>,
_state: &A::Domain, _state: &A::Domain,
@ -46,9 +46,8 @@ where
) { ) {
} }
/// Called with both the `before_statement_effect` and the `statement_effect` of the given /// Called after the "primary" effect of the given statement is applied to `state`.
/// statement applied to `state`. fn visit_after_primary_statement_effect(
fn visit_statement_after_primary_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, A>, _results: &mut Results<'tcx, A>,
_state: &A::Domain, _state: &A::Domain,
@ -57,9 +56,8 @@ where
) { ) {
} }
/// Called with the `before_terminator_effect` of the given terminator applied to `state` but /// Called after the "early" effect of the given terminator is applied to `state`.
/// not its `terminator_effect`. fn visit_after_early_terminator_effect(
fn visit_terminator_before_primary_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, A>, _results: &mut Results<'tcx, A>,
_state: &A::Domain, _state: &A::Domain,
@ -68,11 +66,10 @@ where
) { ) {
} }
/// Called with both the `before_terminator_effect` and the `terminator_effect` of the given /// Called after the "primary" effect of the given terminator is applied to `state`.
/// terminator applied to `state`.
/// ///
/// The `call_return_effect` (if one exists) will *not* be applied to `state`. /// The `call_return_effect` (if one exists) will *not* be applied to `state`.
fn visit_terminator_after_primary_effect( fn visit_after_primary_terminator_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, A>, _results: &mut Results<'tcx, A>,
_state: &A::Domain, _state: &A::Domain,

View file

@ -33,22 +33,22 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals {
// No locals are aliased on function entry // No locals are aliased on function entry
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
statement: &Statement<'tcx>, statement: &Statement<'tcx>,
location: Location, location: Location,
) { ) {
Self::transfer_function(trans).visit_statement(statement, location); Self::transfer_function(state).visit_statement(statement, location);
} }
fn apply_terminator_effect<'mir>( fn apply_primary_terminator_effect<'mir>(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir Terminator<'tcx>, terminator: &'mir Terminator<'tcx>,
location: Location, location: Location,
) -> TerminatorEdges<'mir, 'tcx> { ) -> TerminatorEdges<'mir, 'tcx> {
Self::transfer_function(trans).visit_terminator(terminator, location); Self::transfer_function(state).visit_terminator(terminator, location);
terminator.edges() terminator.edges()
} }
} }

View file

@ -70,7 +70,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
pub fn is_unwind_dead( pub fn is_unwind_dead(
&self, &self,
place: mir::Place<'tcx>, place: mir::Place<'tcx>,
state: &MaybeReachable<MixedBitSet<MovePathIndex>>, state: &<Self as Analysis<'tcx>>::Domain,
) -> bool { ) -> bool {
if let LookupResult::Exact(path) = self.move_data().rev_lookup.find(place.as_ref()) { if let LookupResult::Exact(path) = self.move_data().rev_lookup.find(place.as_ref()) {
let mut maybe_live = false; let mut maybe_live = false;
@ -218,26 +218,26 @@ impl<'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'_, 'tcx> {
impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
fn update_bits( fn update_bits(
trans: &mut <Self as Analysis<'tcx>>::Domain, state: &mut <Self as Analysis<'tcx>>::Domain,
path: MovePathIndex, path: MovePathIndex,
state: DropFlagState, dfstate: DropFlagState,
) { ) {
match state { match dfstate {
DropFlagState::Absent => trans.kill(path), DropFlagState::Absent => state.kill(path),
DropFlagState::Present => trans.gen_(path), DropFlagState::Present => state.gen_(path),
} }
} }
} }
impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> { impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> {
fn update_bits( fn update_bits(
trans: &mut <Self as Analysis<'tcx>>::Domain, state: &mut <Self as Analysis<'tcx>>::Domain,
path: MovePathIndex, path: MovePathIndex,
state: DropFlagState, dfstate: DropFlagState,
) { ) {
match state { match dfstate {
DropFlagState::Absent => trans.gen_(path), DropFlagState::Absent => state.gen_(path),
DropFlagState::Present => trans.kill(path), DropFlagState::Present => state.kill(path),
} }
} }
} }
@ -263,14 +263,14 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
}); });
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
statement: &mir::Statement<'tcx>, statement: &mir::Statement<'tcx>,
location: Location, location: Location,
) { ) {
drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| { drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
Self::update_bits(trans, path, s) Self::update_bits(state, path, s)
}); });
// Mark all places as "maybe init" if they are mutably borrowed. See #90752. // Mark all places as "maybe init" if they are mutably borrowed. See #90752.
@ -282,12 +282,12 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
&& let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref()) && let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref())
{ {
on_all_children_bits(self.move_data(), mpi, |child| { on_all_children_bits(self.move_data(), mpi, |child| {
trans.gen_(child); state.gen_(child);
}) })
} }
} }
fn apply_terminator_effect<'mir>( fn apply_primary_terminator_effect<'mir>(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,
@ -309,7 +309,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
fn apply_call_return_effect( fn apply_call_return_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_block: mir::BasicBlock, _block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>, return_places: CallReturnPlaces<'_, 'tcx>,
) { ) {
@ -320,7 +320,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
self.move_data(), self.move_data(),
self.move_data().rev_lookup.find(place.as_ref()), self.move_data().rev_lookup.find(place.as_ref()),
|mpi| { |mpi| {
trans.gen_(mpi); state.gen_(mpi);
}, },
); );
}); });
@ -345,7 +345,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
}; };
let mut discriminants = enum_def.discriminants(self.tcx); let mut discriminants = enum_def.discriminants(self.tcx);
edge_effects.apply(|trans, edge| { edge_effects.apply(|state, edge| {
let Some(value) = edge.value else { let Some(value) = edge.value else {
return; return;
}; };
@ -363,25 +363,27 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
self.move_data(), self.move_data(),
enum_place, enum_place,
variant, variant,
|mpi| trans.kill(mpi), |mpi| state.kill(mpi),
); );
}); });
} }
} }
/// There can be many more `MovePathIndex` than there are locals in a MIR body.
/// We use a mixed bitset to avoid paying too high a memory footprint.
pub type MaybeUninitializedPlacesDomain = MixedBitSet<MovePathIndex>;
impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
/// There can be many more `MovePathIndex` than there are locals in a MIR body. type Domain = MaybeUninitializedPlacesDomain;
/// We use a mixed bitset to avoid paying too high a memory footprint.
type Domain = MixedBitSet<MovePathIndex>;
const NAME: &'static str = "maybe_uninit"; const NAME: &'static str = "maybe_uninit";
fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
// bottom = initialized (start_block_effect counters this at outset) // bottom = initialized (`initialize_start_block` overwrites this on first entry)
MixedBitSet::new_empty(self.move_data().move_paths.len()) MixedBitSet::new_empty(self.move_data().move_paths.len())
} }
// sets on_entry bits for Arg places // sets state bits for Arg places
fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
// set all bits to 1 (uninit) before gathering counter-evidence // set all bits to 1 (uninit) before gathering counter-evidence
state.insert_all(); state.insert_all();
@ -392,28 +394,28 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
}); });
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>, _statement: &mir::Statement<'tcx>,
location: Location, location: Location,
) { ) {
drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| { drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
Self::update_bits(trans, path, s) Self::update_bits(state, path, s)
}); });
// Unlike in `MaybeInitializedPlaces` above, we don't need to change the state when a // Unlike in `MaybeInitializedPlaces` above, we don't need to change the state when a
// mutable borrow occurs. Places cannot become uninitialized through a mutable reference. // mutable borrow occurs. Places cannot become uninitialized through a mutable reference.
} }
fn apply_terminator_effect<'mir>( fn apply_primary_terminator_effect<'mir>(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,
location: Location, location: Location,
) -> TerminatorEdges<'mir, 'tcx> { ) -> TerminatorEdges<'mir, 'tcx> {
drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| { drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
Self::update_bits(trans, path, s) Self::update_bits(state, path, s)
}); });
if self.skip_unreachable_unwind.contains(location.block) { if self.skip_unreachable_unwind.contains(location.block) {
let mir::TerminatorKind::Drop { target, unwind, .. } = terminator.kind else { bug!() }; let mir::TerminatorKind::Drop { target, unwind, .. } = terminator.kind else { bug!() };
@ -426,7 +428,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
fn apply_call_return_effect( fn apply_call_return_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_block: mir::BasicBlock, _block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>, return_places: CallReturnPlaces<'_, 'tcx>,
) { ) {
@ -437,7 +439,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
self.move_data(), self.move_data(),
self.move_data().rev_lookup.find(place.as_ref()), self.move_data().rev_lookup.find(place.as_ref()),
|mpi| { |mpi| {
trans.kill(mpi); state.kill(mpi);
}, },
); );
}); });
@ -466,7 +468,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
}; };
let mut discriminants = enum_def.discriminants(self.tcx); let mut discriminants = enum_def.discriminants(self.tcx);
edge_effects.apply(|trans, edge| { edge_effects.apply(|state, edge| {
let Some(value) = edge.value else { let Some(value) = edge.value else {
return; return;
}; };
@ -484,16 +486,18 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
self.move_data(), self.move_data(),
enum_place, enum_place,
variant, variant,
|mpi| trans.gen_(mpi), |mpi| state.gen_(mpi),
); );
}); });
} }
} }
/// There can be many more `InitIndex` than there are locals in a MIR body.
/// We use a mixed bitset to avoid paying too high a memory footprint.
pub type EverInitializedPlacesDomain = MixedBitSet<InitIndex>;
impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
/// There can be many more `InitIndex` than there are locals in a MIR body. type Domain = EverInitializedPlacesDomain;
/// We use a mixed bitset to avoid paying too high a memory footprint.
type Domain = MixedBitSet<InitIndex>;
const NAME: &'static str = "ever_init"; const NAME: &'static str = "ever_init";
@ -508,10 +512,10 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
} }
} }
#[instrument(skip(self, trans), level = "debug")] #[instrument(skip(self, state), level = "debug")]
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
stmt: &mir::Statement<'tcx>, stmt: &mir::Statement<'tcx>,
location: Location, location: Location,
) { ) {
@ -521,7 +525,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
let rev_lookup = &move_data.rev_lookup; let rev_lookup = &move_data.rev_lookup;
debug!("initializes move_indexes {:?}", init_loc_map[location]); debug!("initializes move_indexes {:?}", init_loc_map[location]);
trans.gen_all(init_loc_map[location].iter().copied()); state.gen_all(init_loc_map[location].iter().copied());
if let mir::StatementKind::StorageDead(local) = stmt.kind { if let mir::StatementKind::StorageDead(local) = stmt.kind {
// End inits for StorageDead, so that an immutable variable can // End inits for StorageDead, so that an immutable variable can
@ -531,15 +535,15 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
"clears the ever initialized status of {:?}", "clears the ever initialized status of {:?}",
init_path_map[move_path_index] init_path_map[move_path_index]
); );
trans.kill_all(init_path_map[move_path_index].iter().copied()); state.kill_all(init_path_map[move_path_index].iter().copied());
} }
} }
} }
#[instrument(skip(self, trans, terminator), level = "debug")] #[instrument(skip(self, state, terminator), level = "debug")]
fn apply_terminator_effect<'mir>( fn apply_primary_terminator_effect<'mir>(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,
location: Location, location: Location,
) -> TerminatorEdges<'mir, 'tcx> { ) -> TerminatorEdges<'mir, 'tcx> {
@ -548,7 +552,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
let init_loc_map = &move_data.init_loc_map; let init_loc_map = &move_data.init_loc_map;
debug!(?term); debug!(?term);
debug!("initializes move_indexes {:?}", init_loc_map[location]); debug!("initializes move_indexes {:?}", init_loc_map[location]);
trans.gen_all( state.gen_all(
init_loc_map[location] init_loc_map[location]
.iter() .iter()
.filter(|init_index| { .filter(|init_index| {
@ -561,7 +565,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
fn apply_call_return_effect( fn apply_call_return_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
block: mir::BasicBlock, block: mir::BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>, _return_places: CallReturnPlaces<'_, 'tcx>,
) { ) {
@ -570,7 +574,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
let call_loc = self.body.terminator_loc(block); let call_loc = self.body.terminator_loc(block);
for init_index in &init_loc_map[call_loc] { for init_index in &init_loc_map[call_loc] {
trans.gen_(*init_index); state.gen_(*init_index);
} }
} }
} }

View file

@ -40,33 +40,33 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
// No variables are live until we observe a use // No variables are live until we observe a use
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
statement: &mir::Statement<'tcx>, statement: &mir::Statement<'tcx>,
location: Location, location: Location,
) { ) {
TransferFunction(trans).visit_statement(statement, location); TransferFunction(state).visit_statement(statement, location);
} }
fn apply_terminator_effect<'mir>( fn apply_primary_terminator_effect<'mir>(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,
location: Location, location: Location,
) -> TerminatorEdges<'mir, 'tcx> { ) -> TerminatorEdges<'mir, 'tcx> {
TransferFunction(trans).visit_terminator(terminator, location); TransferFunction(state).visit_terminator(terminator, location);
terminator.edges() terminator.edges()
} }
fn apply_call_return_effect( fn apply_call_return_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_block: mir::BasicBlock, _block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>, return_places: CallReturnPlaces<'_, 'tcx>,
) { ) {
if let CallReturnPlaces::Yield(resume_place) = return_places { if let CallReturnPlaces::Yield(resume_place) = return_places {
YieldResumeEffect(trans).visit_place( YieldResumeEffect(state).visit_place(
&resume_place, &resume_place,
PlaceContext::MutatingUse(MutatingUseContext::Yield), PlaceContext::MutatingUse(MutatingUseContext::Yield),
Location::START, Location::START,
@ -74,7 +74,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
} else { } else {
return_places.for_each(|place| { return_places.for_each(|place| {
if let Some(local) = place.as_local() { if let Some(local) = place.as_local() {
trans.kill(local); state.kill(local);
} }
}); });
} }
@ -137,10 +137,10 @@ enum DefUse {
} }
impl DefUse { impl DefUse {
fn apply(trans: &mut BitSet<Local>, place: Place<'_>, context: PlaceContext) { fn apply(state: &mut BitSet<Local>, place: Place<'_>, context: PlaceContext) {
match DefUse::for_place(place, context) { match DefUse::for_place(place, context) {
Some(DefUse::Def) => trans.kill(place.local), Some(DefUse::Def) => state.kill(place.local),
Some(DefUse::Use) => trans.gen_(place.local), Some(DefUse::Use) => state.gen_(place.local),
None => {} None => {}
} }
} }
@ -232,9 +232,9 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
// No variables are live until we observe a use // No variables are live until we observe a use
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
statement: &mir::Statement<'tcx>, statement: &mir::Statement<'tcx>,
location: Location, location: Location,
) { ) {
@ -258,34 +258,34 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
}; };
if let Some(destination) = destination { if let Some(destination) = destination {
if !destination.is_indirect() if !destination.is_indirect()
&& !trans.contains(destination.local) && !state.contains(destination.local)
&& !self.always_live.contains(destination.local) && !self.always_live.contains(destination.local)
{ {
// This store is dead // This store is dead
return; return;
} }
} }
TransferFunction(trans).visit_statement(statement, location); TransferFunction(state).visit_statement(statement, location);
} }
fn apply_terminator_effect<'mir>( fn apply_primary_terminator_effect<'mir>(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,
location: Location, location: Location,
) -> TerminatorEdges<'mir, 'tcx> { ) -> TerminatorEdges<'mir, 'tcx> {
TransferFunction(trans).visit_terminator(terminator, location); TransferFunction(state).visit_terminator(terminator, location);
terminator.edges() terminator.edges()
} }
fn apply_call_return_effect( fn apply_call_return_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_block: mir::BasicBlock, _block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>, return_places: CallReturnPlaces<'_, 'tcx>,
) { ) {
if let CallReturnPlaces::Yield(resume_place) = return_places { if let CallReturnPlaces::Yield(resume_place) = return_places {
YieldResumeEffect(trans).visit_place( YieldResumeEffect(state).visit_place(
&resume_place, &resume_place,
PlaceContext::MutatingUse(MutatingUseContext::Yield), PlaceContext::MutatingUse(MutatingUseContext::Yield),
Location::START, Location::START,
@ -293,7 +293,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
} else { } else {
return_places.for_each(|place| { return_places.for_each(|place| {
if let Some(local) = place.as_local() { if let Some(local) = place.as_local() {
trans.remove(local); state.remove(local);
} }
}); });
} }

View file

@ -5,7 +5,8 @@ mod storage_liveness;
pub use self::borrowed_locals::{MaybeBorrowedLocals, borrowed_locals}; pub use self::borrowed_locals::{MaybeBorrowedLocals, borrowed_locals};
pub use self::initialized::{ pub use self::initialized::{
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces, EverInitializedPlaces, EverInitializedPlacesDomain, MaybeInitializedPlaces,
MaybeUninitializedPlaces, MaybeUninitializedPlacesDomain,
}; };
pub use self::liveness::{ pub use self::liveness::{
MaybeLiveLocals, MaybeTransitiveLiveLocals, TransferFunction as LivenessTransferFunction, MaybeLiveLocals, MaybeTransitiveLiveLocals, TransferFunction as LivenessTransferFunction,

View file

@ -44,23 +44,23 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageLive<'a> {
BitSet::new_empty(body.local_decls.len()) BitSet::new_empty(body.local_decls.len())
} }
fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) { fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
on_entry.union(&*self.always_live_locals); state.union(&*self.always_live_locals);
for arg in body.args_iter() { for arg in body.args_iter() {
on_entry.insert(arg); state.insert(arg);
} }
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
stmt: &Statement<'tcx>, stmt: &Statement<'tcx>,
_: Location, _: Location,
) { ) {
match stmt.kind { match stmt.kind {
StatementKind::StorageLive(l) => trans.gen_(l), StatementKind::StorageLive(l) => state.gen_(l),
StatementKind::StorageDead(l) => trans.kill(l), StatementKind::StorageDead(l) => state.kill(l),
_ => (), _ => (),
} }
} }
@ -86,25 +86,25 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageDead<'a> {
BitSet::new_empty(body.local_decls.len()) BitSet::new_empty(body.local_decls.len())
} }
fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) { fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size()); assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size());
// Do not iterate on return place and args, as they are trivially always live. // Do not iterate on return place and args, as they are trivially always live.
for local in body.vars_and_temps_iter() { for local in body.vars_and_temps_iter() {
if !self.always_live_locals.contains(local) { if !self.always_live_locals.contains(local) {
on_entry.insert(local); state.insert(local);
} }
} }
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
stmt: &Statement<'tcx>, stmt: &Statement<'tcx>,
_: Location, _: Location,
) { ) {
match stmt.kind { match stmt.kind {
StatementKind::StorageLive(l) => trans.kill(l), StatementKind::StorageLive(l) => state.kill(l),
StatementKind::StorageDead(l) => trans.gen_(l), StatementKind::StorageDead(l) => state.gen_(l),
_ => (), _ => (),
} }
} }
@ -134,31 +134,31 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
BitSet::new_empty(body.local_decls.len()) BitSet::new_empty(body.local_decls.len())
} }
fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) { fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
// The resume argument is live on function entry (we don't care about // The resume argument is live on function entry (we don't care about
// the `self` argument) // the `self` argument)
for arg in body.args_iter().skip(1) { for arg in body.args_iter().skip(1) {
on_entry.insert(arg); state.insert(arg);
} }
} }
fn apply_before_statement_effect( fn apply_early_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
stmt: &Statement<'tcx>, stmt: &Statement<'tcx>,
loc: Location, loc: Location,
) { ) {
// If a place is borrowed in a statement, it needs storage for that statement. // If a place is borrowed in a statement, it needs storage for that statement.
MaybeBorrowedLocals::transfer_function(trans).visit_statement(stmt, loc); MaybeBorrowedLocals::transfer_function(state).visit_statement(stmt, loc);
match &stmt.kind { match &stmt.kind {
StatementKind::StorageDead(l) => trans.kill(*l), StatementKind::StorageDead(l) => state.kill(*l),
// If a place is assigned to in a statement, it needs storage for that statement. // If a place is assigned to in a statement, it needs storage for that statement.
StatementKind::Assign(box (place, _)) StatementKind::Assign(box (place, _))
| StatementKind::SetDiscriminant { box place, .. } | StatementKind::SetDiscriminant { box place, .. }
| StatementKind::Deinit(box place) => { | StatementKind::Deinit(box place) => {
trans.gen_(place.local); state.gen_(place.local);
} }
// Nothing to do for these. Match exhaustively so this fails to compile when new // Nothing to do for these. Match exhaustively so this fails to compile when new
@ -176,29 +176,29 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
} }
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_: &Statement<'tcx>, _: &Statement<'tcx>,
loc: Location, loc: Location,
) { ) {
// If we move from a place then it only stops needing storage *after* // If we move from a place then it only stops needing storage *after*
// that statement. // that statement.
self.check_for_move(trans, loc); self.check_for_move(state, loc);
} }
fn apply_before_terminator_effect( fn apply_early_terminator_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
terminator: &Terminator<'tcx>, terminator: &Terminator<'tcx>,
loc: Location, loc: Location,
) { ) {
// If a place is borrowed in a terminator, it needs storage for that terminator. // If a place is borrowed in a terminator, it needs storage for that terminator.
MaybeBorrowedLocals::transfer_function(trans).visit_terminator(terminator, loc); MaybeBorrowedLocals::transfer_function(state).visit_terminator(terminator, loc);
match &terminator.kind { match &terminator.kind {
TerminatorKind::Call { destination, .. } => { TerminatorKind::Call { destination, .. } => {
trans.gen_(destination.local); state.gen_(destination.local);
} }
// Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for
@ -213,7 +213,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
InlineAsmOperand::Out { place, .. } InlineAsmOperand::Out { place, .. }
| InlineAsmOperand::InOut { out_place: place, .. } => { | InlineAsmOperand::InOut { out_place: place, .. } => {
if let Some(place) = place { if let Some(place) = place {
trans.gen_(place.local); state.gen_(place.local);
} }
} }
InlineAsmOperand::In { .. } InlineAsmOperand::In { .. }
@ -242,9 +242,9 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
} }
} }
fn apply_terminator_effect<'t>( fn apply_primary_terminator_effect<'t>(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'t Terminator<'tcx>, terminator: &'t Terminator<'tcx>,
loc: Location, loc: Location,
) -> TerminatorEdges<'t, 'tcx> { ) -> TerminatorEdges<'t, 'tcx> {
@ -254,12 +254,12 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
// Since `propagate_call_unwind` doesn't exist, we have to kill the // Since `propagate_call_unwind` doesn't exist, we have to kill the
// destination here, and then gen it again in `call_return_effect`. // destination here, and then gen it again in `call_return_effect`.
TerminatorKind::Call { destination, .. } => { TerminatorKind::Call { destination, .. } => {
trans.kill(destination.local); state.kill(destination.local);
} }
// The same applies to InlineAsm outputs. // The same applies to InlineAsm outputs.
TerminatorKind::InlineAsm { ref operands, .. } => { TerminatorKind::InlineAsm { ref operands, .. } => {
CallReturnPlaces::InlineAsm(operands).for_each(|place| trans.kill(place.local)); CallReturnPlaces::InlineAsm(operands).for_each(|place| state.kill(place.local));
} }
// Nothing to do for these. Match exhaustively so this fails to compile when new // Nothing to do for these. Match exhaustively so this fails to compile when new
@ -279,32 +279,32 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
| TerminatorKind::Unreachable => {} | TerminatorKind::Unreachable => {}
} }
self.check_for_move(trans, loc); self.check_for_move(state, loc);
terminator.edges() terminator.edges()
} }
fn apply_call_return_effect( fn apply_call_return_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_block: BasicBlock, _block: BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>, return_places: CallReturnPlaces<'_, 'tcx>,
) { ) {
return_places.for_each(|place| trans.gen_(place.local)); return_places.for_each(|place| state.gen_(place.local));
} }
} }
impl<'tcx> MaybeRequiresStorage<'_, 'tcx> { impl<'tcx> MaybeRequiresStorage<'_, 'tcx> {
/// Kill locals that are fully moved and have not been borrowed. /// Kill locals that are fully moved and have not been borrowed.
fn check_for_move(&mut self, trans: &mut <Self as Analysis<'tcx>>::Domain, loc: Location) { fn check_for_move(&mut self, state: &mut <Self as Analysis<'tcx>>::Domain, loc: Location) {
let body = self.borrowed_locals.body(); let body = self.borrowed_locals.body();
let mut visitor = MoveVisitor { trans, borrowed_locals: &mut self.borrowed_locals }; let mut visitor = MoveVisitor { state, borrowed_locals: &mut self.borrowed_locals };
visitor.visit_location(body, loc); visitor.visit_location(body, loc);
} }
} }
struct MoveVisitor<'a, 'mir, 'tcx> { struct MoveVisitor<'a, 'mir, 'tcx> {
borrowed_locals: &'a mut BorrowedLocalsResults<'mir, 'tcx>, borrowed_locals: &'a mut BorrowedLocalsResults<'mir, 'tcx>,
trans: &'a mut BitSet<Local>, state: &'a mut BitSet<Local>,
} }
impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx> { impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx> {
@ -312,7 +312,7 @@ impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx> {
if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context { if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
self.borrowed_locals.seek_before_primary_effect(loc); self.borrowed_locals.seek_before_primary_effect(loc);
if !self.borrowed_locals.get().contains(local) { if !self.borrowed_locals.get().contains(local) {
self.trans.kill(local); self.state.kill(local);
} }
} }
} }

View file

@ -18,7 +18,7 @@ pub use self::drop_flag_effects::{
move_path_children_matching, on_all_children_bits, on_lookup_result_bits, move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
}; };
pub use self::framework::{ pub use self::framework::{
Analysis, Backward, Direction, EntrySets, Forward, GenKill, JoinSemiLattice, MaybeReachable, Analysis, Backward, Direction, EntryStates, Forward, GenKill, JoinSemiLattice, MaybeReachable,
Results, ResultsCursor, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice, Results, ResultsCursor, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
visit_results, visit_results,
}; };

View file

@ -125,7 +125,7 @@ where
A: Analysis<'tcx, Domain = BitSet<N>>, A: Analysis<'tcx, Domain = BitSet<N>>,
N: Idx, N: Idx,
{ {
fn visit_statement_after_primary_effect( fn visit_after_primary_statement_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, A>, _results: &mut Results<'tcx, A>,
state: &A::Domain, state: &A::Domain,
@ -139,7 +139,7 @@ where
}); });
} }
fn visit_terminator_after_primary_effect( fn visit_after_primary_terminator_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, A>, _results: &mut Results<'tcx, A>,
state: &A::Domain, state: &A::Domain,

View file

@ -1,6 +1,5 @@
use rustc_ast::MetaItem; use rustc_ast::MetaItem;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::{self, Body, Local, Location}; use rustc_middle::mir::{self, Body, Local, Location};
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span; use rustc_span::Span;
@ -254,7 +253,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals {
&self, &self,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
place: mir::Place<'tcx>, place: mir::Place<'tcx>,
state: &BitSet<Local>, state: &Self::Domain,
call: PeekCall, call: PeekCall,
) { ) {
info!(?place, "peek_at"); info!(?place, "peek_at");

View file

@ -67,7 +67,7 @@ impl<V: Clone> Clone for StateData<V> {
} }
} }
impl<V: JoinSemiLattice + Clone + HasBottom> JoinSemiLattice for StateData<V> { impl<V: JoinSemiLattice + Clone> JoinSemiLattice for StateData<V> {
fn join(&mut self, other: &Self) -> bool { fn join(&mut self, other: &Self) -> bool {
let mut changed = false; let mut changed = false;
#[allow(rustc::potential_query_instability)] #[allow(rustc::potential_query_instability)]
@ -342,7 +342,7 @@ impl<V: Clone + HasBottom> State<V> {
} }
} }
impl<V: JoinSemiLattice + Clone + HasBottom> JoinSemiLattice for State<V> { impl<V: JoinSemiLattice + Clone> JoinSemiLattice for State<V> {
fn join(&mut self, other: &Self) -> bool { fn join(&mut self, other: &Self) -> bool {
match (&mut *self, other) { match (&mut *self, other) {
(_, State::Unreachable) => false, (_, State::Unreachable) => false,

View file

@ -878,7 +878,7 @@ struct StorageConflictVisitor<'a, 'tcx> {
impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>> impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>>
for StorageConflictVisitor<'a, 'tcx> for StorageConflictVisitor<'a, 'tcx>
{ {
fn visit_statement_before_primary_effect( fn visit_after_early_statement_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>, _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
state: &BitSet<Local>, state: &BitSet<Local>,
@ -888,7 +888,7 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>>
self.apply_state(state, loc); self.apply_state(state, loc);
} }
fn visit_terminator_before_primary_effect( fn visit_after_early_terminator_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>, _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
state: &BitSet<Local>, state: &BitSet<Local>,

View file

@ -106,7 +106,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> {
} }
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
statement: &Statement<'tcx>, statement: &Statement<'tcx>,
@ -117,7 +117,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> {
} }
} }
fn apply_terminator_effect<'mir>( fn apply_primary_terminator_effect<'mir>(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir Terminator<'tcx>, terminator: &'mir Terminator<'tcx>,
@ -224,7 +224,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
} }
/// The effect of a successful function call return should not be /// The effect of a successful function call return should not be
/// applied here, see [`Analysis::apply_terminator_effect`]. /// applied here, see [`Analysis::apply_primary_terminator_effect`].
fn handle_terminator<'mir>( fn handle_terminator<'mir>(
&self, &self,
terminator: &'mir Terminator<'tcx>, terminator: &'mir Terminator<'tcx>,
@ -954,7 +954,7 @@ fn try_write_constant<'tcx>(
impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> { impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> {
#[instrument(level = "trace", skip(self, results, statement))] #[instrument(level = "trace", skip(self, results, statement))]
fn visit_statement_before_primary_effect( fn visit_after_early_statement_effect(
&mut self, &mut self,
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
state: &State<FlatSet<Scalar>>, state: &State<FlatSet<Scalar>>,
@ -976,7 +976,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collect
} }
#[instrument(level = "trace", skip(self, results, statement))] #[instrument(level = "trace", skip(self, results, statement))]
fn visit_statement_after_primary_effect( fn visit_after_primary_statement_effect(
&mut self, &mut self,
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
state: &State<FlatSet<Scalar>>, state: &State<FlatSet<Scalar>>,
@ -1001,7 +1001,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collect
} }
} }
fn visit_terminator_before_primary_effect( fn visit_after_early_terminator_effect(
&mut self, &mut self,
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
state: &State<FlatSet<Scalar>>, state: &State<FlatSet<Scalar>>,

View file

@ -127,7 +127,7 @@ impl InitializationData<'_, '_> {
self.uninits.seek_before_primary_effect(loc); self.uninits.seek_before_primary_effect(loc);
} }
fn maybe_live_dead(&self, path: MovePathIndex) -> (bool, bool) { fn maybe_init_uninit(&self, path: MovePathIndex) -> (bool, bool) {
(self.inits.get().contains(path), self.uninits.get().contains(path)) (self.inits.get().contains(path), self.uninits.get().contains(path))
} }
} }
@ -153,23 +153,23 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for ElaborateDropsCtxt<'a, 'tcx> {
#[instrument(level = "debug", skip(self), ret)] #[instrument(level = "debug", skip(self), ret)]
fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle { fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle {
let ((maybe_live, maybe_dead), multipart) = match mode { let ((maybe_init, maybe_uninit), multipart) = match mode {
DropFlagMode::Shallow => (self.init_data.maybe_live_dead(path), false), DropFlagMode::Shallow => (self.init_data.maybe_init_uninit(path), false),
DropFlagMode::Deep => { DropFlagMode::Deep => {
let mut some_live = false; let mut some_maybe_init = false;
let mut some_dead = false; let mut some_maybe_uninit = false;
let mut children_count = 0; let mut children_count = 0;
on_all_children_bits(self.move_data(), path, |child| { on_all_children_bits(self.move_data(), path, |child| {
let (live, dead) = self.init_data.maybe_live_dead(child); let (maybe_init, maybe_uninit) = self.init_data.maybe_init_uninit(child);
debug!("elaborate_drop: state({:?}) = {:?}", child, (live, dead)); debug!("elaborate_drop: state({:?}) = {:?}", child, (maybe_init, maybe_uninit));
some_live |= live; some_maybe_init |= maybe_init;
some_dead |= dead; some_maybe_uninit |= maybe_uninit;
children_count += 1; children_count += 1;
}); });
((some_live, some_dead), children_count != 1) ((some_maybe_init, some_maybe_uninit), children_count != 1)
} }
}; };
match (maybe_live, maybe_dead, multipart) { match (maybe_init, maybe_uninit, multipart) {
(false, _, _) => DropStyle::Dead, (false, _, _) => DropStyle::Dead,
(true, false, _) => DropStyle::Static, (true, false, _) => DropStyle::Static,
(true, true, false) => DropStyle::Conditional, (true, true, false) => DropStyle::Conditional,
@ -283,15 +283,15 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
LookupResult::Exact(path) => { LookupResult::Exact(path) => {
self.init_data.seek_before(self.body.terminator_loc(bb)); self.init_data.seek_before(self.body.terminator_loc(bb));
on_all_children_bits(self.move_data(), path, |child| { on_all_children_bits(self.move_data(), path, |child| {
let (maybe_live, maybe_dead) = self.init_data.maybe_live_dead(child); let (maybe_init, maybe_uninit) = self.init_data.maybe_init_uninit(child);
debug!( debug!(
"collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", "collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}",
child, child,
place, place,
path, path,
(maybe_live, maybe_dead) (maybe_init, maybe_uninit)
); );
if maybe_live && maybe_dead { if maybe_init && maybe_uninit {
self.create_drop_flag(child, terminator.source_info.span) self.create_drop_flag(child, terminator.source_info.span)
} }
}); });
@ -303,8 +303,8 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
} }
self.init_data.seek_before(self.body.terminator_loc(bb)); self.init_data.seek_before(self.body.terminator_loc(bb));
let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent); let (_maybe_init, maybe_uninit) = self.init_data.maybe_init_uninit(parent);
if maybe_dead { if maybe_uninit {
self.tcx.dcx().span_delayed_bug( self.tcx.dcx().span_delayed_bug(
terminator.source_info.span, terminator.source_info.span,
format!( format!(