3 use crate::dataflow::BitDenotation;
4 use crate::dataflow::HaveBeenBorrowedLocals;
5 use crate::dataflow::{DataflowResults, DataflowResultsCursor, DataflowResultsRefCursor};
6 use rustc::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
8 use std::cell::RefCell;
10 #[derive(Copy, Clone)]
11 pub struct MaybeStorageLive<'a, 'tcx> {
15 impl<'a, 'tcx> MaybeStorageLive<'a, 'tcx> {
16 pub fn new(body: &'a Body<'tcx>) -> Self {
17 MaybeStorageLive { body }
20 pub fn body(&self) -> &Body<'tcx> {
25 impl<'a, 'tcx> BitDenotation<'tcx> for MaybeStorageLive<'a, 'tcx> {
27 fn name() -> &'static str {
30 fn bits_per_block(&self) -> usize {
31 self.body.local_decls.len()
34 fn start_block_effect(&self, _on_entry: &mut BitSet<Local>) {
35 // Nothing is live on function entry (generators only have a self
36 // argument, and we don't care about that)
37 assert_eq!(1, self.body.arg_count);
40 fn statement_effect(&self, trans: &mut GenKillSet<Local>, loc: Location) {
41 let stmt = &self.body[loc.block].statements[loc.statement_index];
44 StatementKind::StorageLive(l) => trans.gen(l),
45 StatementKind::StorageDead(l) => trans.kill(l),
50 fn terminator_effect(&self, _trans: &mut GenKillSet<Local>, _loc: Location) {
51 // Terminators have no effect
54 fn propagate_call_return(
56 _in_out: &mut BitSet<Local>,
57 _call_bb: mir::BasicBlock,
58 _dest_bb: mir::BasicBlock,
59 _dest_place: &mir::Place<'tcx>,
61 // Nothing to do when a call returns successfully
65 impl<'a, 'tcx> BottomValue for MaybeStorageLive<'a, 'tcx> {
67 const BOTTOM_VALUE: bool = false;
70 /// Dataflow analysis that determines whether each local requires storage at a
71 /// given location; i.e. whether its storage can go away without being observed.
72 pub struct RequiresStorage<'mir, 'tcx> {
73 body: ReadOnlyBodyAndCache<'mir, 'tcx>,
75 RefCell<DataflowResultsRefCursor<'mir, 'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>>,
78 impl<'mir, 'tcx: 'mir> RequiresStorage<'mir, 'tcx> {
80 body: ReadOnlyBodyAndCache<'mir, 'tcx>,
81 borrowed_locals: &'mir DataflowResults<'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>,
85 borrowed_locals: RefCell::new(DataflowResultsCursor::new(borrowed_locals, *body)),
89 pub fn body(&self) -> &Body<'tcx> {
94 impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
96 fn name() -> &'static str {
99 fn bits_per_block(&self) -> usize {
100 self.body.local_decls.len()
103 fn start_block_effect(&self, _sets: &mut BitSet<Local>) {
104 // Nothing is live on function entry (generators only have a self
105 // argument, and we don't care about that)
106 assert_eq!(1, self.body.arg_count);
109 fn before_statement_effect(&self, sets: &mut GenKillSet<Self::Idx>, loc: Location) {
110 // If we borrow or assign to a place then it needs storage for that
112 self.check_for_borrow(sets, loc);
114 let stmt = &self.body[loc.block].statements[loc.statement_index];
116 StatementKind::StorageDead(l) => sets.kill(l),
117 StatementKind::Assign(box (ref place, _))
118 | StatementKind::SetDiscriminant { box ref place, .. } => {
119 sets.gen(place.local);
121 StatementKind::InlineAsm(box InlineAsm { ref outputs, .. }) => {
122 for place in &**outputs {
123 sets.gen(place.local);
130 fn statement_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
131 // If we move from a place then only stops needing storage *after*
133 self.check_for_move(sets, loc);
136 fn before_terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
137 self.check_for_borrow(sets, loc);
139 if let TerminatorKind::Call { destination: Some((Place { local, .. }, _)), .. } =
140 self.body[loc.block].terminator().kind
146 fn terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
147 // For call terminators the destination requires storage for the call
148 // and after the call returns successfully, but not after a panic.
149 // Since `propagate_call_unwind` doesn't exist, we have to kill the
150 // destination here, and then gen it again in `propagate_call_return`.
151 if let TerminatorKind::Call { destination: Some((ref place, _)), .. } =
152 self.body[loc.block].terminator().kind
154 if let Some(local) = place.as_local() {
158 self.check_for_move(sets, loc);
161 fn propagate_call_return(
163 in_out: &mut BitSet<Local>,
164 _call_bb: mir::BasicBlock,
165 _dest_bb: mir::BasicBlock,
166 dest_place: &mir::Place<'tcx>,
168 in_out.insert(dest_place.local);
172 impl<'mir, 'tcx> RequiresStorage<'mir, 'tcx> {
173 /// Kill locals that are fully moved and have not been borrowed.
174 fn check_for_move(&self, sets: &mut GenKillSet<Local>, loc: Location) {
175 let mut visitor = MoveVisitor { sets, borrowed_locals: &self.borrowed_locals };
176 visitor.visit_location(self.body, loc);
179 /// Gen locals that are newly borrowed. This includes borrowing any part of
180 /// a local (we rely on this behavior of `HaveBeenBorrowedLocals`).
181 fn check_for_borrow(&self, sets: &mut GenKillSet<Local>, loc: Location) {
182 let mut borrowed_locals = self.borrowed_locals.borrow_mut();
183 borrowed_locals.seek(loc);
184 borrowed_locals.each_gen_bit(|l| sets.gen(l));
188 impl<'mir, 'tcx> BottomValue for RequiresStorage<'mir, 'tcx> {
190 const BOTTOM_VALUE: bool = false;
193 struct MoveVisitor<'a, 'mir, 'tcx> {
195 &'a RefCell<DataflowResultsRefCursor<'mir, 'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>>,
196 sets: &'a mut GenKillSet<Local>,
199 impl<'a, 'mir: 'a, 'tcx> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx> {
200 fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) {
201 if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
202 let mut borrowed_locals = self.borrowed_locals.borrow_mut();
203 borrowed_locals.seek(loc);
204 if !borrowed_locals.contains(*local) {
205 self.sets.kill(*local);