|
1 | 1 | //! Validates the MIR to ensure that invariants are upheld.
|
2 | 2 |
|
| 3 | +use crate::{ |
| 4 | + dataflow::impls::MaybeStorageLive, dataflow::Analysis, dataflow::ResultsCursor, |
| 5 | + util::storage::AlwaysLiveLocals, |
| 6 | +}; |
| 7 | + |
3 | 8 | use super::{MirPass, MirSource};
|
4 |
| -use rustc_middle::mir::visit::Visitor; |
| 9 | +use rustc_middle::mir::{visit::PlaceContext, visit::Visitor, Local}; |
5 | 10 | use rustc_middle::{
|
6 | 11 | mir::{
|
7 | 12 | AggregateKind, BasicBlock, Body, BorrowKind, Location, MirPhase, Operand, Rvalue,
|
@@ -33,9 +38,18 @@ pub struct Validator {
|
33 | 38 |
|
34 | 39 | impl<'tcx> MirPass<'tcx> for Validator {
|
35 | 40 | fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
|
36 |
| - let param_env = tcx.param_env(source.def_id()); |
| 41 | + let def_id = source.def_id(); |
| 42 | + let param_env = tcx.param_env(def_id); |
37 | 43 | let mir_phase = self.mir_phase;
|
38 |
| - TypeChecker { when: &self.when, source, body, tcx, param_env, mir_phase }.visit_body(body); |
| 44 | + |
| 45 | + let always_live_locals = AlwaysLiveLocals::new(body); |
| 46 | + let storage_liveness = MaybeStorageLive::new(always_live_locals) |
| 47 | + .into_engine(tcx, body, def_id) |
| 48 | + .iterate_to_fixpoint() |
| 49 | + .into_results_cursor(body); |
| 50 | + |
| 51 | + TypeChecker { when: &self.when, source, body, tcx, param_env, mir_phase, storage_liveness } |
| 52 | + .visit_body(body); |
39 | 53 | }
|
40 | 54 | }
|
41 | 55 |
|
@@ -138,6 +152,7 @@ struct TypeChecker<'a, 'tcx> {
|
138 | 152 | tcx: TyCtxt<'tcx>,
|
139 | 153 | param_env: ParamEnv<'tcx>,
|
140 | 154 | mir_phase: MirPhase,
|
| 155 | + storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive>, |
141 | 156 | }
|
142 | 157 |
|
143 | 158 | impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
@@ -210,6 +225,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
210 | 225 | }
|
211 | 226 |
|
212 | 227 | impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
| 228 | + fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) { |
| 229 | + if context.is_use() { |
| 230 | + // Uses of locals must occur while the local's storage is allocated. |
| 231 | + self.storage_liveness.seek_after_primary_effect(location); |
| 232 | + let locals_with_storage = self.storage_liveness.get(); |
| 233 | + if !locals_with_storage.contains(*local) { |
| 234 | + self.fail(location, format!("use of local {:?}, which has no storage here", local)); |
| 235 | + } |
| 236 | + } |
| 237 | + } |
| 238 | + |
213 | 239 | fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
|
214 | 240 | // `Operand::Copy` is only supposed to be used with `Copy` types.
|
215 | 241 | if let Operand::Copy(place) = operand {
|
|
0 commit comments