Skip to content

Commit daea09c

Browse files
Add MaybeInitializedLocals dataflow analysis
1 parent 3a7dfda commit daea09c

File tree

2 files changed

+117
-0
lines changed

2 files changed

+117
-0
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
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::VarDebugInfo,
103+
)
104+
| PlaceContext::NonMutatingUse(
105+
NonMutatingUseContext::Inspect
106+
| NonMutatingUseContext::Copy
107+
| NonMutatingUseContext::SharedBorrow
108+
| NonMutatingUseContext::ShallowBorrow
109+
| NonMutatingUseContext::UniqueBorrow
110+
| NonMutatingUseContext::AddressOf
111+
| NonMutatingUseContext::Projection,
112+
) => {}
113+
}
114+
}
115+
}

src/librustc_mir/dataflow/impls/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ use crate::dataflow::drop_flag_effects;
2222

2323
mod borrowed_locals;
2424
pub(super) mod borrows;
25+
mod init_locals;
2526
mod liveness;
2627
mod storage_liveness;
2728

2829
pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals};
2930
pub use self::borrows::Borrows;
31+
pub use self::init_locals::MaybeInitializedLocals;
3032
pub use self::liveness::MaybeLiveLocals;
3133
pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive};
3234

0 commit comments

Comments
 (0)