1 //! A less precise version of `MaybeInitializedPlaces` whose domain is entire locals.
3 //! A local will be maybe initialized if *any* projections of that local might be initialized.
5 use crate::{CallReturnPlaces, GenKill};
7 use rustc_index::bit_set::BitSet;
8 use rustc_middle::mir::visit::{PlaceContext, Visitor};
9 use rustc_middle::mir::{self, BasicBlock, Local, Location};
11 pub struct MaybeInitializedLocals;
13 impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeInitializedLocals {
14 type Domain = BitSet<Local>;
16 const NAME: &'static str = "maybe_init_locals";
18 fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
20 BitSet::new_empty(body.local_decls.len())
23 fn initialize_start_block(&self, body: &mir::Body<'tcx>, entry_set: &mut Self::Domain) {
24 // Function arguments are initialized to begin with.
25 for arg in body.args_iter() {
26 entry_set.insert(arg);
31 impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeInitializedLocals {
36 trans: &mut impl GenKill<Self::Idx>,
37 statement: &mir::Statement<'tcx>,
40 TransferFunction { trans }.visit_statement(statement, loc)
45 trans: &mut impl GenKill<Self::Idx>,
46 terminator: &mir::Terminator<'tcx>,
49 TransferFunction { trans }.visit_terminator(terminator, loc)
52 fn call_return_effect(
54 trans: &mut impl GenKill<Self::Idx>,
56 return_places: CallReturnPlaces<'_, 'tcx>,
58 return_places.for_each(|place| trans.gen(place.local));
61 /// See `Analysis::apply_yield_resume_effect`.
62 fn yield_resume_effect(
64 trans: &mut impl GenKill<Self::Idx>,
65 _resume_block: BasicBlock,
66 resume_place: mir::Place<'tcx>,
68 trans.gen(resume_place.local)
72 struct TransferFunction<'a, T> {
76 impl<T> Visitor<'_> for TransferFunction<'_, T>
80 fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
81 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, NonUseContext};
83 // These are handled specially in `call_return_effect` and `yield_resume_effect`.
84 PlaceContext::MutatingUse(
85 MutatingUseContext::Call
86 | MutatingUseContext::AsmOutput
87 | MutatingUseContext::Yield,
90 // Otherwise, when a place is mutated, we must consider it possibly initialized.
91 PlaceContext::MutatingUse(_) => self.trans.gen(local),
93 // If the local is moved out of, or if it gets marked `StorageDead`, consider it no
94 // longer initialized.
95 PlaceContext::NonUse(NonUseContext::StorageDead)
96 | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => self.trans.kill(local),
98 // All other uses do not affect this analysis.
100 NonUseContext::StorageLive
101 | NonUseContext::AscribeUserTy
102 | NonUseContext::VarDebugInfo,
104 | PlaceContext::NonMutatingUse(
105 NonMutatingUseContext::Inspect
106 | NonMutatingUseContext::Copy
107 | NonMutatingUseContext::SharedBorrow
108 | NonMutatingUseContext::ShallowBorrow
109 | NonMutatingUseContext::UniqueBorrow
110 | NonMutatingUseContext::AddressOf
111 | NonMutatingUseContext::Projection,