]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/dataflow/impls/init_locals.rs
New upstream version 1.47.0+dfsg1
[rustc.git] / src / librustc_mir / dataflow / 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::dataflow::{self, BottomValue, 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 BottomValue for MaybeInitializedLocals {
14 /// bottom = uninit
15 const BOTTOM_VALUE: bool = false;
16 }
17
18 impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals {
19 type Idx = Local;
20
21 const NAME: &'static str = "maybe_init_locals";
22
23 fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
24 body.local_decls.len()
25 }
26
27 fn initialize_start_block(&self, body: &mir::Body<'tcx>, entry_set: &mut BitSet<Self::Idx>) {
28 // Function arguments are initialized to begin with.
29 for arg in body.args_iter() {
30 entry_set.insert(arg);
31 }
32 }
33 }
34
35 impl dataflow::GenKillAnalysis<'tcx> for MaybeInitializedLocals {
36 fn statement_effect(
37 &self,
38 trans: &mut impl GenKill<Self::Idx>,
39 statement: &mir::Statement<'tcx>,
40 loc: Location,
41 ) {
42 TransferFunction { trans }.visit_statement(statement, loc)
43 }
44
45 fn terminator_effect(
46 &self,
47 trans: &mut impl GenKill<Self::Idx>,
48 terminator: &mir::Terminator<'tcx>,
49 loc: Location,
50 ) {
51 TransferFunction { trans }.visit_terminator(terminator, loc)
52 }
53
54 fn call_return_effect(
55 &self,
56 trans: &mut impl GenKill<Self::Idx>,
57 _block: BasicBlock,
58 _func: &mir::Operand<'tcx>,
59 _args: &[mir::Operand<'tcx>],
60 return_place: mir::Place<'tcx>,
61 ) {
62 trans.gen(return_place.local)
63 }
64
65 /// See `Analysis::apply_yield_resume_effect`.
66 fn yield_resume_effect(
67 &self,
68 trans: &mut impl GenKill<Self::Idx>,
69 _resume_block: BasicBlock,
70 resume_place: mir::Place<'tcx>,
71 ) {
72 trans.gen(resume_place.local)
73 }
74 }
75
76 struct TransferFunction<'a, T> {
77 trans: &'a mut T,
78 }
79
80 impl<T> Visitor<'tcx> for TransferFunction<'a, T>
81 where
82 T: GenKill<Local>,
83 {
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(MutatingUseContext::Call | MutatingUseContext::Yield) => {}
89
90 // Otherwise, when a place is mutated, we must consider it possibly initialized.
91 PlaceContext::MutatingUse(_) => self.trans.gen(local),
92
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),
97
98 // All other uses do not affect this analysis.
99 PlaceContext::NonUse(
100 NonUseContext::StorageLive
101 | NonUseContext::AscribeUserTy
102 | NonUseContext::Coverage
103 | NonUseContext::VarDebugInfo,
104 )
105 | PlaceContext::NonMutatingUse(
106 NonMutatingUseContext::Inspect
107 | NonMutatingUseContext::Copy
108 | NonMutatingUseContext::SharedBorrow
109 | NonMutatingUseContext::ShallowBorrow
110 | NonMutatingUseContext::UniqueBorrow
111 | NonMutatingUseContext::AddressOf
112 | NonMutatingUseContext::Projection,
113 ) => {}
114 }
115 }
116 }