|  | 
| 1 | 1 | pub use super::*; | 
| 2 | 2 | 
 | 
| 3 | 3 | use crate::dataflow::BottomValue; | 
| 4 |  | -use crate::dataflow::{self, GenKill, Results, ResultsRefCursor}; | 
|  | 4 | +use crate::dataflow::{self, GenKill}; | 
| 5 | 5 | use crate::util::storage::AlwaysLiveLocals; | 
| 6 |  | -use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; | 
| 7 | 6 | use rustc_middle::mir::*; | 
| 8 |  | -use std::cell::RefCell; | 
| 9 | 7 | 
 | 
| 10 | 8 | #[derive(Clone)] | 
| 11 | 9 | pub struct MaybeStorageLive { | 
| @@ -78,233 +76,3 @@ impl BottomValue for MaybeStorageLive { | 
| 78 | 76 |     /// bottom = dead | 
| 79 | 77 |     const BOTTOM_VALUE: bool = false; | 
| 80 | 78 | } | 
| 81 |  | - | 
| 82 |  | -type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>; | 
| 83 |  | - | 
| 84 |  | -/// Dataflow analysis that determines whether each local requires storage at a | 
| 85 |  | -/// given location; i.e. whether its storage can go away without being observed. | 
| 86 |  | -pub struct MaybeRequiresStorage<'mir, 'tcx> { | 
| 87 |  | -    body: &'mir Body<'tcx>, | 
| 88 |  | -    borrowed_locals: RefCell<BorrowedLocalsResults<'mir, 'tcx>>, | 
| 89 |  | -} | 
| 90 |  | - | 
| 91 |  | -impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { | 
| 92 |  | -    pub fn new( | 
| 93 |  | -        body: &'mir Body<'tcx>, | 
| 94 |  | -        borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>, | 
| 95 |  | -    ) -> Self { | 
| 96 |  | -        MaybeRequiresStorage { | 
| 97 |  | -            body, | 
| 98 |  | -            borrowed_locals: RefCell::new(ResultsRefCursor::new(&body, borrowed_locals)), | 
| 99 |  | -        } | 
| 100 |  | -    } | 
| 101 |  | -} | 
| 102 |  | - | 
| 103 |  | -impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { | 
| 104 |  | -    type Idx = Local; | 
| 105 |  | - | 
| 106 |  | -    const NAME: &'static str = "requires_storage"; | 
| 107 |  | - | 
| 108 |  | -    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { | 
| 109 |  | -        body.local_decls.len() | 
| 110 |  | -    } | 
| 111 |  | - | 
| 112 |  | -    fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut BitSet<Self::Idx>) { | 
| 113 |  | -        // The resume argument is live on function entry (we don't care about | 
| 114 |  | -        // the `self` argument) | 
| 115 |  | -        for arg in body.args_iter().skip(1) { | 
| 116 |  | -            on_entry.insert(arg); | 
| 117 |  | -        } | 
| 118 |  | -    } | 
| 119 |  | -} | 
| 120 |  | - | 
| 121 |  | -impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { | 
| 122 |  | -    fn before_statement_effect( | 
| 123 |  | -        &self, | 
| 124 |  | -        trans: &mut impl GenKill<Self::Idx>, | 
| 125 |  | -        stmt: &mir::Statement<'tcx>, | 
| 126 |  | -        loc: Location, | 
| 127 |  | -    ) { | 
| 128 |  | -        // If a place is borrowed in a statement, it needs storage for that statement. | 
| 129 |  | -        self.borrowed_locals.borrow().analysis().statement_effect(trans, stmt, loc); | 
| 130 |  | - | 
| 131 |  | -        match &stmt.kind { | 
| 132 |  | -            StatementKind::StorageDead(l) => trans.kill(*l), | 
| 133 |  | - | 
| 134 |  | -            // If a place is assigned to in a statement, it needs storage for that statement. | 
| 135 |  | -            StatementKind::Assign(box (place, _)) | 
| 136 |  | -            | StatementKind::SetDiscriminant { box place, .. } => { | 
| 137 |  | -                trans.gen(place.local); | 
| 138 |  | -            } | 
| 139 |  | -            StatementKind::LlvmInlineAsm(asm) => { | 
| 140 |  | -                for place in &*asm.outputs { | 
| 141 |  | -                    trans.gen(place.local); | 
| 142 |  | -                } | 
| 143 |  | -            } | 
| 144 |  | - | 
| 145 |  | -            // Nothing to do for these. Match exhaustively so this fails to compile when new | 
| 146 |  | -            // variants are added. | 
| 147 |  | -            StatementKind::AscribeUserType(..) | 
| 148 |  | -            | StatementKind::FakeRead(..) | 
| 149 |  | -            | StatementKind::Nop | 
| 150 |  | -            | StatementKind::Retag(..) | 
| 151 |  | -            | StatementKind::StorageLive(..) => {} | 
| 152 |  | -        } | 
| 153 |  | -    } | 
| 154 |  | - | 
| 155 |  | -    fn statement_effect( | 
| 156 |  | -        &self, | 
| 157 |  | -        trans: &mut impl GenKill<Self::Idx>, | 
| 158 |  | -        _: &mir::Statement<'tcx>, | 
| 159 |  | -        loc: Location, | 
| 160 |  | -    ) { | 
| 161 |  | -        // If we move from a place then only stops needing storage *after* | 
| 162 |  | -        // that statement. | 
| 163 |  | -        self.check_for_move(trans, loc); | 
| 164 |  | -    } | 
| 165 |  | - | 
| 166 |  | -    fn before_terminator_effect( | 
| 167 |  | -        &self, | 
| 168 |  | -        trans: &mut impl GenKill<Self::Idx>, | 
| 169 |  | -        terminator: &mir::Terminator<'tcx>, | 
| 170 |  | -        loc: Location, | 
| 171 |  | -    ) { | 
| 172 |  | -        // If a place is borrowed in a terminator, it needs storage for that terminator. | 
| 173 |  | -        self.borrowed_locals.borrow().analysis().terminator_effect(trans, terminator, loc); | 
| 174 |  | - | 
| 175 |  | -        match &terminator.kind { | 
| 176 |  | -            TerminatorKind::Call { destination: Some((place, _)), .. } => { | 
| 177 |  | -                trans.gen(place.local); | 
| 178 |  | -            } | 
| 179 |  | - | 
| 180 |  | -            // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for | 
| 181 |  | -            // that is that a `yield` will return from the function, and `resume_arg` is written | 
| 182 |  | -            // only when the generator is later resumed. Unlike `Call`, this doesn't require the | 
| 183 |  | -            // place to have storage *before* the yield, only after. | 
| 184 |  | -            TerminatorKind::Yield { .. } => {} | 
| 185 |  | - | 
| 186 |  | -            TerminatorKind::InlineAsm { operands, .. } => { | 
| 187 |  | -                for op in operands { | 
| 188 |  | -                    match op { | 
| 189 |  | -                        InlineAsmOperand::Out { place, .. } | 
| 190 |  | -                        | InlineAsmOperand::InOut { out_place: place, .. } => { | 
| 191 |  | -                            if let Some(place) = place { | 
| 192 |  | -                                trans.gen(place.local); | 
| 193 |  | -                            } | 
| 194 |  | -                        } | 
| 195 |  | -                        InlineAsmOperand::In { .. } | 
| 196 |  | -                        | InlineAsmOperand::Const { .. } | 
| 197 |  | -                        | InlineAsmOperand::SymFn { .. } | 
| 198 |  | -                        | InlineAsmOperand::SymStatic { .. } => {} | 
| 199 |  | -                    } | 
| 200 |  | -                } | 
| 201 |  | -            } | 
| 202 |  | - | 
| 203 |  | -            // Nothing to do for these. Match exhaustively so this fails to compile when new | 
| 204 |  | -            // variants are added. | 
| 205 |  | -            TerminatorKind::Call { destination: None, .. } | 
| 206 |  | -            | TerminatorKind::Abort | 
| 207 |  | -            | TerminatorKind::Assert { .. } | 
| 208 |  | -            | TerminatorKind::Drop { .. } | 
| 209 |  | -            | TerminatorKind::DropAndReplace { .. } | 
| 210 |  | -            | TerminatorKind::FalseEdges { .. } | 
| 211 |  | -            | TerminatorKind::FalseUnwind { .. } | 
| 212 |  | -            | TerminatorKind::GeneratorDrop | 
| 213 |  | -            | TerminatorKind::Goto { .. } | 
| 214 |  | -            | TerminatorKind::Resume | 
| 215 |  | -            | TerminatorKind::Return | 
| 216 |  | -            | TerminatorKind::SwitchInt { .. } | 
| 217 |  | -            | TerminatorKind::Unreachable => {} | 
| 218 |  | -        } | 
| 219 |  | -    } | 
| 220 |  | - | 
| 221 |  | -    fn terminator_effect( | 
| 222 |  | -        &self, | 
| 223 |  | -        trans: &mut impl GenKill<Self::Idx>, | 
| 224 |  | -        terminator: &mir::Terminator<'tcx>, | 
| 225 |  | -        loc: Location, | 
| 226 |  | -    ) { | 
| 227 |  | -        match &terminator.kind { | 
| 228 |  | -            // For call terminators the destination requires storage for the call | 
| 229 |  | -            // and after the call returns successfully, but not after a panic. | 
| 230 |  | -            // Since `propagate_call_unwind` doesn't exist, we have to kill the | 
| 231 |  | -            // destination here, and then gen it again in `call_return_effect`. | 
| 232 |  | -            TerminatorKind::Call { destination: Some((place, _)), .. } => { | 
| 233 |  | -                trans.kill(place.local); | 
| 234 |  | -            } | 
| 235 |  | - | 
| 236 |  | -            // Nothing to do for these. Match exhaustively so this fails to compile when new | 
| 237 |  | -            // variants are added. | 
| 238 |  | -            TerminatorKind::Call { destination: None, .. } | 
| 239 |  | -            | TerminatorKind::Yield { .. } | 
| 240 |  | -            | TerminatorKind::Abort | 
| 241 |  | -            | TerminatorKind::Assert { .. } | 
| 242 |  | -            | TerminatorKind::Drop { .. } | 
| 243 |  | -            | TerminatorKind::DropAndReplace { .. } | 
| 244 |  | -            | TerminatorKind::FalseEdges { .. } | 
| 245 |  | -            | TerminatorKind::FalseUnwind { .. } | 
| 246 |  | -            | TerminatorKind::GeneratorDrop | 
| 247 |  | -            | TerminatorKind::Goto { .. } | 
| 248 |  | -            | TerminatorKind::InlineAsm { .. } | 
| 249 |  | -            | TerminatorKind::Resume | 
| 250 |  | -            | TerminatorKind::Return | 
| 251 |  | -            | TerminatorKind::SwitchInt { .. } | 
| 252 |  | -            | TerminatorKind::Unreachable => {} | 
| 253 |  | -        } | 
| 254 |  | - | 
| 255 |  | -        self.check_for_move(trans, loc); | 
| 256 |  | -    } | 
| 257 |  | - | 
| 258 |  | -    fn call_return_effect( | 
| 259 |  | -        &self, | 
| 260 |  | -        trans: &mut impl GenKill<Self::Idx>, | 
| 261 |  | -        _block: BasicBlock, | 
| 262 |  | -        _func: &mir::Operand<'tcx>, | 
| 263 |  | -        _args: &[mir::Operand<'tcx>], | 
| 264 |  | -        return_place: mir::Place<'tcx>, | 
| 265 |  | -    ) { | 
| 266 |  | -        trans.gen(return_place.local); | 
| 267 |  | -    } | 
| 268 |  | - | 
| 269 |  | -    fn yield_resume_effect( | 
| 270 |  | -        &self, | 
| 271 |  | -        trans: &mut impl GenKill<Self::Idx>, | 
| 272 |  | -        _resume_block: BasicBlock, | 
| 273 |  | -        resume_place: mir::Place<'tcx>, | 
| 274 |  | -    ) { | 
| 275 |  | -        trans.gen(resume_place.local); | 
| 276 |  | -    } | 
| 277 |  | -} | 
| 278 |  | - | 
| 279 |  | -impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { | 
| 280 |  | -    /// Kill locals that are fully moved and have not been borrowed. | 
| 281 |  | -    fn check_for_move(&self, trans: &mut impl GenKill<Local>, loc: Location) { | 
| 282 |  | -        let mut visitor = MoveVisitor { trans, borrowed_locals: &self.borrowed_locals }; | 
| 283 |  | -        visitor.visit_location(&self.body, loc); | 
| 284 |  | -    } | 
| 285 |  | -} | 
| 286 |  | - | 
| 287 |  | -impl<'mir, 'tcx> BottomValue for MaybeRequiresStorage<'mir, 'tcx> { | 
| 288 |  | -    /// bottom = dead | 
| 289 |  | -    const BOTTOM_VALUE: bool = false; | 
| 290 |  | -} | 
| 291 |  | - | 
| 292 |  | -struct MoveVisitor<'a, 'mir, 'tcx, T> { | 
| 293 |  | -    borrowed_locals: &'a RefCell<BorrowedLocalsResults<'mir, 'tcx>>, | 
| 294 |  | -    trans: &'a mut T, | 
| 295 |  | -} | 
| 296 |  | - | 
| 297 |  | -impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T> | 
| 298 |  | -where | 
| 299 |  | -    T: GenKill<Local>, | 
| 300 |  | -{ | 
| 301 |  | -    fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) { | 
| 302 |  | -        if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context { | 
| 303 |  | -            let mut borrowed_locals = self.borrowed_locals.borrow_mut(); | 
| 304 |  | -            borrowed_locals.seek_before_primary_effect(loc); | 
| 305 |  | -            if !borrowed_locals.contains(*local) { | 
| 306 |  | -                self.trans.kill(*local); | 
| 307 |  | -            } | 
| 308 |  | -        } | 
| 309 |  | -    } | 
| 310 |  | -} | 
0 commit comments