]>
Commit | Line | Data |
---|---|---|
041b39d2 XL |
1 | //! Dataflow analyses are built upon some interpretation of the |
2 | //! bitvectors attached to each basic block, represented via a | |
3 | //! zero-sized structure. | |
4 | ||
e74abb32 XL |
5 | use rustc_index::bit_set::BitSet; |
6 | use rustc_index::vec::Idx; | |
ba9703b0 XL |
7 | use rustc_middle::mir::{self, Body, Location}; |
8 | use rustc_middle::ty::{self, TyCtxt}; | |
9 | use rustc_target::abi::VariantIdx; | |
3157f602 | 10 | |
041b39d2 | 11 | use super::MoveDataParamEnv; |
83c7162d | 12 | |
9fa01778 | 13 | use crate::util::elaborate_drops::DropFlagState; |
3157f602 | 14 | |
74b04a01 | 15 | use super::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex}; |
ba9703b0 | 16 | use super::{AnalysisDomain, BottomValue, GenKill, GenKillAnalysis}; |
3157f602 | 17 | |
041b39d2 XL |
18 | use super::drop_flag_effects_for_function_entry; |
19 | use super::drop_flag_effects_for_location; | |
b7449926 | 20 | use super::on_lookup_result_bits; |
74b04a01 | 21 | use crate::dataflow::drop_flag_effects; |
3157f602 | 22 | |
2c00a5a8 | 23 | mod borrowed_locals; |
e74abb32 | 24 | mod storage_liveness; |
2c00a5a8 XL |
25 | |
26 | pub use self::borrowed_locals::*; | |
e74abb32 | 27 | pub use self::storage_liveness::*; |
2c00a5a8 | 28 | |
3b2f2976 XL |
29 | pub(super) mod borrows; |
30 | ||
2c00a5a8 | 31 | /// `MaybeInitializedPlaces` tracks all places that might be |
3157f602 XL |
32 | /// initialized upon reaching a particular point in the control flow |
33 | /// for a function. | |
34 | /// | |
35 | /// For example, in code like the following, we have corresponding | |
36 | /// dataflow information shown in the right-hand comments. | |
37 | /// | |
38 | /// ```rust | |
39 | /// struct S; | |
40 | /// fn foo(pred: bool) { // maybe-init: | |
41 | /// // {} | |
42 | /// let a = S; let b = S; let c; let d; // {a, b} | |
43 | /// | |
44 | /// if pred { | |
45 | /// drop(a); // { b} | |
46 | /// b = S; // { b} | |
47 | /// | |
48 | /// } else { | |
49 | /// drop(b); // {a} | |
50 | /// d = S; // {a, d} | |
51 | /// | |
52 | /// } // {a, b, d} | |
53 | /// | |
54 | /// c = S; // {a, b, c, d} | |
55 | /// } | |
56 | /// ``` | |
57 | /// | |
2c00a5a8 | 58 | /// To determine whether a place *must* be initialized at a |
3157f602 | 59 | /// particular control-flow point, one can take the set-difference |
2c00a5a8 | 60 | /// between this data and the data from `MaybeUninitializedPlaces` at the |
3157f602 XL |
61 | /// corresponding control-flow point. |
62 | /// | |
63 | /// Similarly, at a given `drop` statement, the set-intersection | |
2c00a5a8 XL |
64 | /// between this data and `MaybeUninitializedPlaces` yields the set of |
65 | /// places that would require a dynamic drop-flag at that statement. | |
dc9dc135 XL |
66 | pub struct MaybeInitializedPlaces<'a, 'tcx> { |
67 | tcx: TyCtxt<'tcx>, | |
68 | body: &'a Body<'tcx>, | |
69 | mdpe: &'a MoveDataParamEnv<'tcx>, | |
3157f602 XL |
70 | } |
71 | ||
dc9dc135 XL |
72 | impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { |
73 | pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { | |
60c5eb7d | 74 | MaybeInitializedPlaces { tcx, body, mdpe } |
3157f602 XL |
75 | } |
76 | } | |
77 | ||
dc9dc135 | 78 | impl<'a, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { |
dfeec247 XL |
79 | fn move_data(&self) -> &MoveData<'tcx> { |
80 | &self.mdpe.move_data | |
81 | } | |
32a655c1 SL |
82 | } |
83 | ||
2c00a5a8 | 84 | /// `MaybeUninitializedPlaces` tracks all places that might be |
3157f602 XL |
85 | /// uninitialized upon reaching a particular point in the control flow |
86 | /// for a function. | |
87 | /// | |
88 | /// For example, in code like the following, we have corresponding | |
89 | /// dataflow information shown in the right-hand comments. | |
90 | /// | |
91 | /// ```rust | |
92 | /// struct S; | |
93 | /// fn foo(pred: bool) { // maybe-uninit: | |
94 | /// // {a, b, c, d} | |
95 | /// let a = S; let b = S; let c; let d; // { c, d} | |
96 | /// | |
97 | /// if pred { | |
98 | /// drop(a); // {a, c, d} | |
99 | /// b = S; // {a, c, d} | |
100 | /// | |
101 | /// } else { | |
102 | /// drop(b); // { b, c, d} | |
103 | /// d = S; // { b, c } | |
104 | /// | |
105 | /// } // {a, b, c, d} | |
106 | /// | |
107 | /// c = S; // {a, b, d} | |
108 | /// } | |
109 | /// ``` | |
110 | /// | |
2c00a5a8 | 111 | /// To determine whether a place *must* be uninitialized at a |
3157f602 | 112 | /// particular control-flow point, one can take the set-difference |
2c00a5a8 | 113 | /// between this data and the data from `MaybeInitializedPlaces` at the |
3157f602 XL |
114 | /// corresponding control-flow point. |
115 | /// | |
116 | /// Similarly, at a given `drop` statement, the set-intersection | |
2c00a5a8 XL |
117 | /// between this data and `MaybeInitializedPlaces` yields the set of |
118 | /// places that would require a dynamic drop-flag at that statement. | |
dc9dc135 XL |
119 | pub struct MaybeUninitializedPlaces<'a, 'tcx> { |
120 | tcx: TyCtxt<'tcx>, | |
121 | body: &'a Body<'tcx>, | |
122 | mdpe: &'a MoveDataParamEnv<'tcx>, | |
3157f602 XL |
123 | } |
124 | ||
dc9dc135 XL |
125 | impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { |
126 | pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { | |
60c5eb7d | 127 | MaybeUninitializedPlaces { tcx, body, mdpe } |
3157f602 XL |
128 | } |
129 | } | |
130 | ||
dc9dc135 | 131 | impl<'a, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> { |
dfeec247 XL |
132 | fn move_data(&self) -> &MoveData<'tcx> { |
133 | &self.mdpe.move_data | |
134 | } | |
32a655c1 SL |
135 | } |
136 | ||
2c00a5a8 | 137 | /// `DefinitelyInitializedPlaces` tracks all places that are definitely |
3157f602 XL |
138 | /// initialized upon reaching a particular point in the control flow |
139 | /// for a function. | |
140 | /// | |
3157f602 XL |
141 | /// For example, in code like the following, we have corresponding |
142 | /// dataflow information shown in the right-hand comments. | |
143 | /// | |
144 | /// ```rust | |
145 | /// struct S; | |
146 | /// fn foo(pred: bool) { // definite-init: | |
147 | /// // { } | |
148 | /// let a = S; let b = S; let c; let d; // {a, b } | |
149 | /// | |
150 | /// if pred { | |
151 | /// drop(a); // { b, } | |
152 | /// b = S; // { b, } | |
153 | /// | |
154 | /// } else { | |
155 | /// drop(b); // {a, } | |
156 | /// d = S; // {a, d} | |
157 | /// | |
158 | /// } // { } | |
159 | /// | |
160 | /// c = S; // { c } | |
161 | /// } | |
162 | /// ``` | |
163 | /// | |
2c00a5a8 | 164 | /// To determine whether a place *may* be uninitialized at a |
3157f602 XL |
165 | /// particular control-flow point, one can take the set-complement |
166 | /// of this data. | |
167 | /// | |
168 | /// Similarly, at a given `drop` statement, the set-difference between | |
2c00a5a8 | 169 | /// this data and `MaybeInitializedPlaces` yields the set of places |
3157f602 | 170 | /// that would require a dynamic drop-flag at that statement. |
dc9dc135 XL |
171 | pub struct DefinitelyInitializedPlaces<'a, 'tcx> { |
172 | tcx: TyCtxt<'tcx>, | |
173 | body: &'a Body<'tcx>, | |
174 | mdpe: &'a MoveDataParamEnv<'tcx>, | |
3157f602 XL |
175 | } |
176 | ||
dc9dc135 XL |
177 | impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { |
178 | pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { | |
60c5eb7d | 179 | DefinitelyInitializedPlaces { tcx, body, mdpe } |
3157f602 XL |
180 | } |
181 | } | |
182 | ||
dc9dc135 | 183 | impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { |
dfeec247 XL |
184 | fn move_data(&self) -> &MoveData<'tcx> { |
185 | &self.mdpe.move_data | |
186 | } | |
32a655c1 SL |
187 | } |
188 | ||
2c00a5a8 | 189 | /// `EverInitializedPlaces` tracks all places that might have ever been |
ff7c6d11 XL |
190 | /// initialized upon reaching a particular point in the control flow |
191 | /// for a function, without an intervening `Storage Dead`. | |
192 | /// | |
193 | /// This dataflow is used to determine if an immutable local variable may | |
194 | /// be assigned to. | |
195 | /// | |
196 | /// For example, in code like the following, we have corresponding | |
197 | /// dataflow information shown in the right-hand comments. | |
198 | /// | |
199 | /// ```rust | |
200 | /// struct S; | |
201 | /// fn foo(pred: bool) { // ever-init: | |
202 | /// // { } | |
203 | /// let a = S; let b = S; let c; let d; // {a, b } | |
204 | /// | |
205 | /// if pred { | |
206 | /// drop(a); // {a, b, } | |
207 | /// b = S; // {a, b, } | |
208 | /// | |
209 | /// } else { | |
210 | /// drop(b); // {a, b, } | |
211 | /// d = S; // {a, b, d } | |
212 | /// | |
213 | /// } // {a, b, d } | |
214 | /// | |
215 | /// c = S; // {a, b, c, d } | |
216 | /// } | |
217 | /// ``` | |
dc9dc135 | 218 | pub struct EverInitializedPlaces<'a, 'tcx> { |
74b04a01 | 219 | #[allow(dead_code)] |
dc9dc135 XL |
220 | tcx: TyCtxt<'tcx>, |
221 | body: &'a Body<'tcx>, | |
222 | mdpe: &'a MoveDataParamEnv<'tcx>, | |
ff7c6d11 XL |
223 | } |
224 | ||
dc9dc135 XL |
225 | impl<'a, 'tcx> EverInitializedPlaces<'a, 'tcx> { |
226 | pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { | |
60c5eb7d | 227 | EverInitializedPlaces { tcx, body, mdpe } |
ff7c6d11 XL |
228 | } |
229 | } | |
230 | ||
dc9dc135 | 231 | impl<'a, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, 'tcx> { |
dfeec247 XL |
232 | fn move_data(&self) -> &MoveData<'tcx> { |
233 | &self.mdpe.move_data | |
234 | } | |
ff7c6d11 XL |
235 | } |
236 | ||
dc9dc135 | 237 | impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { |
dfeec247 | 238 | fn update_bits( |
74b04a01 | 239 | trans: &mut impl GenKill<MovePathIndex>, |
dfeec247 XL |
240 | path: MovePathIndex, |
241 | state: DropFlagState, | |
242 | ) { | |
3157f602 | 243 | match state { |
dc9dc135 XL |
244 | DropFlagState::Absent => trans.kill(path), |
245 | DropFlagState::Present => trans.gen(path), | |
3157f602 XL |
246 | } |
247 | } | |
248 | } | |
249 | ||
dc9dc135 | 250 | impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { |
dfeec247 | 251 | fn update_bits( |
74b04a01 | 252 | trans: &mut impl GenKill<MovePathIndex>, |
dfeec247 XL |
253 | path: MovePathIndex, |
254 | state: DropFlagState, | |
255 | ) { | |
3157f602 | 256 | match state { |
dc9dc135 XL |
257 | DropFlagState::Absent => trans.gen(path), |
258 | DropFlagState::Present => trans.kill(path), | |
3157f602 XL |
259 | } |
260 | } | |
261 | } | |
262 | ||
dc9dc135 | 263 | impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { |
dfeec247 | 264 | fn update_bits( |
74b04a01 | 265 | trans: &mut impl GenKill<MovePathIndex>, |
dfeec247 XL |
266 | path: MovePathIndex, |
267 | state: DropFlagState, | |
268 | ) { | |
3157f602 | 269 | match state { |
dc9dc135 XL |
270 | DropFlagState::Absent => trans.kill(path), |
271 | DropFlagState::Present => trans.gen(path), | |
3157f602 XL |
272 | } |
273 | } | |
274 | } | |
275 | ||
74b04a01 | 276 | impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { |
3157f602 | 277 | type Idx = MovePathIndex; |
74b04a01 XL |
278 | |
279 | const NAME: &'static str = "maybe_init"; | |
280 | ||
281 | fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { | |
32a655c1 | 282 | self.move_data().move_paths.len() |
3157f602 XL |
283 | } |
284 | ||
74b04a01 | 285 | fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) { |
dfeec247 XL |
286 | drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { |
287 | assert!(s == DropFlagState::Present); | |
74b04a01 | 288 | state.insert(path); |
dfeec247 XL |
289 | }); |
290 | } | |
291 | ||
74b04a01 XL |
292 | fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> { |
293 | write!(w, "{}", self.move_data().move_paths[mpi]) | |
294 | } | |
295 | } | |
296 | ||
297 | impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { | |
298 | fn statement_effect( | |
299 | &self, | |
300 | trans: &mut impl GenKill<Self::Idx>, | |
301 | _statement: &mir::Statement<'tcx>, | |
302 | location: Location, | |
303 | ) { | |
dfeec247 XL |
304 | drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { |
305 | Self::update_bits(trans, path, s) | |
306 | }) | |
307 | } | |
308 | ||
74b04a01 XL |
309 | fn terminator_effect( |
310 | &self, | |
311 | trans: &mut impl GenKill<Self::Idx>, | |
312 | _terminator: &mir::Terminator<'tcx>, | |
313 | location: Location, | |
314 | ) { | |
dfeec247 XL |
315 | drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { |
316 | Self::update_bits(trans, path, s) | |
317 | }) | |
3157f602 XL |
318 | } |
319 | ||
74b04a01 | 320 | fn call_return_effect( |
0731742a | 321 | &self, |
74b04a01 XL |
322 | trans: &mut impl GenKill<Self::Idx>, |
323 | _block: mir::BasicBlock, | |
324 | _func: &mir::Operand<'tcx>, | |
325 | _args: &[mir::Operand<'tcx>], | |
ba9703b0 | 326 | dest_place: mir::Place<'tcx>, |
0731742a | 327 | ) { |
3157f602 | 328 | // when a call returns successfully, that means we need to set |
ff7c6d11 | 329 | // the bits for that dest_place to 1 (initialized). |
dfeec247 XL |
330 | on_lookup_result_bits( |
331 | self.tcx, | |
332 | self.body, | |
333 | self.move_data(), | |
334 | self.move_data().rev_lookup.find(dest_place.as_ref()), | |
335 | |mpi| { | |
74b04a01 | 336 | trans.gen(mpi); |
dfeec247 XL |
337 | }, |
338 | ); | |
3157f602 | 339 | } |
74b04a01 XL |
340 | |
341 | fn discriminant_switch_effect( | |
342 | &self, | |
343 | trans: &mut impl GenKill<Self::Idx>, | |
344 | _block: mir::BasicBlock, | |
ba9703b0 | 345 | enum_place: mir::Place<'tcx>, |
74b04a01 XL |
346 | _adt: &ty::AdtDef, |
347 | variant: VariantIdx, | |
348 | ) { | |
349 | let enum_mpi = match self.move_data().rev_lookup.find(enum_place.as_ref()) { | |
350 | LookupResult::Exact(mpi) => mpi, | |
351 | LookupResult::Parent(_) => return, | |
352 | }; | |
353 | ||
354 | // Kill all move paths that correspond to variants other than this one | |
355 | let move_paths = &self.move_data().move_paths; | |
356 | let enum_path = &move_paths[enum_mpi]; | |
357 | for (mpi, variant_path) in enum_path.children(move_paths) { | |
358 | trans.kill(mpi); | |
359 | match variant_path.place.projection.last().unwrap() { | |
360 | mir::ProjectionElem::Downcast(_, idx) if *idx == variant => continue, | |
361 | _ => drop_flag_effects::on_all_children_bits( | |
362 | self.tcx, | |
363 | self.body, | |
364 | self.move_data(), | |
365 | mpi, | |
366 | |mpi| trans.kill(mpi), | |
367 | ), | |
368 | } | |
369 | } | |
370 | } | |
3157f602 XL |
371 | } |
372 | ||
74b04a01 | 373 | impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { |
3157f602 | 374 | type Idx = MovePathIndex; |
74b04a01 XL |
375 | |
376 | const NAME: &'static str = "maybe_uninit"; | |
377 | ||
378 | fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { | |
32a655c1 | 379 | self.move_data().move_paths.len() |
3157f602 XL |
380 | } |
381 | ||
ff7c6d11 | 382 | // sets on_entry bits for Arg places |
74b04a01 | 383 | fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) { |
3157f602 | 384 | // set all bits to 1 (uninit) before gathering counterevidence |
74b04a01 XL |
385 | assert!(self.bits_per_block(body) == state.domain_size()); |
386 | state.insert_all(); | |
3157f602 | 387 | |
dfeec247 XL |
388 | drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { |
389 | assert!(s == DropFlagState::Present); | |
74b04a01 | 390 | state.remove(path); |
dfeec247 | 391 | }); |
3157f602 XL |
392 | } |
393 | ||
74b04a01 XL |
394 | fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> { |
395 | write!(w, "{}", self.move_data().move_paths[mpi]) | |
396 | } | |
397 | } | |
398 | ||
399 | impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { | |
400 | fn statement_effect( | |
401 | &self, | |
402 | trans: &mut impl GenKill<Self::Idx>, | |
403 | _statement: &mir::Statement<'tcx>, | |
404 | location: Location, | |
405 | ) { | |
dfeec247 XL |
406 | drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { |
407 | Self::update_bits(trans, path, s) | |
408 | }) | |
3157f602 XL |
409 | } |
410 | ||
74b04a01 XL |
411 | fn terminator_effect( |
412 | &self, | |
413 | trans: &mut impl GenKill<Self::Idx>, | |
414 | _terminator: &mir::Terminator<'tcx>, | |
415 | location: Location, | |
416 | ) { | |
dfeec247 XL |
417 | drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { |
418 | Self::update_bits(trans, path, s) | |
419 | }) | |
3157f602 XL |
420 | } |
421 | ||
74b04a01 | 422 | fn call_return_effect( |
0731742a | 423 | &self, |
74b04a01 XL |
424 | trans: &mut impl GenKill<Self::Idx>, |
425 | _block: mir::BasicBlock, | |
426 | _func: &mir::Operand<'tcx>, | |
427 | _args: &[mir::Operand<'tcx>], | |
ba9703b0 | 428 | dest_place: mir::Place<'tcx>, |
0731742a | 429 | ) { |
3157f602 | 430 | // when a call returns successfully, that means we need to set |
ff7c6d11 | 431 | // the bits for that dest_place to 0 (initialized). |
dfeec247 XL |
432 | on_lookup_result_bits( |
433 | self.tcx, | |
434 | self.body, | |
435 | self.move_data(), | |
436 | self.move_data().rev_lookup.find(dest_place.as_ref()), | |
437 | |mpi| { | |
74b04a01 | 438 | trans.kill(mpi); |
dfeec247 XL |
439 | }, |
440 | ); | |
3157f602 XL |
441 | } |
442 | } | |
443 | ||
74b04a01 | 444 | impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { |
3157f602 | 445 | type Idx = MovePathIndex; |
74b04a01 XL |
446 | |
447 | const NAME: &'static str = "definite_init"; | |
448 | ||
449 | fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { | |
32a655c1 | 450 | self.move_data().move_paths.len() |
3157f602 XL |
451 | } |
452 | ||
ff7c6d11 | 453 | // sets on_entry bits for Arg places |
74b04a01 XL |
454 | fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) { |
455 | state.clear(); | |
3157f602 | 456 | |
dfeec247 XL |
457 | drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { |
458 | assert!(s == DropFlagState::Present); | |
74b04a01 | 459 | state.insert(path); |
dfeec247 | 460 | }); |
3157f602 XL |
461 | } |
462 | ||
74b04a01 XL |
463 | fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> { |
464 | write!(w, "{}", self.move_data().move_paths[mpi]) | |
465 | } | |
466 | } | |
467 | ||
468 | impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { | |
469 | fn statement_effect( | |
470 | &self, | |
471 | trans: &mut impl GenKill<Self::Idx>, | |
472 | _statement: &mir::Statement<'tcx>, | |
473 | location: Location, | |
474 | ) { | |
dfeec247 XL |
475 | drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { |
476 | Self::update_bits(trans, path, s) | |
477 | }) | |
3157f602 XL |
478 | } |
479 | ||
74b04a01 XL |
480 | fn terminator_effect( |
481 | &self, | |
482 | trans: &mut impl GenKill<Self::Idx>, | |
483 | _terminator: &mir::Terminator<'tcx>, | |
484 | location: Location, | |
485 | ) { | |
dfeec247 XL |
486 | drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| { |
487 | Self::update_bits(trans, path, s) | |
488 | }) | |
3157f602 XL |
489 | } |
490 | ||
74b04a01 | 491 | fn call_return_effect( |
0731742a | 492 | &self, |
74b04a01 XL |
493 | trans: &mut impl GenKill<Self::Idx>, |
494 | _block: mir::BasicBlock, | |
495 | _func: &mir::Operand<'tcx>, | |
496 | _args: &[mir::Operand<'tcx>], | |
ba9703b0 | 497 | dest_place: mir::Place<'tcx>, |
0731742a | 498 | ) { |
3157f602 | 499 | // when a call returns successfully, that means we need to set |
ff7c6d11 | 500 | // the bits for that dest_place to 1 (initialized). |
dfeec247 XL |
501 | on_lookup_result_bits( |
502 | self.tcx, | |
503 | self.body, | |
504 | self.move_data(), | |
505 | self.move_data().rev_lookup.find(dest_place.as_ref()), | |
506 | |mpi| { | |
74b04a01 | 507 | trans.gen(mpi); |
dfeec247 XL |
508 | }, |
509 | ); | |
3157f602 XL |
510 | } |
511 | } | |
512 | ||
74b04a01 | 513 | impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { |
ff7c6d11 | 514 | type Idx = InitIndex; |
74b04a01 XL |
515 | |
516 | const NAME: &'static str = "ever_init"; | |
517 | ||
518 | fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { | |
ff7c6d11 XL |
519 | self.move_data().inits.len() |
520 | } | |
abe05a73 | 521 | |
74b04a01 XL |
522 | fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) { |
523 | for arg_init in 0..body.arg_count { | |
524 | state.insert(InitIndex::new(arg_init)); | |
ff7c6d11 XL |
525 | } |
526 | } | |
74b04a01 | 527 | } |
ff7c6d11 | 528 | |
74b04a01 XL |
529 | impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { |
530 | fn statement_effect( | |
531 | &self, | |
532 | trans: &mut impl GenKill<Self::Idx>, | |
533 | stmt: &mir::Statement<'tcx>, | |
534 | location: Location, | |
535 | ) { | |
536 | let move_data = self.move_data(); | |
ff7c6d11 XL |
537 | let init_path_map = &move_data.init_path_map; |
538 | let init_loc_map = &move_data.init_loc_map; | |
539 | let rev_lookup = &move_data.rev_lookup; | |
540 | ||
dfeec247 XL |
541 | debug!( |
542 | "statement {:?} at loc {:?} initializes move_indexes {:?}", | |
543 | stmt, location, &init_loc_map[location] | |
544 | ); | |
74b04a01 | 545 | trans.gen_all(init_loc_map[location].iter().copied()); |
ff7c6d11 | 546 | |
ba9703b0 XL |
547 | if let mir::StatementKind::StorageDead(local) = stmt.kind { |
548 | // End inits for StorageDead, so that an immutable variable can | |
549 | // be reinitialized on the next iteration of the loop. | |
550 | let move_path_index = rev_lookup.find_local(local); | |
551 | debug!( | |
552 | "stmt {:?} at loc {:?} clears the ever initialized status of {:?}", | |
553 | stmt, location, &init_path_map[move_path_index] | |
554 | ); | |
555 | trans.kill_all(init_path_map[move_path_index].iter().copied()); | |
ff7c6d11 XL |
556 | } |
557 | } | |
558 | ||
74b04a01 XL |
559 | fn terminator_effect( |
560 | &self, | |
561 | trans: &mut impl GenKill<Self::Idx>, | |
562 | _terminator: &mir::Terminator<'tcx>, | |
563 | location: Location, | |
564 | ) { | |
dc9dc135 XL |
565 | let (body, move_data) = (self.body, self.move_data()); |
566 | let term = body[location.block].terminator(); | |
ff7c6d11 | 567 | let init_loc_map = &move_data.init_loc_map; |
dfeec247 XL |
568 | debug!( |
569 | "terminator {:?} at loc {:?} initializes move_indexes {:?}", | |
570 | term, location, &init_loc_map[location] | |
571 | ); | |
dc9dc135 | 572 | trans.gen_all( |
74b04a01 XL |
573 | init_loc_map[location] |
574 | .iter() | |
575 | .filter(|init_index| { | |
576 | move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly | |
577 | }) | |
578 | .copied(), | |
ff7c6d11 XL |
579 | ); |
580 | } | |
581 | ||
74b04a01 | 582 | fn call_return_effect( |
0731742a | 583 | &self, |
74b04a01 XL |
584 | trans: &mut impl GenKill<Self::Idx>, |
585 | block: mir::BasicBlock, | |
586 | _func: &mir::Operand<'tcx>, | |
587 | _args: &[mir::Operand<'tcx>], | |
ba9703b0 | 588 | _dest_place: mir::Place<'tcx>, |
0731742a | 589 | ) { |
ff7c6d11 | 590 | let move_data = self.move_data(); |
ff7c6d11 XL |
591 | let init_loc_map = &move_data.init_loc_map; |
592 | ||
74b04a01 | 593 | let call_loc = self.body.terminator_loc(block); |
ff7c6d11 | 594 | for init_index in &init_loc_map[call_loc] { |
74b04a01 | 595 | trans.gen(*init_index); |
ff7c6d11 XL |
596 | } |
597 | } | |
598 | } | |
abe05a73 | 599 | |
dc9dc135 XL |
600 | impl<'a, 'tcx> BottomValue for MaybeInitializedPlaces<'a, 'tcx> { |
601 | /// bottom = uninitialized | |
602 | const BOTTOM_VALUE: bool = false; | |
3157f602 XL |
603 | } |
604 | ||
dc9dc135 XL |
605 | impl<'a, 'tcx> BottomValue for MaybeUninitializedPlaces<'a, 'tcx> { |
606 | /// bottom = initialized (start_block_effect counters this at outset) | |
607 | const BOTTOM_VALUE: bool = false; | |
3157f602 XL |
608 | } |
609 | ||
dc9dc135 XL |
610 | impl<'a, 'tcx> BottomValue for DefinitelyInitializedPlaces<'a, 'tcx> { |
611 | /// bottom = initialized (start_block_effect counters this at outset) | |
612 | const BOTTOM_VALUE: bool = true; | |
ff7c6d11 XL |
613 | } |
614 | ||
dc9dc135 XL |
615 | impl<'a, 'tcx> BottomValue for EverInitializedPlaces<'a, 'tcx> { |
616 | /// bottom = no initialized variables by default | |
617 | const BOTTOM_VALUE: bool = false; | |
ff7c6d11 | 618 | } |