]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_mir/src/transform/validate.rs
Refactor how SwitchInt stores jump targets
[rust.git] / compiler / rustc_mir / src / transform / validate.rs
index d1a91ae4fc33ae04ef23d075c36f127c8727f710..48477f60ef72e779ec9b6de46cab3d3cfd829970 100644 (file)
@@ -1,23 +1,17 @@
 //! Validates the MIR to ensure that invariants are upheld.
 
-use crate::{
-    dataflow::impls::MaybeStorageLive, dataflow::Analysis, dataflow::ResultsCursor,
-    util::storage::AlwaysLiveLocals,
-};
+use crate::dataflow::impls::MaybeStorageLive;
+use crate::dataflow::{Analysis, ResultsCursor};
+use crate::util::storage::AlwaysLiveLocals;
 
-use super::{MirPass, MirSource};
-use rustc_middle::mir::{visit::PlaceContext, visit::Visitor, Local};
-use rustc_middle::{
-    mir::{
-        AggregateKind, BasicBlock, Body, BorrowKind, Location, MirPhase, Operand, Rvalue,
-        Statement, StatementKind, Terminator, TerminatorKind,
-    },
-    ty::{
-        self,
-        relate::{Relate, RelateResult, TypeRelation},
-        ParamEnv, Ty, TyCtxt,
-    },
+use super::MirPass;
+use rustc_middle::mir::visit::{PlaceContext, Visitor};
+use rustc_middle::mir::{
+    AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, Rvalue,
+    Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo,
 };
+use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
+use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
 
 #[derive(Copy, Clone, Debug)]
 enum EdgeKind {
@@ -37,18 +31,18 @@ pub struct Validator {
 }
 
 impl<'tcx> MirPass<'tcx> for Validator {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        let def_id = source.def_id();
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        let def_id = body.source.def_id();
         let param_env = tcx.param_env(def_id);
         let mir_phase = self.mir_phase;
 
         let always_live_locals = AlwaysLiveLocals::new(body);
         let storage_liveness = MaybeStorageLive::new(always_live_locals)
-            .into_engine(tcx, body, def_id)
+            .into_engine(tcx, body)
             .iterate_to_fixpoint()
             .into_results_cursor(body);
 
-        TypeChecker { when: &self.when, source, body, tcx, param_env, mir_phase, storage_liveness }
+        TypeChecker { when: &self.when, body, tcx, param_env, mir_phase, storage_liveness }
             .visit_body(body);
     }
 }
@@ -147,7 +141,6 @@ fn binders<T>(
 
 struct TypeChecker<'a, 'tcx> {
     when: &'a str,
-    source: MirSource<'tcx>,
     body: &'a Body<'tcx>,
     tcx: TyCtxt<'tcx>,
     param_env: ParamEnv<'tcx>,
@@ -164,7 +157,7 @@ fn fail(&self, location: Location, msg: impl AsRef<str>) {
             span,
             &format!(
                 "broken MIR in {:?} ({}) at {:?}:\n{}",
-                self.source.instance,
+                self.body.source.instance,
                 self.when,
                 location,
                 msg.as_ref()
@@ -236,6 +229,11 @@ fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Locati
         }
     }
 
+    fn visit_var_debug_info(&mut self, _var_debug_info: &VarDebugInfo<'tcx>) {
+        // Debuginfo can contain field projections, which count as a use of the base local. Skip
+        // debuginfo so that we avoid the storage liveness assertion in that case.
+    }
+
     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
         // `Operand::Copy` is only supposed to be used with `Copy` types.
         if let Operand::Copy(place) = operand {
@@ -336,7 +334,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
             TerminatorKind::Goto { target } => {
                 self.check_edge(location, *target, EdgeKind::Normal);
             }
-            TerminatorKind::SwitchInt { targets, values, switch_ty, discr } => {
+            TerminatorKind::SwitchInt { targets, switch_ty, discr } => {
                 let ty = discr.ty(&self.body.local_decls, self.tcx);
                 if ty != *switch_ty {
                     self.fail(
@@ -347,19 +345,10 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                         ),
                     );
                 }
-                if targets.len() != values.len() + 1 {
-                    self.fail(
-                        location,
-                        format!(
-                            "encountered `SwitchInt` terminator with {} values, but {} targets (should be values+1)",
-                            values.len(),
-                            targets.len(),
-                        ),
-                    );
-                }
-                for target in targets {
-                    self.check_edge(location, *target, EdgeKind::Normal);
+                for (_, target) in targets.iter() {
+                    self.check_edge(location, target, EdgeKind::Normal);
                 }
+                self.check_edge(location, targets.otherwise(), EdgeKind::Normal);
             }
             TerminatorKind::Drop { target, unwind, .. } => {
                 self.check_edge(location, *target, EdgeKind::Normal);