4 use rustc::mir::visit::{
5 PlaceContext, Visitor, NonMutatingUseContext,
7 use std::cell::RefCell;
8 use crate::dataflow::BitDenotation;
9 use crate::dataflow::HaveBeenBorrowedLocals;
10 use crate::dataflow::{DataflowResults, DataflowResultsCursor, DataflowResultsRefCursor};
12 #[derive(Copy, Clone)]
13 pub struct MaybeStorageLive<'a, 'tcx> {
17 impl<'a, 'tcx> MaybeStorageLive<'a, 'tcx> {
18 pub fn new(body: &'a Body<'tcx>)
20 MaybeStorageLive { body }
23 pub fn body(&self) -> &Body<'tcx> {
28 impl<'a, 'tcx> BitDenotation<'tcx> for MaybeStorageLive<'a, 'tcx> {
30 fn name() -> &'static str { "maybe_storage_live" }
31 fn bits_per_block(&self) -> usize {
32 self.body.local_decls.len()
35 fn start_block_effect(&self, _on_entry: &mut BitSet<Local>) {
36 // Nothing is live on function entry (generators only have a self
37 // argument, and we don't care about that)
38 assert_eq!(1, self.body.arg_count);
41 fn statement_effect(&self,
42 trans: &mut GenKillSet<Local>,
44 let stmt = &self.body[loc.block].statements[loc.statement_index];
47 StatementKind::StorageLive(l) => trans.gen(l),
48 StatementKind::StorageDead(l) => trans.kill(l),
53 fn terminator_effect(&self,
54 _trans: &mut GenKillSet<Local>,
56 // Terminators have no effect
59 fn propagate_call_return(
61 _in_out: &mut BitSet<Local>,
62 _call_bb: mir::BasicBlock,
63 _dest_bb: mir::BasicBlock,
64 _dest_place: &mir::Place<'tcx>,
66 // Nothing to do when a call returns successfully
70 impl<'a, 'tcx> BottomValue for MaybeStorageLive<'a, 'tcx> {
72 const BOTTOM_VALUE: bool = false;
75 /// Dataflow analysis that determines whether each local requires storage at a
76 /// given location; i.e. whether its storage can go away without being observed.
77 pub struct RequiresStorage<'mir, 'tcx> {
78 body: ReadOnlyBodyCache<'mir, 'tcx>,
80 RefCell<DataflowResultsRefCursor<'mir, 'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>>,
83 impl<'mir, 'tcx: 'mir> RequiresStorage<'mir, 'tcx> {
85 body: ReadOnlyBodyCache<'mir, 'tcx>,
86 borrowed_locals: &'mir DataflowResults<'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>,
90 borrowed_locals: RefCell::new(
91 DataflowResultsCursor::new(borrowed_locals, body.body())
96 pub fn body(&self) -> &Body<'tcx> {
101 impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
103 fn name() -> &'static str { "requires_storage" }
104 fn bits_per_block(&self) -> usize {
105 self.body.local_decls.len()
108 fn start_block_effect(&self, _sets: &mut BitSet<Local>) {
109 // Nothing is live on function entry (generators only have a self
110 // argument, and we don't care about that)
111 assert_eq!(1, self.body.arg_count);
114 fn before_statement_effect(&self, sets: &mut GenKillSet<Self::Idx>, loc: Location) {
115 // If we borrow or assign to a place then it needs storage for that
117 self.check_for_borrow(sets, loc);
119 let stmt = &self.body[loc.block].statements[loc.statement_index];
121 StatementKind::StorageDead(l) => sets.kill(l),
122 StatementKind::Assign(box(ref place, _))
123 | StatementKind::SetDiscriminant { box ref place, .. } => {
124 if let PlaceBase::Local(local) = place.base {
128 StatementKind::InlineAsm(box InlineAsm { ref outputs, .. }) => {
129 for p in &**outputs {
130 if let PlaceBase::Local(local) = p.base {
139 fn statement_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
140 // If we move from a place then only stops needing storage *after*
142 self.check_for_move(sets, loc);
145 fn before_terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
146 self.check_for_borrow(sets, loc);
148 if let TerminatorKind::Call {
149 destination: Some((Place { base: PlaceBase::Local(local), .. }, _)),
151 } = self.body[loc.block].terminator().kind {
156 fn terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
157 // For call terminators the destination requires storage for the call
158 // and after the call returns successfully, but not after a panic.
159 // Since `propagate_call_unwind` doesn't exist, we have to kill the
160 // destination here, and then gen it again in `propagate_call_return`.
161 if let TerminatorKind::Call {
162 destination: Some((ref place, _)),
164 } = self.body[loc.block].terminator().kind {
165 if let Some(local) = place.as_local() {
169 self.check_for_move(sets, loc);
172 fn propagate_call_return(
174 in_out: &mut BitSet<Local>,
175 _call_bb: mir::BasicBlock,
176 _dest_bb: mir::BasicBlock,
177 dest_place: &mir::Place<'tcx>,
179 if let PlaceBase::Local(local) = dest_place.base {
180 in_out.insert(local);
185 impl<'mir, 'tcx> RequiresStorage<'mir, 'tcx> {
186 /// Kill locals that are fully moved and have not been borrowed.
187 fn check_for_move(&self, sets: &mut GenKillSet<Local>, loc: Location) {
188 let mut visitor = MoveVisitor {
190 borrowed_locals: &self.borrowed_locals,
192 visitor.visit_location(self.body, loc);
195 /// Gen locals that are newly borrowed. This includes borrowing any part of
196 /// a local (we rely on this behavior of `HaveBeenBorrowedLocals`).
197 fn check_for_borrow(&self, sets: &mut GenKillSet<Local>, loc: Location) {
198 let mut borrowed_locals = self.borrowed_locals.borrow_mut();
199 borrowed_locals.seek(loc);
200 borrowed_locals.each_gen_bit(|l| sets.gen(l));
204 impl<'mir, 'tcx> BottomValue for RequiresStorage<'mir, 'tcx> {
206 const BOTTOM_VALUE: bool = false;
209 struct MoveVisitor<'a, 'mir, 'tcx> {
211 &'a RefCell<DataflowResultsRefCursor<'mir, 'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>>,
212 sets: &'a mut GenKillSet<Local>,
215 impl<'a, 'mir: 'a, 'tcx> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx> {
216 fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) {
217 if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
218 let mut borrowed_locals = self.borrowed_locals.borrow_mut();
219 borrowed_locals.seek(loc);
220 if !borrowed_locals.contains(*local) {
221 self.sets.kill(*local);