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 // FIXME: Using `visit_local` here is a bug. For example, on `move _5.field` we mark `_5` as
81 // deinitialized, although clearly it is only partially deinitialized. This analysis is not
82 // actually used anywhere at the moment, so this is not critical, but this does need to be fixed
83 // before it starts being used again.
84 fn visit_local(&mut self, local
: Local
, context
: PlaceContext
, _
: Location
) {
85 use rustc_middle
::mir
::visit
::{MutatingUseContext, NonMutatingUseContext, NonUseContext}
;
87 // These are handled specially in `call_return_effect` and `yield_resume_effect`.
88 PlaceContext
::MutatingUse(
89 MutatingUseContext
::Call
90 | MutatingUseContext
::AsmOutput
91 | MutatingUseContext
::Yield
,
94 // If it's deinitialized, it's no longer init
95 PlaceContext
::MutatingUse(MutatingUseContext
::Deinit
) => self.trans
.kill(local
),
97 // Otherwise, when a place is mutated, we must consider it possibly initialized.
98 PlaceContext
::MutatingUse(_
) => self.trans
.gen(local
),
100 // If the local is moved out of, or if it gets marked `StorageDead`, consider it no
101 // longer initialized.
102 PlaceContext
::NonUse(NonUseContext
::StorageDead
)
103 | PlaceContext
::NonMutatingUse(NonMutatingUseContext
::Move
) => self.trans
.kill(local
),
105 // All other uses do not affect this analysis.
106 PlaceContext
::NonUse(
107 NonUseContext
::StorageLive
108 | NonUseContext
::AscribeUserTy
109 | NonUseContext
::VarDebugInfo
,
111 | PlaceContext
::NonMutatingUse(
112 NonMutatingUseContext
::Inspect
113 | NonMutatingUseContext
::Copy
114 | NonMutatingUseContext
::SharedBorrow
115 | NonMutatingUseContext
::ShallowBorrow
116 | NonMutatingUseContext
::UniqueBorrow
117 | NonMutatingUseContext
::AddressOf
118 | NonMutatingUseContext
::Projection
,