Update dataflow analyses to use new interface

This commit is contained in:
Dylan MacKenzie 2020-08-28 13:26:25 -07:00
parent 3233fb18a8
commit b19b8ea611
9 changed files with 106 additions and 143 deletions

View File

@ -82,15 +82,15 @@ impl<K> AnalysisDomain<'tcx> for MaybeBorrowedLocals<K>
where
K: BorrowAnalysisKind<'tcx>,
{
type Idx = Local;
type Domain = BitSet<Local>;
const NAME: &'static str = K::ANALYSIS_NAME;
fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
body.local_decls().len()
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
// bottom = unborrowed
BitSet::new_empty(body.local_decls().len())
}
fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet<Self::Idx>) {
fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
// No locals are aliased on function entry
}
}
@ -99,6 +99,8 @@ impl<K> GenKillAnalysis<'tcx> for MaybeBorrowedLocals<K>
where
K: BorrowAnalysisKind<'tcx>,
{
type Idx = Local;
fn statement_effect(
&self,
trans: &mut impl GenKill<Self::Idx>,
@ -128,11 +130,6 @@ where
}
}
impl<K> BottomValue for MaybeBorrowedLocals<K> {
// bottom = unborrowed
const BOTTOM_VALUE: bool = false;
}
/// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`.
struct TransferFunction<'a, T, K> {
trans: &'a mut T,

View File

@ -8,9 +8,9 @@ use rustc_index::bit_set::BitSet;
use crate::borrow_check::{
places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid,
};
use crate::dataflow::BottomValue;
use crate::dataflow::{self, GenKill};
use crate::dataflow::{self, fmt::DebugWithContext, GenKill};
use std::fmt;
use std::rc::Rc;
rustc_index::newtype_index! {
@ -227,25 +227,24 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
}
impl<'tcx> dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> {
type Idx = BorrowIndex;
type Domain = BitSet<BorrowIndex>;
const NAME: &'static str = "borrows";
fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
self.borrow_set.len() * 2
fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
// bottom = nothing is reserved or activated yet;
BitSet::new_empty(self.borrow_set.len() * 2)
}
fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet<Self::Idx>) {
fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
// no borrows of code region_scopes have been taken prior to
// function execution, so this method has no effect.
}
fn pretty_print_idx(&self, w: &mut impl std::io::Write, idx: Self::Idx) -> std::io::Result<()> {
write!(w, "{:?}", self.location(idx))
}
}
impl<'tcx> dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
type Idx = BorrowIndex;
fn before_statement_effect(
&self,
trans: &mut impl GenKill<Self::Idx>,
@ -344,7 +343,8 @@ impl<'tcx> dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
}
}
impl<'a, 'tcx> BottomValue for Borrows<'a, 'tcx> {
/// bottom = nothing is reserved or activated yet;
const BOTTOM_VALUE: bool = false;
impl DebugWithContext<Borrows<'_, '_>> for BorrowIndex {
fn fmt_with(&self, ctxt: &Borrows<'_, '_>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", ctxt.location(*self))
}
}

View File

@ -2,7 +2,7 @@
//!
//! A local will be maybe initialized if *any* projections of that local might be initialized.
use crate::dataflow::{self, BottomValue, GenKill};
use crate::dataflow::{self, GenKill};
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
@ -10,21 +10,17 @@ use rustc_middle::mir::{self, BasicBlock, Local, Location};
pub struct MaybeInitializedLocals;
impl BottomValue for MaybeInitializedLocals {
/// bottom = uninit
const BOTTOM_VALUE: bool = false;
}
impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals {
type Idx = Local;
type Domain = BitSet<Local>;
const NAME: &'static str = "maybe_init_locals";
fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
body.local_decls.len()
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
// bottom = uninit
BitSet::new_empty(body.local_decls.len())
}
fn initialize_start_block(&self, body: &mir::Body<'tcx>, entry_set: &mut BitSet<Self::Idx>) {
fn initialize_start_block(&self, body: &mir::Body<'tcx>, entry_set: &mut Self::Domain) {
// Function arguments are initialized to begin with.
for arg in body.args_iter() {
entry_set.insert(arg);
@ -33,6 +29,8 @@ impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals {
}
impl dataflow::GenKillAnalysis<'tcx> for MaybeInitializedLocals {
type Idx = Local;
fn statement_effect(
&self,
trans: &mut impl GenKill<Self::Idx>,

View File

@ -2,7 +2,7 @@ use rustc_index::bit_set::BitSet;
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{self, Local, Location};
use crate::dataflow::{AnalysisDomain, Backward, BottomValue, GenKill, GenKillAnalysis};
use crate::dataflow::{AnalysisDomain, Backward, GenKill, GenKillAnalysis};
/// A [live-variable dataflow analysis][liveness].
///
@ -22,27 +22,25 @@ impl MaybeLiveLocals {
}
}
impl BottomValue for MaybeLiveLocals {
// bottom = not live
const BOTTOM_VALUE: bool = false;
}
impl AnalysisDomain<'tcx> for MaybeLiveLocals {
type Idx = Local;
type Domain = BitSet<Local>;
type Direction = Backward;
const NAME: &'static str = "liveness";
fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
body.local_decls.len()
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
// bottom = not live
BitSet::new_empty(body.local_decls.len())
}
fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet<Self::Idx>) {
fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
// No variables are live until we observe a use
}
}
impl GenKillAnalysis<'tcx> for MaybeLiveLocals {
type Idx = Local;
fn statement_effect(
&self,
trans: &mut impl GenKill<Self::Idx>,

View File

@ -13,7 +13,7 @@ use super::MoveDataParamEnv;
use crate::util::elaborate_drops::DropFlagState;
use super::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex};
use super::{AnalysisDomain, BottomValue, GenKill, GenKillAnalysis};
use super::{lattice, AnalysisDomain, GenKill, GenKillAnalysis};
use super::drop_flag_effects_for_function_entry;
use super::drop_flag_effects_for_location;
@ -290,27 +290,25 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
}
impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
type Idx = MovePathIndex;
type Domain = BitSet<MovePathIndex>;
const NAME: &'static str = "maybe_init";
fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
self.move_data().move_paths.len()
fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
// bottom = uninitialized
BitSet::new_empty(self.move_data().move_paths.len())
}
fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| {
assert!(s == DropFlagState::Present);
state.insert(path);
});
}
fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> {
write!(w, "{}", self.move_data().move_paths[mpi])
}
}
impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
type Idx = MovePathIndex;
fn statement_effect(
&self,
trans: &mut impl GenKill<Self::Idx>,
@ -376,18 +374,18 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
}
impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
type Idx = MovePathIndex;
type Domain = BitSet<MovePathIndex>;
const NAME: &'static str = "maybe_uninit";
fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
self.move_data().move_paths.len()
fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
// bottom = initialized (start_block_effect counters this at outset)
BitSet::new_empty(self.move_data().move_paths.len())
}
// sets on_entry bits for Arg places
fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
// set all bits to 1 (uninit) before gathering counterevidence
assert!(self.bits_per_block(body) == state.domain_size());
state.insert_all();
drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| {
@ -395,13 +393,11 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
state.remove(path);
});
}
fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> {
write!(w, "{}", self.move_data().move_paths[mpi])
}
}
impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
type Idx = MovePathIndex;
fn statement_effect(
&self,
trans: &mut impl GenKill<Self::Idx>,
@ -471,30 +467,30 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
}
impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
type Idx = MovePathIndex;
/// Use set intersection as the join operator.
type Domain = lattice::Dual<BitSet<MovePathIndex>>;
const NAME: &'static str = "definite_init";
fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
self.move_data().move_paths.len()
fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
// bottom = initialized (start_block_effect counters this at outset)
lattice::Dual(BitSet::new_filled(self.move_data().move_paths.len()))
}
// sets on_entry bits for Arg places
fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
state.clear();
fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
state.0.clear();
drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| {
assert!(s == DropFlagState::Present);
state.insert(path);
state.0.insert(path);
});
}
fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> {
write!(w, "{}", self.move_data().move_paths[mpi])
}
}
impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
type Idx = MovePathIndex;
fn statement_effect(
&self,
trans: &mut impl GenKill<Self::Idx>,
@ -540,15 +536,16 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
}
impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> {
type Idx = InitIndex;
type Domain = BitSet<InitIndex>;
const NAME: &'static str = "ever_init";
fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
self.move_data().inits.len()
fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
// bottom = no initialized variables by default
BitSet::new_empty(self.move_data().inits.len())
}
fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
for arg_init in 0..body.arg_count {
state.insert(InitIndex::new(arg_init));
}
@ -556,6 +553,8 @@ impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> {
}
impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
type Idx = InitIndex;
fn statement_effect(
&self,
trans: &mut impl GenKill<Self::Idx>,
@ -625,23 +624,3 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
}
}
}
impl<'a, 'tcx> BottomValue for MaybeInitializedPlaces<'a, 'tcx> {
/// bottom = uninitialized
const BOTTOM_VALUE: bool = false;
}
impl<'a, 'tcx> BottomValue for MaybeUninitializedPlaces<'a, 'tcx> {
/// bottom = initialized (start_block_effect counters this at outset)
const BOTTOM_VALUE: bool = false;
}
impl<'a, 'tcx> BottomValue for DefinitelyInitializedPlaces<'a, 'tcx> {
/// bottom = initialized (start_block_effect counters this at outset)
const BOTTOM_VALUE: bool = true;
}
impl<'a, 'tcx> BottomValue for EverInitializedPlaces<'a, 'tcx> {
/// bottom = no initialized variables by default
const BOTTOM_VALUE: bool = false;
}

View File

@ -1,6 +1,5 @@
pub use super::*;
use crate::dataflow::BottomValue;
use crate::dataflow::{self, GenKill, Results, ResultsRefCursor};
use crate::util::storage::AlwaysLiveLocals;
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
@ -19,15 +18,16 @@ impl MaybeStorageLive {
}
impl dataflow::AnalysisDomain<'tcx> for MaybeStorageLive {
type Idx = Local;
type Domain = BitSet<Local>;
const NAME: &'static str = "maybe_storage_live";
fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
body.local_decls.len()
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
// bottom = dead
BitSet::new_empty(body.local_decls.len())
}
fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut BitSet<Self::Idx>) {
fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut Self::Domain) {
assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size());
for local in self.always_live_locals.iter() {
on_entry.insert(local);
@ -40,6 +40,8 @@ impl dataflow::AnalysisDomain<'tcx> for MaybeStorageLive {
}
impl dataflow::GenKillAnalysis<'tcx> for MaybeStorageLive {
type Idx = Local;
fn statement_effect(
&self,
trans: &mut impl GenKill<Self::Idx>,
@ -74,11 +76,6 @@ impl dataflow::GenKillAnalysis<'tcx> for MaybeStorageLive {
}
}
impl BottomValue for MaybeStorageLive {
/// bottom = dead
const BOTTOM_VALUE: bool = false;
}
type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>;
/// Dataflow analysis that determines whether each local requires storage at a
@ -101,15 +98,16 @@ impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
}
impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
type Idx = Local;
type Domain = BitSet<Local>;
const NAME: &'static str = "requires_storage";
fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
body.local_decls.len()
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
// bottom = dead
BitSet::new_empty(body.local_decls.len())
}
fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut BitSet<Self::Idx>) {
fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut Self::Domain) {
// The resume argument is live on function entry (we don't care about
// the `self` argument)
for arg in body.args_iter().skip(1) {
@ -119,6 +117,8 @@ impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, '
}
impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
type Idx = Local;
fn before_statement_effect(
&self,
trans: &mut impl GenKill<Self::Idx>,
@ -285,11 +285,6 @@ impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
}
}
impl<'mir, 'tcx> BottomValue for MaybeRequiresStorage<'mir, 'tcx> {
/// bottom = dead
const BOTTOM_VALUE: bool = false;
}
struct MoveVisitor<'a, 'mir, 'tcx, T> {
borrowed_locals: &'a RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
trans: &'a mut T,

View File

@ -165,23 +165,19 @@ where
}
}
impl<Q> dataflow::BottomValue for FlowSensitiveAnalysis<'_, '_, '_, Q> {
const BOTTOM_VALUE: bool = false;
}
impl<Q> dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
where
Q: Qualif,
{
type Idx = Local;
type Domain = BitSet<Local>;
const NAME: &'static str = Q::ANALYSIS_NAME;
fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
body.local_decls.len()
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
BitSet::new_empty(body.local_decls.len())
}
fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut Self::Domain) {
self.transfer_function(state).initialize_state();
}
}
@ -192,7 +188,7 @@ where
{
fn apply_statement_effect(
&self,
state: &mut BitSet<Self::Idx>,
state: &mut Self::Domain,
statement: &mir::Statement<'tcx>,
location: Location,
) {
@ -201,7 +197,7 @@ where
fn apply_terminator_effect(
&self,
state: &mut BitSet<Self::Idx>,
state: &mut Self::Domain,
terminator: &mir::Terminator<'tcx>,
location: Location,
) {
@ -210,7 +206,7 @@ where
fn apply_call_return_effect(
&self,
state: &mut BitSet<Self::Idx>,
state: &mut Self::Domain,
block: BasicBlock,
func: &mir::Operand<'tcx>,
args: &[mir::Operand<'tcx>],

View File

@ -1,4 +1,6 @@
use rustc_ast as ast;
use std::borrow::Borrow;
use rustc_ast::ast;
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
@ -16,7 +18,7 @@ use crate::dataflow::impls::{
use crate::dataflow::move_paths::{HasMoveData, MoveData};
use crate::dataflow::move_paths::{LookupResult, MovePathIndex};
use crate::dataflow::MoveDataParamEnv;
use crate::dataflow::{Analysis, Results, ResultsCursor};
use crate::dataflow::{Analysis, JoinSemiLattice, Results, ResultsCursor};
pub struct SanityCheck;
@ -248,25 +250,26 @@ pub trait RustcPeekAt<'tcx>: Analysis<'tcx> {
&self,
tcx: TyCtxt<'tcx>,
place: mir::Place<'tcx>,
flow_state: &BitSet<Self::Idx>,
flow_state: &Self::Domain,
call: PeekCall,
);
}
impl<'tcx, A> RustcPeekAt<'tcx> for A
impl<'tcx, A, D> RustcPeekAt<'tcx> for A
where
A: Analysis<'tcx, Idx = MovePathIndex> + HasMoveData<'tcx>,
A: Analysis<'tcx, Domain = D> + HasMoveData<'tcx>,
D: JoinSemiLattice + Clone + Borrow<BitSet<MovePathIndex>>,
{
fn peek_at(
&self,
tcx: TyCtxt<'tcx>,
place: mir::Place<'tcx>,
flow_state: &BitSet<Self::Idx>,
flow_state: &Self::Domain,
call: PeekCall,
) {
match self.move_data().rev_lookup.find(place.as_ref()) {
LookupResult::Exact(peek_mpi) => {
let bit_state = flow_state.contains(peek_mpi);
let bit_state = flow_state.borrow().contains(peek_mpi);
debug!("rustc_peek({:?} = &{:?}) bit_state: {}", call.arg, place, bit_state);
if !bit_state {
tcx.sess.span_err(call.span, "rustc_peek: bit not set");

View File

@ -14,7 +14,6 @@ use rustc_middle::mir::{
visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _},
};
use rustc_middle::ty::{self, fold::TypeVisitor, Ty};
use rustc_mir::dataflow::BottomValue;
use rustc_mir::dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::{BytePos, Span};
@ -411,14 +410,15 @@ impl<'tcx> mir::visit::Visitor<'tcx> for LocalUseVisitor {
struct MaybeStorageLive;
impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive {
type Idx = mir::Local;
type Domain = BitSet<mir::Local>;
const NAME: &'static str = "maybe_storage_live";
fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
body.local_decls.len()
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
// bottom = dead
BitSet::new_empty(body.local_decls.len())
}
fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
for arg in body.args_iter() {
state.insert(arg);
}
@ -426,6 +426,8 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive {
}
impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
type Idx = mir::Local;
fn statement_effect(&self, trans: &mut impl GenKill<Self::Idx>, stmt: &mir::Statement<'tcx>, _: mir::Location) {
match stmt.kind {
mir::StatementKind::StorageLive(l) => trans.gen(l),
@ -454,11 +456,6 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
}
}
impl BottomValue for MaybeStorageLive {
/// bottom = dead
const BOTTOM_VALUE: bool = false;
}
/// Collects the possible borrowers of each local.
/// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
/// possible borrowers of `a`.