]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/dataflow/impls/borrowed_locals.rs
Unify API of `Scalar` and `ScalarMaybeUndef`
[rust.git] / src / librustc_mir / dataflow / impls / borrowed_locals.rs
1 // Copyright 2017 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.
4 //
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.
10
11 pub use super::*;
12
13 use rustc::mir::*;
14 use rustc::mir::visit::Visitor;
15 use dataflow::BitDenotation;
16
17 /// This calculates if any part of a MIR local could have previously been borrowed.
18 /// This means that once a local has been borrowed, its bit will always be set
19 /// from that point and onwards, even if the borrow ends. You could also think of this
20 /// as computing the lifetimes of infinite borrows.
21 /// This is used to compute which locals are live during a yield expression for
22 /// immovable generators.
23 #[derive(Copy, Clone)]
24 pub struct HaveBeenBorrowedLocals<'a, 'tcx: 'a> {
25     mir: &'a Mir<'tcx>,
26 }
27
28 impl<'a, 'tcx: 'a> HaveBeenBorrowedLocals<'a, 'tcx> {
29     pub fn new(mir: &'a Mir<'tcx>)
30                -> Self {
31         HaveBeenBorrowedLocals { mir: mir }
32     }
33
34     pub fn mir(&self) -> &Mir<'tcx> {
35         self.mir
36     }
37 }
38
39 impl<'a, 'tcx> BitDenotation for HaveBeenBorrowedLocals<'a, 'tcx> {
40     type Idx = Local;
41     fn name() -> &'static str { "has_been_borrowed_locals" }
42     fn bits_per_block(&self) -> usize {
43         self.mir.local_decls.len()
44     }
45
46     fn start_block_effect(&self, _sets: &mut IdxSet<Local>) {
47         // Nothing is borrowed on function entry
48     }
49
50     fn statement_effect(&self,
51                         sets: &mut BlockSets<Local>,
52                         loc: Location) {
53         BorrowedLocalsVisitor {
54             sets,
55         }.visit_statement(loc.block, &self.mir[loc.block].statements[loc.statement_index], loc);
56     }
57
58     fn terminator_effect(&self,
59                          sets: &mut BlockSets<Local>,
60                          loc: Location) {
61         BorrowedLocalsVisitor {
62             sets,
63         }.visit_terminator(loc.block, self.mir[loc.block].terminator(), loc);
64     }
65
66     fn propagate_call_return(&self,
67                              _in_out: &mut IdxSet<Local>,
68                              _call_bb: mir::BasicBlock,
69                              _dest_bb: mir::BasicBlock,
70                              _dest_place: &mir::Place) {
71         // Nothing to do when a call returns successfully
72     }
73 }
74
75 impl<'a, 'tcx> BitwiseOperator for HaveBeenBorrowedLocals<'a, 'tcx> {
76     #[inline]
77     fn join(&self, pred1: Word, pred2: Word) -> Word {
78         pred1 | pred2 // "maybe" means we union effects of both preds
79     }
80 }
81
82 impl<'a, 'tcx> InitialFlow for HaveBeenBorrowedLocals<'a, 'tcx> {
83     #[inline]
84     fn bottom_value() -> bool {
85         false // bottom = unborrowed
86     }
87 }
88
89 struct BorrowedLocalsVisitor<'b, 'c: 'b> {
90     sets: &'b mut BlockSets<'c, Local>,
91 }
92
93 fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
94     match *place {
95         Place::Local(l) => Some(l),
96         Place::Promoted(_) |
97         Place::Static(..) => None,
98         Place::Projection(ref proj) => {
99             match proj.elem {
100                 ProjectionElem::Deref => None,
101                 _ => find_local(&proj.base)
102             }
103         }
104     }
105 }
106
107 impl<'tcx, 'b, 'c> Visitor<'tcx> for BorrowedLocalsVisitor<'b, 'c> {
108     fn visit_rvalue(&mut self,
109                     rvalue: &Rvalue<'tcx>,
110                     location: Location) {
111         if let Rvalue::Ref(_, _, ref place) = *rvalue {
112             if let Some(local) = find_local(place) {
113                 self.sets.gen(&local);
114             }
115         }
116
117         self.super_rvalue(rvalue, location)
118     }
119 }