]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir_dataflow/src/impls/init_locals.rs
Rollup merge of #102227 - devnexen:solarish_get_path, r=m-ou-se
[rust.git] / compiler / rustc_mir_dataflow / src / impls / init_locals.rs
1 //! A less precise version of `MaybeInitializedPlaces` whose domain is entire locals.
2 //!
3 //! A local will be maybe initialized if *any* projections of that local might be initialized.
4
5 use crate::{CallReturnPlaces, GenKill};
6
7 use rustc_index::bit_set::BitSet;
8 use rustc_middle::mir::visit::{PlaceContext, Visitor};
9 use rustc_middle::mir::{self, BasicBlock, Local, Location};
10
11 pub struct MaybeInitializedLocals;
12
13 impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeInitializedLocals {
14     type Domain = BitSet<Local>;
15
16     const NAME: &'static str = "maybe_init_locals";
17
18     fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
19         // bottom = uninit
20         BitSet::new_empty(body.local_decls.len())
21     }
22
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);
27         }
28     }
29 }
30
31 impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeInitializedLocals {
32     type Idx = Local;
33
34     fn statement_effect(
35         &self,
36         trans: &mut impl GenKill<Self::Idx>,
37         statement: &mir::Statement<'tcx>,
38         loc: Location,
39     ) {
40         TransferFunction { trans }.visit_statement(statement, loc)
41     }
42
43     fn terminator_effect(
44         &self,
45         trans: &mut impl GenKill<Self::Idx>,
46         terminator: &mir::Terminator<'tcx>,
47         loc: Location,
48     ) {
49         TransferFunction { trans }.visit_terminator(terminator, loc)
50     }
51
52     fn call_return_effect(
53         &self,
54         trans: &mut impl GenKill<Self::Idx>,
55         _block: BasicBlock,
56         return_places: CallReturnPlaces<'_, 'tcx>,
57     ) {
58         return_places.for_each(|place| trans.gen(place.local));
59     }
60
61     /// See `Analysis::apply_yield_resume_effect`.
62     fn yield_resume_effect(
63         &self,
64         trans: &mut impl GenKill<Self::Idx>,
65         _resume_block: BasicBlock,
66         resume_place: mir::Place<'tcx>,
67     ) {
68         trans.gen(resume_place.local)
69     }
70 }
71
72 struct TransferFunction<'a, T> {
73     trans: &'a mut T,
74 }
75
76 impl<T> Visitor<'_> for TransferFunction<'_, T>
77 where
78     T: GenKill<Local>,
79 {
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};
86         match context {
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,
92             ) => {}
93
94             // If it's deinitialized, it's no longer init
95             PlaceContext::MutatingUse(MutatingUseContext::Deinit) => self.trans.kill(local),
96
97             // Otherwise, when a place is mutated, we must consider it possibly initialized.
98             PlaceContext::MutatingUse(_) => self.trans.gen(local),
99
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),
104
105             // All other uses do not affect this analysis.
106             PlaceContext::NonUse(
107                 NonUseContext::StorageLive
108                 | NonUseContext::AscribeUserTy
109                 | NonUseContext::VarDebugInfo,
110             )
111             | PlaceContext::NonMutatingUse(
112                 NonMutatingUseContext::Inspect
113                 | NonMutatingUseContext::Copy
114                 | NonMutatingUseContext::SharedBorrow
115                 | NonMutatingUseContext::ShallowBorrow
116                 | NonMutatingUseContext::UniqueBorrow
117                 | NonMutatingUseContext::AddressOf
118                 | NonMutatingUseContext::Projection,
119             ) => {}
120         }
121     }
122 }