From daea09cf91fdf50c03500784d0f1612db42afd2b Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 4 May 2020 14:03:59 -0700 Subject: [PATCH] Add `MaybeInitializedLocals` dataflow analysis --- .../dataflow/impls/init_locals.rs | 115 ++++++++++++++++++ src/librustc_mir/dataflow/impls/mod.rs | 2 + 2 files changed, 117 insertions(+) create mode 100644 src/librustc_mir/dataflow/impls/init_locals.rs diff --git a/src/librustc_mir/dataflow/impls/init_locals.rs b/src/librustc_mir/dataflow/impls/init_locals.rs new file mode 100644 index 00000000000..01cb794a2e0 --- /dev/null +++ b/src/librustc_mir/dataflow/impls/init_locals.rs @@ -0,0 +1,115 @@ +//! A less precise version of `MaybeInitializedPlaces` whose domain is entire locals. +//! +//! A local will be maybe initialized if *any* projections of that local might be initialized. + +use crate::dataflow::{self, BottomValue, GenKill}; + +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::visit::{PlaceContext, Visitor}; +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; + + const NAME: &'static str = "maybe_init_locals"; + + fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { + body.local_decls.len() + } + + fn initialize_start_block(&self, body: &mir::Body<'tcx>, entry_set: &mut BitSet) { + // Function arguments are initialized to begin with. + for arg in body.args_iter() { + entry_set.insert(arg); + } + } +} + +impl dataflow::GenKillAnalysis<'tcx> for MaybeInitializedLocals { + fn statement_effect( + &self, + trans: &mut impl GenKill, + statement: &mir::Statement<'tcx>, + loc: Location, + ) { + TransferFunction { trans }.visit_statement(statement, loc) + } + + fn terminator_effect( + &self, + trans: &mut impl GenKill, + terminator: &mir::Terminator<'tcx>, + loc: Location, + ) { + TransferFunction { trans }.visit_terminator(terminator, loc) + } + + fn call_return_effect( + &self, + trans: &mut impl GenKill, + _block: BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + return_place: mir::Place<'tcx>, + ) { + trans.gen(return_place.local) + } + + /// See `Analysis::apply_yield_resume_effect`. + fn yield_resume_effect( + &self, + trans: &mut impl GenKill, + _resume_block: BasicBlock, + resume_place: mir::Place<'tcx>, + ) { + trans.gen(resume_place.local) + } +} + +struct TransferFunction<'a, T> { + trans: &'a mut T, +} + +impl Visitor<'tcx> for TransferFunction<'a, T> +where + T: GenKill, +{ + fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { + use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, NonUseContext}; + match context { + // These are handled specially in `call_return_effect` and `yield_resume_effect`. + PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => {} + + // Otherwise, when a place is mutated, we must consider it possibly initialized. + PlaceContext::MutatingUse(_) => self.trans.gen(local), + + // If the local is moved out of, or if it gets marked `StorageDead`, consider it no + // longer initialized. + PlaceContext::NonUse(NonUseContext::StorageDead) + | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => self.trans.kill(local), + + // All other uses do not affect this analysis. + PlaceContext::NonUse( + NonUseContext::StorageLive + | NonUseContext::AscribeUserTy + | NonUseContext::VarDebugInfo, + ) + | PlaceContext::NonMutatingUse( + NonMutatingUseContext::Inspect + | NonMutatingUseContext::Copy + | NonMutatingUseContext::SharedBorrow + | NonMutatingUseContext::ShallowBorrow + | NonMutatingUseContext::UniqueBorrow + | NonMutatingUseContext::AddressOf + | NonMutatingUseContext::Projection, + ) => {} + } + } +} diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index e199a174efb..d5def038912 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -22,11 +22,13 @@ use crate::dataflow::drop_flag_effects; mod borrowed_locals; pub(super) mod borrows; +mod init_locals; mod liveness; mod storage_liveness; pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals}; pub use self::borrows::Borrows; +pub use self::init_locals::MaybeInitializedLocals; pub use self::liveness::MaybeLiveLocals; pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive};