about summary refs log tree commit diff
path: root/compiler/rustc_mir/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir/src')
-rw-r--r--compiler/rustc_mir/src/borrow_check/region_infer/mod.rs29
-rw-r--r--compiler/rustc_mir/src/const_eval/fn_queries.rs2
-rw-r--r--compiler/rustc_mir/src/dataflow/framework/direction.rs146
-rw-r--r--compiler/rustc_mir/src/dataflow/framework/mod.rs65
-rw-r--r--compiler/rustc_mir/src/dataflow/impls/mod.rs149
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/validation.rs3
6 files changed, 248 insertions, 146 deletions
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
index 081125cb625..3dc082a4413 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
@@ -551,7 +551,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         mir_def_id: DefId,
         polonius_output: Option<Rc<PoloniusOutput>>,
     ) -> (Option<ClosureRegionRequirements<'tcx>>, RegionErrors<'tcx>) {
-        self.propagate_constraints(body);
+        self.propagate_constraints(body, infcx.tcx);
 
         let mut errors_buffer = RegionErrors::new();
 
@@ -599,7 +599,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// for each region variable until all the constraints are
     /// satisfied. Note that some values may grow **too** large to be
     /// feasible, but we check this later.
-    fn propagate_constraints(&mut self, _body: &Body<'tcx>) {
+    fn propagate_constraints(&mut self, _body: &Body<'tcx>, tcx: TyCtxt<'tcx>) {
         debug!("propagate_constraints()");
 
         debug!("propagate_constraints: constraints={:#?}", {
@@ -617,7 +617,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // own.
         let constraint_sccs = self.constraint_sccs.clone();
         for scc in constraint_sccs.all_sccs() {
-            self.compute_value_for_scc(scc);
+            self.compute_value_for_scc(scc, tcx);
         }
 
         // Sort the applied member constraints so we can binary search
@@ -629,7 +629,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// computed, by unioning the values of its successors.
     /// Assumes that all successors have been computed already
     /// (which is assured by iterating over SCCs in dependency order).
-    fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex) {
+    fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex, tcx: TyCtxt<'tcx>) {
         let constraint_sccs = self.constraint_sccs.clone();
 
         // Walk each SCC `B` such that `A: B`...
@@ -652,7 +652,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // Now take member constraints into account.
         let member_constraints = self.member_constraints.clone();
         for m_c_i in member_constraints.indices(scc_a) {
-            self.apply_member_constraint(scc_a, m_c_i, member_constraints.choice_regions(m_c_i));
+            self.apply_member_constraint(
+                tcx,
+                scc_a,
+                m_c_i,
+                member_constraints.choice_regions(m_c_i),
+            );
         }
 
         debug!(
@@ -675,6 +680,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// If we make any changes, returns true, else false.
     fn apply_member_constraint(
         &mut self,
+        tcx: TyCtxt<'tcx>,
         scc: ConstraintSccIndex,
         member_constraint_index: NllMemberConstraintIndex,
         choice_regions: &[ty::RegionVid],
@@ -688,12 +694,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             // `impl_trait_in_bindings`, I believe, and we are just
             // opting not to handle it for now. See #61773 for
             // details.
-            bug!(
-                "member constraint for `{:?}` has an option region `{:?}` \
-                 that is not a universal region",
-                self.member_constraints[member_constraint_index].opaque_type_def_id,
-                uh_oh,
+            tcx.sess.delay_span_bug(
+                self.member_constraints[member_constraint_index].definition_span,
+                &format!(
+                    "member constraint for `{:?}` has an option region `{:?}` \
+                     that is not a universal region",
+                    self.member_constraints[member_constraint_index].opaque_type_def_id, uh_oh,
+                ),
             );
+            return false;
         }
 
         // Create a mutable vector of the options. We'll try to winnow
diff --git a/compiler/rustc_mir/src/const_eval/fn_queries.rs b/compiler/rustc_mir/src/const_eval/fn_queries.rs
index b20d89b6e83..aca822a05bd 100644
--- a/compiler/rustc_mir/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_mir/src/const_eval/fn_queries.rs
@@ -50,7 +50,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
             None => {
                 if let Some(stab) = tcx.lookup_stability(def_id) {
                     if stab.level.is_stable() {
-                        tcx.sess.span_err(
+                        tcx.sess.delay_span_bug(
                             tcx.def_span(def_id),
                             "stable const functions must have either `rustc_const_stable` or \
                              `rustc_const_unstable` attribute",
diff --git a/compiler/rustc_mir/src/dataflow/framework/direction.rs b/compiler/rustc_mir/src/dataflow/framework/direction.rs
index 76c48100371..ca2bb6e0bf7 100644
--- a/compiler/rustc_mir/src/dataflow/framework/direction.rs
+++ b/compiler/rustc_mir/src/dataflow/framework/direction.rs
@@ -1,10 +1,10 @@
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::{self, BasicBlock, Location};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::TyCtxt;
 use std::ops::RangeInclusive;
 
 use super::visitor::{ResultsVisitable, ResultsVisitor};
-use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet};
+use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget};
 
 pub trait Direction {
     fn is_forward() -> bool;
@@ -425,8 +425,8 @@ impl Direction for Forward {
 
     fn join_state_into_successors_of<A>(
         analysis: &A,
-        tcx: TyCtxt<'tcx>,
-        body: &mir::Body<'tcx>,
+        _tcx: TyCtxt<'tcx>,
+        _body: &mir::Body<'tcx>,
         dead_unwinds: Option<&BitSet<BasicBlock>>,
         exit_state: &mut A::Domain,
         (bb, bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>),
@@ -489,50 +489,23 @@ impl Direction for Forward {
             }
 
             SwitchInt { ref targets, ref values, ref discr, switch_ty: _ } => {
-                let enum_ = discr
-                    .place()
-                    .and_then(|discr| switch_on_enum_discriminant(tcx, &body, bb_data, discr));
-                match enum_ {
-                    // If this is a switch on an enum discriminant, a custom effect may be applied
-                    // along each outgoing edge.
-                    Some((enum_place, enum_def)) => {
-                        // MIR building adds discriminants to the `values` array in the same order as they
-                        // are yielded by `AdtDef::discriminants`. We rely on this to match each
-                        // discriminant in `values` to its corresponding variant in linear time.
-                        let mut tmp = analysis.bottom_value(body);
-                        let mut discriminants = enum_def.discriminants(tcx);
-                        for (value, target) in values.iter().zip(targets.iter().copied()) {
-                            let (variant_idx, _) =
-                                discriminants.find(|&(_, discr)| discr.val == *value).expect(
-                                    "Order of `AdtDef::discriminants` differed \
-                                         from that of `SwitchInt::values`",
-                                );
-
-                            tmp.clone_from(exit_state);
-                            analysis.apply_discriminant_switch_effect(
-                                &mut tmp,
-                                bb,
-                                enum_place,
-                                enum_def,
-                                variant_idx,
-                            );
-                            propagate(target, &tmp);
-                        }
-
-                        // Move out of `tmp` so we don't accidentally use it below.
-                        std::mem::drop(tmp);
-
-                        // Propagate dataflow state along the "otherwise" edge.
-                        let otherwise = targets.last().copied().unwrap();
-                        propagate(otherwise, exit_state)
-                    }
-
-                    // Otherwise, it's just a normal `SwitchInt`, and every successor sees the same
-                    // exit state.
-                    None => {
-                        for target in targets.iter().copied() {
-                            propagate(target, exit_state);
-                        }
+                let mut applier = SwitchIntEdgeEffectApplier {
+                    exit_state,
+                    targets: targets.as_ref(),
+                    values: values.as_ref(),
+                    propagate,
+                    effects_applied: false,
+                };
+
+                analysis.apply_switch_int_edge_effects(bb, discr, &mut applier);
+
+                let SwitchIntEdgeEffectApplier {
+                    exit_state, mut propagate, effects_applied, ..
+                } = applier;
+
+                if !effects_applied {
+                    for &target in targets.iter() {
+                        propagate(target, exit_state);
                     }
                 }
             }
@@ -540,37 +513,54 @@ impl Direction for Forward {
     }
 }
 
-/// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is
-/// an enum discriminant.
-///
-/// We expect such blocks to have a call to `discriminant` as their last statement like so:
-///   _42 = discriminant(_1)
-///   SwitchInt(_42, ..)
-///
-/// If the basic block matches this pattern, this function returns the place corresponding to the
-/// enum (`_1` in the example above) as well as the `AdtDef` of that enum.
-fn switch_on_enum_discriminant(
-    tcx: TyCtxt<'tcx>,
-    body: &'mir mir::Body<'tcx>,
-    block: &'mir mir::BasicBlockData<'tcx>,
-    switch_on: mir::Place<'tcx>,
-) -> Option<(mir::Place<'tcx>, &'tcx ty::AdtDef)> {
-    match block.statements.last().map(|stmt| &stmt.kind) {
-        Some(mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated))))
-            if *lhs == switch_on =>
-        {
-            match &discriminated.ty(body, tcx).ty.kind() {
-                ty::Adt(def, _) => Some((*discriminated, def)),
-
-                // `Rvalue::Discriminant` is also used to get the active yield point for a
-                // generator, but we do not need edge-specific effects in that case. This may
-                // change in the future.
-                ty::Generator(..) => None,
-
-                t => bug!("`discriminant` called on unexpected type {:?}", t),
-            }
+struct SwitchIntEdgeEffectApplier<'a, D, F> {
+    exit_state: &'a mut D,
+    values: &'a [u128],
+    targets: &'a [BasicBlock],
+    propagate: F,
+
+    effects_applied: bool,
+}
+
+impl<D, F> super::SwitchIntEdgeEffects<D> for SwitchIntEdgeEffectApplier<'_, D, F>
+where
+    D: Clone,
+    F: FnMut(BasicBlock, &D),
+{
+    fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) {
+        assert!(!self.effects_applied);
+
+        let mut tmp = None;
+        for (&value, &target) in self.values.iter().zip(self.targets.iter()) {
+            let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state);
+            apply_edge_effect(tmp, SwitchIntTarget { value: Some(value), target });
+            (self.propagate)(target, tmp);
         }
 
-        _ => None,
+        // Once we get to the final, "otherwise" branch, there is no need to preserve `exit_state`,
+        // so pass it directly to `apply_edge_effect` to save a clone of the dataflow state.
+        let otherwise = self.targets.last().copied().unwrap();
+        apply_edge_effect(self.exit_state, SwitchIntTarget { value: None, target: otherwise });
+        (self.propagate)(otherwise, self.exit_state);
+
+        self.effects_applied = true;
+    }
+}
+
+/// An analogue of `Option::get_or_insert_with` that stores a clone of `val` into `opt`, but uses
+/// the more efficient `clone_from` if `opt` was `Some`.
+///
+/// Returns a mutable reference to the new clone that resides in `opt`.
+//
+// FIXME: Figure out how to express this using `Option::clone_from`, or maybe lift it into the
+// standard library?
+fn opt_clone_from_or_clone<T: Clone>(opt: &'a mut Option<T>, val: &T) -> &'a mut T {
+    if opt.is_some() {
+        let ret = opt.as_mut().unwrap();
+        ret.clone_from(val);
+        ret
+    } else {
+        *opt = Some(val.clone());
+        opt.as_mut().unwrap()
     }
 }
diff --git a/compiler/rustc_mir/src/dataflow/framework/mod.rs b/compiler/rustc_mir/src/dataflow/framework/mod.rs
index eefa1395a62..65c159e6a72 100644
--- a/compiler/rustc_mir/src/dataflow/framework/mod.rs
+++ b/compiler/rustc_mir/src/dataflow/framework/mod.rs
@@ -37,8 +37,7 @@ use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::{BitSet, HybridBitSet};
 use rustc_index::vec::Idx;
 use rustc_middle::mir::{self, BasicBlock, Location};
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_target::abi::VariantIdx;
+use rustc_middle::ty::TyCtxt;
 
 mod cursor;
 mod direction;
@@ -152,6 +151,8 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
     ) {
     }
 
+    /* Edge-specific effects */
+
     /// Updates the current dataflow state with the effect of a successful return from a `Call`
     /// terminator.
     ///
@@ -183,20 +184,28 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
     /// Updates the current dataflow state with the effect of taking a particular branch in a
     /// `SwitchInt` terminator.
     ///
-    /// Much like `apply_call_return_effect`, this effect is only propagated along a single
-    /// outgoing edge from this basic block.
+    /// Unlike the other edge-specific effects, which are allowed to mutate `Self::Domain`
+    /// directly, overriders of this method must pass a callback to
+    /// `SwitchIntEdgeEffects::apply`. The callback will be run once for each outgoing edge and
+    /// will have access to the dataflow state that will be propagated along that edge.
+    ///
+    /// This interface is somewhat more complex than the other visitor-like "effect" methods.
+    /// However, it is both more ergonomic—callers don't need to recompute or cache information
+    /// about a given `SwitchInt` terminator for each one of its edges—and more efficient—the
+    /// engine doesn't need to clone the exit state for a block unless
+    /// `SwitchIntEdgeEffects::apply` is actually called.
     ///
     /// FIXME: This class of effects is not supported for backward dataflow analyses.
-    fn apply_discriminant_switch_effect(
+    fn apply_switch_int_edge_effects(
         &self,
-        _state: &mut Self::Domain,
         _block: BasicBlock,
-        _enum_place: mir::Place<'tcx>,
-        _adt: &ty::AdtDef,
-        _variant: VariantIdx,
+        _discr: &mir::Operand<'tcx>,
+        _apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
     ) {
     }
 
+    /* Extension methods */
+
     /// Creates an `Engine` to find the fixpoint for this dataflow problem.
     ///
     /// You shouldn't need to override this outside this module, since the combination of the
@@ -267,6 +276,8 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
     ) {
     }
 
+    /* Edge-specific effects */
+
     /// See `Analysis::apply_call_return_effect`.
     fn call_return_effect(
         &self,
@@ -286,14 +297,12 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
     ) {
     }
 
-    /// See `Analysis::apply_discriminant_switch_effect`.
-    fn discriminant_switch_effect(
+    /// See `Analysis::apply_switch_int_edge_effects`.
+    fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
         &self,
-        _state: &mut impl GenKill<Self::Idx>,
         _block: BasicBlock,
-        _enum_place: mir::Place<'tcx>,
-        _adt: &ty::AdtDef,
-        _variant: VariantIdx,
+        _discr: &mir::Operand<'tcx>,
+        _edge_effects: &mut impl SwitchIntEdgeEffects<G>,
     ) {
     }
 }
@@ -339,6 +348,8 @@ where
         self.before_terminator_effect(state, terminator, location);
     }
 
+    /* Edge-specific effects */
+
     fn apply_call_return_effect(
         &self,
         state: &mut A::Domain,
@@ -359,17 +370,17 @@ where
         self.yield_resume_effect(state, resume_block, resume_place);
     }
 
-    fn apply_discriminant_switch_effect(
+    fn apply_switch_int_edge_effects(
         &self,
-        state: &mut A::Domain,
         block: BasicBlock,
-        enum_place: mir::Place<'tcx>,
-        adt: &ty::AdtDef,
-        variant: VariantIdx,
+        discr: &mir::Operand<'tcx>,
+        edge_effects: &mut impl SwitchIntEdgeEffects<A::Domain>,
     ) {
-        self.discriminant_switch_effect(state, block, enum_place, adt, variant);
+        self.switch_int_edge_effects(block, discr, edge_effects);
     }
 
+    /* Extension methods */
+
     fn into_engine(
         self,
         tcx: TyCtxt<'tcx>,
@@ -531,5 +542,17 @@ impl EffectIndex {
     }
 }
 
+pub struct SwitchIntTarget {
+    pub value: Option<u128>,
+    pub target: BasicBlock,
+}
+
+/// A type that records the edge-specific effects for a `SwitchInt` terminator.
+pub trait SwitchIntEdgeEffects<D> {
+    /// Calls `apply_edge_effect` for each outgoing edge from a `SwitchInt` terminator and
+    /// records the results.
+    fn apply(&mut self, apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget));
+}
+
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_mir/src/dataflow/impls/mod.rs b/compiler/rustc_mir/src/dataflow/impls/mod.rs
index 1769feaf7a5..d4b9600f766 100644
--- a/compiler/rustc_mir/src/dataflow/impls/mod.rs
+++ b/compiler/rustc_mir/src/dataflow/impls/mod.rs
@@ -6,7 +6,6 @@ use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
 use rustc_middle::mir::{self, Body, Location};
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_target::abi::VariantIdx;
 
 use super::MoveDataParamEnv;
 
@@ -19,6 +18,7 @@ use super::drop_flag_effects_for_function_entry;
 use super::drop_flag_effects_for_location;
 use super::on_lookup_result_bits;
 use crate::dataflow::drop_flag_effects;
+use crate::dataflow::framework::SwitchIntEdgeEffects;
 
 mod borrowed_locals;
 pub(super) mod borrows;
@@ -352,24 +352,46 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
         );
     }
 
-    fn discriminant_switch_effect(
+    fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
         &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _block: mir::BasicBlock,
-        enum_place: mir::Place<'tcx>,
-        _adt: &ty::AdtDef,
-        variant: VariantIdx,
+        block: mir::BasicBlock,
+        discr: &mir::Operand<'tcx>,
+        edge_effects: &mut impl SwitchIntEdgeEffects<G>,
     ) {
-        // Kill all move paths that correspond to variants we know to be inactive along this
-        // particular outgoing edge of a `SwitchInt`.
-        drop_flag_effects::on_all_inactive_variants(
-            self.tcx,
-            self.body,
-            self.move_data(),
-            enum_place,
-            variant,
-            |mpi| trans.kill(mpi),
-        );
+        let enum_ = discr.place().and_then(|discr| {
+            switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr)
+        });
+
+        let (enum_place, enum_def) = match enum_ {
+            Some(x) => x,
+            None => return,
+        };
+
+        let mut discriminants = enum_def.discriminants(self.tcx);
+        edge_effects.apply(|trans, edge| {
+            let value = match edge.value {
+                Some(x) => x,
+                None => return,
+            };
+
+            // MIR building adds discriminants to the `values` array in the same order as they
+            // are yielded by `AdtDef::discriminants`. We rely on this to match each
+            // discriminant in `values` to its corresponding variant in linear time.
+            let (variant, _) = discriminants
+                .find(|&(_, discr)| discr.val == value)
+                .expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`");
+
+            // Kill all move paths that correspond to variants we know to be inactive along this
+            // particular outgoing edge of a `SwitchInt`.
+            drop_flag_effects::on_all_inactive_variants(
+                self.tcx,
+                self.body,
+                self.move_data(),
+                enum_place,
+                variant,
+                |mpi| trans.kill(mpi),
+            );
+        });
     }
 }
 
@@ -441,28 +463,50 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
         );
     }
 
-    fn discriminant_switch_effect(
+    fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
         &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _block: mir::BasicBlock,
-        enum_place: mir::Place<'tcx>,
-        _adt: &ty::AdtDef,
-        variant: VariantIdx,
+        block: mir::BasicBlock,
+        discr: &mir::Operand<'tcx>,
+        edge_effects: &mut impl SwitchIntEdgeEffects<G>,
     ) {
         if !self.mark_inactive_variants_as_uninit {
             return;
         }
 
-        // Mark all move paths that correspond to variants other than this one as maybe
-        // uninitialized (in reality, they are *definitely* uninitialized).
-        drop_flag_effects::on_all_inactive_variants(
-            self.tcx,
-            self.body,
-            self.move_data(),
-            enum_place,
-            variant,
-            |mpi| trans.gen(mpi),
-        );
+        let enum_ = discr.place().and_then(|discr| {
+            switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr)
+        });
+
+        let (enum_place, enum_def) = match enum_ {
+            Some(x) => x,
+            None => return,
+        };
+
+        let mut discriminants = enum_def.discriminants(self.tcx);
+        edge_effects.apply(|trans, edge| {
+            let value = match edge.value {
+                Some(x) => x,
+                None => return,
+            };
+
+            // MIR building adds discriminants to the `values` array in the same order as they
+            // are yielded by `AdtDef::discriminants`. We rely on this to match each
+            // discriminant in `values` to its corresponding variant in linear time.
+            let (variant, _) = discriminants
+                .find(|&(_, discr)| discr.val == value)
+                .expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`");
+
+            // Mark all move paths that correspond to variants other than this one as maybe
+            // uninitialized (in reality, they are *definitely* uninitialized).
+            drop_flag_effects::on_all_inactive_variants(
+                self.tcx,
+                self.body,
+                self.move_data(),
+                enum_place,
+                variant,
+                |mpi| trans.gen(mpi),
+            );
+        });
     }
 }
 
@@ -624,3 +668,42 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
         }
     }
 }
+
+/// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is
+/// an enum discriminant.
+///
+/// We expect such blocks to have a call to `discriminant` as their last statement like so:
+///
+/// ```text
+/// ...
+/// _42 = discriminant(_1)
+/// SwitchInt(_42, ..)
+/// ```
+///
+/// If the basic block matches this pattern, this function returns the place corresponding to the
+/// enum (`_1` in the example above) as well as the `AdtDef` of that enum.
+fn switch_on_enum_discriminant(
+    tcx: TyCtxt<'tcx>,
+    body: &'mir mir::Body<'tcx>,
+    block: &'mir mir::BasicBlockData<'tcx>,
+    switch_on: mir::Place<'tcx>,
+) -> Option<(mir::Place<'tcx>, &'tcx ty::AdtDef)> {
+    match block.statements.last().map(|stmt| &stmt.kind) {
+        Some(mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated))))
+            if *lhs == switch_on =>
+        {
+            match &discriminated.ty(body, tcx).ty.kind() {
+                ty::Adt(def, _) => Some((*discriminated, def)),
+
+                // `Rvalue::Discriminant` is also used to get the active yield point for a
+                // generator, but we do not need edge-specific effects in that case. This may
+                // change in the future.
+                ty::Generator(..) => None,
+
+                t => bug!("`discriminant` called on unexpected type {:?}", t),
+            }
+        }
+
+        _ => None,
+    }
+}
diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index 73725c7b98e..ee6adbc7a45 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -204,9 +204,6 @@ impl Validator<'mir, 'tcx> {
     pub fn check_body(&mut self) {
         let ConstCx { tcx, body, def_id, .. } = *self.ccx;
 
-        // HACK: This function has side-effects???? Make sure we call it.
-        let _ = crate::const_eval::is_min_const_fn(tcx, def_id.to_def_id());
-
         // The local type and predicate checks are not free and only relevant for `const fn`s.
         if self.const_kind() == hir::ConstContext::ConstFn {
             // Prevent const trait methods from being annotated as `stable`.