]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/dataflow/impls/borrowed_locals.rs
069ce3a78c5f9f0b4f451939beb5539e80047307
[rust.git] / src / librustc_mir / dataflow / impls / borrowed_locals.rs
1 pub use super::*;
2
3 use rustc::mir::*;
4 use rustc::mir::visit::Visitor;
5 use crate::dataflow::BitDenotation;
6
7 /// This calculates if any part of a MIR local could have previously been borrowed.
8 /// This means that once a local has been borrowed, its bit will be set
9 /// from that point and onwards, until we see a StorageDead statement for the local,
10 /// at which points there is no memory associated with the local, so it cannot be borrowed.
11 /// This is used to compute which locals are live during a yield expression for
12 /// immovable generators.
13 #[derive(Copy, Clone)]
14 pub struct HaveBeenBorrowedLocals<'a, 'tcx> {
15     body: &'a Body<'tcx>,
16 }
17
18 impl<'a, 'tcx> HaveBeenBorrowedLocals<'a, 'tcx> {
19     pub fn new(body: &'a Body<'tcx>)
20                -> Self {
21         HaveBeenBorrowedLocals { body }
22     }
23
24     pub fn body(&self) -> &Body<'tcx> {
25         self.body
26     }
27 }
28
29 impl<'a, 'tcx> BitDenotation<'tcx> for HaveBeenBorrowedLocals<'a, 'tcx> {
30     type Idx = Local;
31     fn name() -> &'static str { "has_been_borrowed_locals" }
32     fn bits_per_block(&self) -> usize {
33         self.body.local_decls.len()
34     }
35
36     fn start_block_effect(&self, _sets: &mut BitSet<Local>) {
37         // Nothing is borrowed on function entry
38     }
39
40     fn statement_effect(&self,
41                         sets: &mut BlockSets<'_, Local>,
42                         loc: Location) {
43         let stmt = &self.body[loc.block].statements[loc.statement_index];
44
45         BorrowedLocalsVisitor {
46             sets,
47         }.visit_statement(stmt, loc);
48
49         // StorageDead invalidates all borrows and raw pointers to a local
50         match stmt.kind {
51             StatementKind::StorageDead(l) => sets.kill(l),
52             _ => (),
53         }
54     }
55
56     fn terminator_effect(&self,
57                          sets: &mut BlockSets<'_, Local>,
58                          loc: Location) {
59         let terminator = self.body[loc.block].terminator();
60         BorrowedLocalsVisitor {
61             sets,
62         }.visit_terminator(terminator, loc);
63         match &terminator.kind {
64             // Drop terminators borrows the location
65             TerminatorKind::Drop { location, .. } |
66             TerminatorKind::DropAndReplace { location, .. } => {
67                 if let Some(local) = find_local(location) {
68                     sets.gen(local);
69                 }
70             }
71             _ => (),
72         }
73     }
74
75     fn propagate_call_return(
76         &self,
77         _in_out: &mut BitSet<Local>,
78         _call_bb: mir::BasicBlock,
79         _dest_bb: mir::BasicBlock,
80         _dest_place: &mir::Place<'tcx>,
81     ) {
82         // Nothing to do when a call returns successfully
83     }
84 }
85
86 impl<'a, 'tcx> BitSetOperator for HaveBeenBorrowedLocals<'a, 'tcx> {
87     #[inline]
88     fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
89         inout_set.union(in_set) // "maybe" means we union effects of both preds
90     }
91 }
92
93 impl<'a, 'tcx> InitialFlow for HaveBeenBorrowedLocals<'a, 'tcx> {
94     #[inline]
95     fn bottom_value() -> bool {
96         false // bottom = unborrowed
97     }
98 }
99
100 struct BorrowedLocalsVisitor<'b, 'c> {
101     sets: &'b mut BlockSets<'c, Local>,
102 }
103
104 fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
105     place.iterate(|place_base, place_projection| {
106         for proj in place_projection {
107             if proj.elem == ProjectionElem::Deref {
108                 return None;
109             }
110         }
111
112         if let PlaceBase::Local(local) = place_base {
113             Some(*local)
114         } else {
115             None
116         }
117     })
118 }
119
120 impl<'tcx, 'b, 'c> Visitor<'tcx> for BorrowedLocalsVisitor<'b, 'c> {
121     fn visit_rvalue(&mut self,
122                     rvalue: &Rvalue<'tcx>,
123                     location: Location) {
124         if let Rvalue::Ref(_, _, ref place) = *rvalue {
125             if let Some(local) = find_local(place) {
126                 self.sets.gen(local);
127             }
128         }
129
130         self.super_rvalue(rvalue, location)
131     }
132 }