1 // Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Dataflow analyses are built upon some interpretation of the
12 //! bitvectors attached to each basic block, represented via a
13 //! zero-sized structure.
15 use rustc::ty::TyCtxt;
16 use rustc::mir::{self, Mir, Location};
17 use rustc_data_structures::bitslice::{BitwiseOperator};
18 use rustc_data_structures::indexed_set::{IdxSet};
20 use super::MoveDataParamEnv;
21 use util::elaborate_drops::DropFlagState;
23 use super::move_paths::{HasMoveData, MoveData, MovePathIndex};
24 use super::{BitDenotation, BlockSets, DataflowOperator};
26 use super::drop_flag_effects_for_function_entry;
27 use super::drop_flag_effects_for_location;
28 use super::on_lookup_result_bits;
32 pub use self::storage_liveness::*;
35 pub(super) mod borrows;
37 /// `MaybeInitializedLvals` tracks all l-values that might be
38 /// initialized upon reaching a particular point in the control flow
41 /// For example, in code like the following, we have corresponding
42 /// dataflow information shown in the right-hand comments.
46 /// fn foo(pred: bool) { // maybe-init:
48 /// let a = S; let b = S; let c; let d; // {a, b}
60 /// c = S; // {a, b, c, d}
64 /// To determine whether an l-value *must* be initialized at a
65 /// particular control-flow point, one can take the set-difference
66 /// between this data and the data from `MaybeUninitializedLvals` at the
67 /// corresponding control-flow point.
69 /// Similarly, at a given `drop` statement, the set-intersection
70 /// between this data and `MaybeUninitializedLvals` yields the set of
71 /// l-values that would require a dynamic drop-flag at that statement.
72 pub struct MaybeInitializedLvals<'a, 'tcx: 'a> {
73 tcx: TyCtxt<'a, 'tcx, 'tcx>,
75 mdpe: &'a MoveDataParamEnv<'tcx>,
78 impl<'a, 'tcx: 'a> MaybeInitializedLvals<'a, 'tcx> {
79 pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
81 mdpe: &'a MoveDataParamEnv<'tcx>)
84 MaybeInitializedLvals { tcx: tcx, mir: mir, mdpe: mdpe }
88 impl<'a, 'tcx: 'a> HasMoveData<'tcx> for MaybeInitializedLvals<'a, 'tcx> {
89 fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
92 /// `MaybeUninitializedLvals` tracks all l-values that might be
93 /// uninitialized upon reaching a particular point in the control flow
96 /// For example, in code like the following, we have corresponding
97 /// dataflow information shown in the right-hand comments.
101 /// fn foo(pred: bool) { // maybe-uninit:
103 /// let a = S; let b = S; let c; let d; // { c, d}
106 /// drop(a); // {a, c, d}
107 /// b = S; // {a, c, d}
110 /// drop(b); // { b, c, d}
111 /// d = S; // { b, c }
113 /// } // {a, b, c, d}
115 /// c = S; // {a, b, d}
119 /// To determine whether an l-value *must* be uninitialized at a
120 /// particular control-flow point, one can take the set-difference
121 /// between this data and the data from `MaybeInitializedLvals` at the
122 /// corresponding control-flow point.
124 /// Similarly, at a given `drop` statement, the set-intersection
125 /// between this data and `MaybeInitializedLvals` yields the set of
126 /// l-values that would require a dynamic drop-flag at that statement.
127 pub struct MaybeUninitializedLvals<'a, 'tcx: 'a> {
128 tcx: TyCtxt<'a, 'tcx, 'tcx>,
130 mdpe: &'a MoveDataParamEnv<'tcx>,
133 impl<'a, 'tcx: 'a> MaybeUninitializedLvals<'a, 'tcx> {
134 pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
136 mdpe: &'a MoveDataParamEnv<'tcx>)
139 MaybeUninitializedLvals { tcx: tcx, mir: mir, mdpe: mdpe }
143 impl<'a, 'tcx: 'a> HasMoveData<'tcx> for MaybeUninitializedLvals<'a, 'tcx> {
144 fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
147 /// `DefinitelyInitializedLvals` tracks all l-values that are definitely
148 /// initialized upon reaching a particular point in the control flow
151 /// FIXME: Note that once flow-analysis is complete, this should be
152 /// the set-complement of MaybeUninitializedLvals; thus we can get rid
153 /// of one or the other of these two. I'm inclined to get rid of
154 /// MaybeUninitializedLvals, simply because the sets will tend to be
155 /// smaller in this analysis and thus easier for humans to process
158 /// For example, in code like the following, we have corresponding
159 /// dataflow information shown in the right-hand comments.
163 /// fn foo(pred: bool) { // definite-init:
165 /// let a = S; let b = S; let c; let d; // {a, b }
168 /// drop(a); // { b, }
172 /// drop(b); // {a, }
181 /// To determine whether an l-value *may* be uninitialized at a
182 /// particular control-flow point, one can take the set-complement
185 /// Similarly, at a given `drop` statement, the set-difference between
186 /// this data and `MaybeInitializedLvals` yields the set of l-values
187 /// that would require a dynamic drop-flag at that statement.
188 pub struct DefinitelyInitializedLvals<'a, 'tcx: 'a> {
189 tcx: TyCtxt<'a, 'tcx, 'tcx>,
191 mdpe: &'a MoveDataParamEnv<'tcx>,
194 impl<'a, 'tcx: 'a> DefinitelyInitializedLvals<'a, 'tcx> {
195 pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
197 mdpe: &'a MoveDataParamEnv<'tcx>)
200 DefinitelyInitializedLvals { tcx: tcx, mir: mir, mdpe: mdpe }
204 impl<'a, 'tcx: 'a> HasMoveData<'tcx> for DefinitelyInitializedLvals<'a, 'tcx> {
205 fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
208 impl<'a, 'tcx> MaybeInitializedLvals<'a, 'tcx> {
209 fn update_bits(sets: &mut BlockSets<MovePathIndex>, path: MovePathIndex,
210 state: DropFlagState)
213 DropFlagState::Absent => sets.kill(&path),
214 DropFlagState::Present => sets.gen(&path),
219 impl<'a, 'tcx> MaybeUninitializedLvals<'a, 'tcx> {
220 fn update_bits(sets: &mut BlockSets<MovePathIndex>, path: MovePathIndex,
221 state: DropFlagState)
224 DropFlagState::Absent => sets.gen(&path),
225 DropFlagState::Present => sets.kill(&path),
230 impl<'a, 'tcx> DefinitelyInitializedLvals<'a, 'tcx> {
231 fn update_bits(sets: &mut BlockSets<MovePathIndex>, path: MovePathIndex,
232 state: DropFlagState)
235 DropFlagState::Absent => sets.kill(&path),
236 DropFlagState::Present => sets.gen(&path),
241 impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> {
242 type Idx = MovePathIndex;
243 fn name() -> &'static str { "maybe_init" }
244 fn bits_per_block(&self) -> usize {
245 self.move_data().move_paths.len()
248 fn start_block_effect(&self, sets: &mut BlockSets<MovePathIndex>)
250 drop_flag_effects_for_function_entry(
251 self.tcx, self.mir, self.mdpe,
253 assert!(s == DropFlagState::Present);
254 sets.on_entry.add(&path);
258 fn statement_effect(&self,
259 sets: &mut BlockSets<MovePathIndex>,
262 drop_flag_effects_for_location(
263 self.tcx, self.mir, self.mdpe,
265 |path, s| Self::update_bits(sets, path, s)
269 fn terminator_effect(&self,
270 sets: &mut BlockSets<MovePathIndex>,
273 drop_flag_effects_for_location(
274 self.tcx, self.mir, self.mdpe,
276 |path, s| Self::update_bits(sets, path, s)
280 fn propagate_call_return(&self,
281 in_out: &mut IdxSet<MovePathIndex>,
282 _call_bb: mir::BasicBlock,
283 _dest_bb: mir::BasicBlock,
284 dest_lval: &mir::Lvalue) {
285 // when a call returns successfully, that means we need to set
286 // the bits for that dest_lval to 1 (initialized).
287 on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
288 self.move_data().rev_lookup.find(dest_lval),
289 |mpi| { in_out.add(&mpi); });
293 impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> {
294 type Idx = MovePathIndex;
295 fn name() -> &'static str { "maybe_uninit" }
296 fn bits_per_block(&self) -> usize {
297 self.move_data().move_paths.len()
300 // sets on_entry bits for Arg lvalues
301 fn start_block_effect(&self, sets: &mut BlockSets<MovePathIndex>) {
302 // set all bits to 1 (uninit) before gathering counterevidence
303 for e in sets.on_entry.words_mut() { *e = !0; }
305 drop_flag_effects_for_function_entry(
306 self.tcx, self.mir, self.mdpe,
308 assert!(s == DropFlagState::Present);
309 sets.on_entry.remove(&path);
313 fn statement_effect(&self,
314 sets: &mut BlockSets<MovePathIndex>,
317 drop_flag_effects_for_location(
318 self.tcx, self.mir, self.mdpe,
320 |path, s| Self::update_bits(sets, path, s)
324 fn terminator_effect(&self,
325 sets: &mut BlockSets<MovePathIndex>,
328 drop_flag_effects_for_location(
329 self.tcx, self.mir, self.mdpe,
331 |path, s| Self::update_bits(sets, path, s)
335 fn propagate_call_return(&self,
336 in_out: &mut IdxSet<MovePathIndex>,
337 _call_bb: mir::BasicBlock,
338 _dest_bb: mir::BasicBlock,
339 dest_lval: &mir::Lvalue) {
340 // when a call returns successfully, that means we need to set
341 // the bits for that dest_lval to 0 (initialized).
342 on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
343 self.move_data().rev_lookup.find(dest_lval),
344 |mpi| { in_out.remove(&mpi); });
348 impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> {
349 type Idx = MovePathIndex;
350 fn name() -> &'static str { "definite_init" }
351 fn bits_per_block(&self) -> usize {
352 self.move_data().move_paths.len()
355 // sets on_entry bits for Arg lvalues
356 fn start_block_effect(&self, sets: &mut BlockSets<MovePathIndex>) {
357 for e in sets.on_entry.words_mut() { *e = 0; }
359 drop_flag_effects_for_function_entry(
360 self.tcx, self.mir, self.mdpe,
362 assert!(s == DropFlagState::Present);
363 sets.on_entry.add(&path);
367 fn statement_effect(&self,
368 sets: &mut BlockSets<MovePathIndex>,
371 drop_flag_effects_for_location(
372 self.tcx, self.mir, self.mdpe,
374 |path, s| Self::update_bits(sets, path, s)
378 fn terminator_effect(&self,
379 sets: &mut BlockSets<MovePathIndex>,
382 drop_flag_effects_for_location(
383 self.tcx, self.mir, self.mdpe,
385 |path, s| Self::update_bits(sets, path, s)
389 fn propagate_call_return(&self,
390 in_out: &mut IdxSet<MovePathIndex>,
391 _call_bb: mir::BasicBlock,
392 _dest_bb: mir::BasicBlock,
393 dest_lval: &mir::Lvalue) {
394 // when a call returns successfully, that means we need to set
395 // the bits for that dest_lval to 1 (initialized).
396 on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
397 self.move_data().rev_lookup.find(dest_lval),
398 |mpi| { in_out.add(&mpi); });
402 impl<'a, 'tcx> BitwiseOperator for MaybeInitializedLvals<'a, 'tcx> {
404 fn join(&self, pred1: usize, pred2: usize) -> usize {
405 pred1 | pred2 // "maybe" means we union effects of both preds
409 impl<'a, 'tcx> BitwiseOperator for MaybeUninitializedLvals<'a, 'tcx> {
411 fn join(&self, pred1: usize, pred2: usize) -> usize {
412 pred1 | pred2 // "maybe" means we union effects of both preds
416 impl<'a, 'tcx> BitwiseOperator for DefinitelyInitializedLvals<'a, 'tcx> {
418 fn join(&self, pred1: usize, pred2: usize) -> usize {
419 pred1 & pred2 // "definitely" means we intersect effects of both preds
423 // The way that dataflow fixed point iteration works, you want to
424 // start at bottom and work your way to a fixed point. Control-flow
425 // merges will apply the `join` operator to each block entry's current
426 // state (which starts at that bottom value).
428 // This means, for propagation across the graph, that you either want
429 // to start at all-zeroes and then use Union as your merge when
430 // propagating, or you start at all-ones and then use Intersect as
431 // your merge when propagating.
433 impl<'a, 'tcx> DataflowOperator for MaybeInitializedLvals<'a, 'tcx> {
435 fn bottom_value() -> bool {
436 false // bottom = uninitialized
440 impl<'a, 'tcx> DataflowOperator for MaybeUninitializedLvals<'a, 'tcx> {
442 fn bottom_value() -> bool {
443 false // bottom = initialized (start_block_effect counters this at outset)
447 impl<'a, 'tcx> DataflowOperator for DefinitelyInitializedLvals<'a, 'tcx> {
449 fn bottom_value() -> bool {
450 true // bottom = initialized (start_block_effect counters this at outset)