about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-11-23 01:13:41 +0000
committerbors <bors@rust-lang.org>2019-11-23 01:13:41 +0000
commit6d523ee501a1ae30428d22ce4fc3c1f720e896e6 (patch)
tree94b996d5eab8f40f1b541501df4ddfddd97000ce /src
parenta449535bbc7912c4adc1bbf2ab2738d0442f212c (diff)
parentb09bb1569b23eaadcf22d7420f1ba9872c1088f7 (diff)
downloadrust-6d523ee501a1ae30428d22ce4fc3c1f720e896e6.tar.gz
rust-6d523ee501a1ae30428d22ce4fc3c1f720e896e6.zip
Auto merge of #66507 - ecstatic-morse:const-if-match, r=oli-obk
Enable `if` and `match` in constants behind a feature flag

This PR is an initial implementation of #49146. It introduces a `const_if_match` feature flag and does the following if it is enabled:
- Allows `Downcast` projections, `SwitchInt` terminators and `FakeRead`s for matched places through the MIR const-checker.
- Allows `if` and `match` expressions through the HIR const-checker.
- Stops converting `&&` to `&` and `||` to `|` in `const` and `static` items.

As a result, the following operations are now allowed in a const context behind the feature flag:
- `if` and `match`
- short circuiting logic operators (`&&` and `||`)
- the `assert` and `debug_assert` macros (if the `const_panic` feature flag is also enabled)

However, the following operations remain forbidden:
- `while`, `loop` and `for` (see #52000)
- the `?` operator (calls `From::from` on its error variant)
- the `assert_eq` and `assert_ne` macros, along with their `debug` variants (calls `fmt::Debug`)

This PR is possible now that we use dataflow for const qualification (see #64470 and #66385).

r? @oli-obk
cc @rust-lang/wg-const-eval @eddyb
Diffstat (limited to 'src')
-rw-r--r--src/doc/unstable-book/src/language-features/const-if-match.md14
-rw-r--r--src/librustc/hir/mod.rs17
-rw-r--r--src/librustc_mir/hair/cx/expr.rs15
-rw-r--r--src/librustc_mir/transform/check_consts/ops.rs10
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs22
-rw-r--r--src/librustc_passes/check_const.rs98
-rw-r--r--src/libsyntax/feature_gate/active.rs3
-rw-r--r--src/libsyntax_pos/symbol.rs1
-rw-r--r--src/test/ui/borrowck/issue-64453.stderr6
-rw-r--r--src/test/ui/consts/const-eval/infinite_loop.stderr7
-rw-r--r--src/test/ui/consts/const-eval/match-test-ptr-null.stderr7
-rw-r--r--src/test/ui/consts/const-if.rs21
-rw-r--r--src/test/ui/consts/const-if.stderr37
-rw-r--r--src/test/ui/consts/const-loop.rs90
-rw-r--r--src/test/ui/consts/const-match-pattern-arm.stderr12
-rw-r--r--src/test/ui/consts/control-flow/assert.both.stderr13
-rw-r--r--src/test/ui/consts/control-flow/assert.if_match.stderr23
-rw-r--r--src/test/ui/consts/control-flow/assert.panic.stderr21
-rw-r--r--src/test/ui/consts/control-flow/assert.rs17
-rw-r--r--src/test/ui/consts/control-flow/assert.stock.stderr21
-rw-r--r--src/test/ui/consts/control-flow/basics.rs43
-rw-r--r--src/test/ui/consts/control-flow/drop-failure.rs35
-rw-r--r--src/test/ui/consts/control-flow/drop-failure.stderr21
-rw-r--r--src/test/ui/consts/control-flow/drop-success.rs24
-rw-r--r--src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr14
-rw-r--r--src/test/ui/consts/control-flow/feature-gate-const-if-match.rs118
-rw-r--r--src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr249
-rw-r--r--src/test/ui/consts/control-flow/interior-mutability.rs27
-rw-r--r--src/test/ui/consts/control-flow/interior-mutability.stderr24
-rw-r--r--src/test/ui/consts/control-flow/issue-46843.if_match.stderr9
-rw-r--r--src/test/ui/consts/control-flow/issue-46843.rs18
-rw-r--r--src/test/ui/consts/control-flow/issue-46843.stock.stderr18
-rw-r--r--src/test/ui/consts/control-flow/issue-50577.if_match.stderr16
-rw-r--r--src/test/ui/consts/control-flow/issue-50577.rs13
-rw-r--r--src/test/ui/consts/control-flow/issue-50577.stock.stderr (renamed from src/test/ui/issues/issue-50577.stderr)22
-rw-r--r--src/test/ui/consts/control-flow/loop.if_match.stderr (renamed from src/test/ui/consts/const-loop.stderr)52
-rw-r--r--src/test/ui/consts/control-flow/loop.rs97
-rw-r--r--src/test/ui/consts/control-flow/loop.stock.stderr134
-rw-r--r--src/test/ui/consts/control-flow/short-circuit-let.rs39
-rw-r--r--src/test/ui/consts/control-flow/short-circuit.if_match.stderr8
-rw-r--r--src/test/ui/consts/control-flow/short-circuit.rs14
-rw-r--r--src/test/ui/consts/control-flow/short-circuit.stock.stderr23
-rw-r--r--src/test/ui/consts/control-flow/single_variant_match_ice.rs27
-rw-r--r--src/test/ui/consts/control-flow/try.rs12
-rw-r--r--src/test/ui/consts/control-flow/try.stderr9
-rw-r--r--src/test/ui/consts/single_variant_match_ice.rs23
-rw-r--r--src/test/ui/consts/single_variant_match_ice.stderr29
-rw-r--r--src/test/ui/enum-discriminant/niche.rs (renamed from src/test/ui/consts/miri_unleashed/enum_discriminants.rs)3
-rw-r--r--src/test/ui/issues/issue-46843.rs13
-rw-r--r--src/test/ui/issues/issue-46843.stderr14
-rw-r--r--src/test/ui/issues/issue-50577.rs9
-rw-r--r--src/test/ui/issues/issue-51714.rs2
-rw-r--r--src/test/ui/issues/issue-51714.stderr2
-rw-r--r--src/test/ui/loops/loop-break-value.rs6
-rw-r--r--src/test/ui/loops/loop-break-value.stderr12
-rw-r--r--src/test/ui/return/return-match-array-const.stderr17
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr17
57 files changed, 1321 insertions, 347 deletions
diff --git a/src/doc/unstable-book/src/language-features/const-if-match.md b/src/doc/unstable-book/src/language-features/const-if-match.md
new file mode 100644
index 00000000000..ee9cfcbd9de
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/const-if-match.md
@@ -0,0 +1,14 @@
+# `const_if_match`
+
+The tracking issue for this feature is: [#49146]
+
+[#49146]: https://github.com/rust-lang/rust/issues/49146
+
+------------------------
+
+Allows for the use of conditionals (`if` and `match`) in a const context.
+Const contexts include `static`, `static mut`, `const`, `const fn`, const
+generics, and array initializers. Enabling this feature flag will also make
+`&&` and `||` function normally in a const-context by removing the hack that
+replaces them with their non-short-circuiting equivalents, `&` and `|`, in a
+`const` or `static`.
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 1f605711c8a..64d22ae9435 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1749,6 +1749,20 @@ pub enum MatchSource {
     AwaitDesugar,
 }
 
+impl MatchSource {
+    pub fn name(self) -> &'static str {
+        use MatchSource::*;
+        match self {
+            Normal => "match",
+            IfDesugar { .. } | IfLetDesugar { .. } => "if",
+            WhileDesugar | WhileLetDesugar => "while",
+            ForLoopDesugar => "for",
+            TryDesugar => "?",
+            AwaitDesugar => ".await",
+        }
+    }
+}
+
 /// The loop type that yielded an `ExprKind::Loop`.
 #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub enum LoopSource {
@@ -1766,8 +1780,7 @@ impl LoopSource {
     pub fn name(self) -> &'static str {
         match self {
             LoopSource::Loop => "loop",
-            LoopSource::While => "while",
-            LoopSource::WhileLet => "while let",
+            LoopSource::While | LoopSource::WhileLet => "while",
             LoopSource::ForLoop => "for",
         }
     }
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index de50755616b..694a3fd04ee 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -341,9 +341,10 @@ fn make_mirror_unadjusted<'a, 'tcx>(
             } else {
                 // FIXME overflow
                 match (op.node, cx.constness) {
-                    // FIXME(eddyb) use logical ops in constants when
-                    // they can handle that kind of control-flow.
-                    (hir::BinOpKind::And, hir::Constness::Const) => {
+                    // Destroy control flow if `#![feature(const_if_match)]` is not enabled.
+                    (hir::BinOpKind::And, hir::Constness::Const)
+                        if !cx.tcx.features().const_if_match =>
+                    {
                         cx.control_flow_destroyed.push((
                             op.span,
                             "`&&` operator".into(),
@@ -354,7 +355,9 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                             rhs: rhs.to_ref(),
                         }
                     }
-                    (hir::BinOpKind::Or, hir::Constness::Const) => {
+                    (hir::BinOpKind::Or, hir::Constness::Const)
+                        if !cx.tcx.features().const_if_match =>
+                    {
                         cx.control_flow_destroyed.push((
                             op.span,
                             "`||` operator".into(),
@@ -366,14 +369,14 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                         }
                     }
 
-                    (hir::BinOpKind::And, hir::Constness::NotConst) => {
+                    (hir::BinOpKind::And, _) => {
                         ExprKind::LogicalOp {
                             op: LogicalOp::And,
                             lhs: lhs.to_ref(),
                             rhs: rhs.to_ref(),
                         }
                     }
-                    (hir::BinOpKind::Or, hir::Constness::NotConst) => {
+                    (hir::BinOpKind::Or, _) => {
                         ExprKind::LogicalOp {
                             op: LogicalOp::Or,
                             lhs: lhs.to_ref(),
diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs
index 80f2925193a..acad56be604 100644
--- a/src/librustc_mir/transform/check_consts/ops.rs
+++ b/src/librustc_mir/transform/check_consts/ops.rs
@@ -52,7 +52,11 @@ pub trait NonConstOp: std::fmt::Debug {
 /// A `Downcast` projection.
 #[derive(Debug)]
 pub struct Downcast;
-impl NonConstOp for Downcast {}
+impl NonConstOp for Downcast {
+    fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
+        Some(tcx.features().const_if_match)
+    }
+}
 
 /// A function call where the callee is a pointer.
 #[derive(Debug)]
@@ -139,6 +143,10 @@ impl NonConstOp for HeapAllocation {
 #[derive(Debug)]
 pub struct IfOrMatch;
 impl NonConstOp for IfOrMatch {
+    fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
+        Some(tcx.features().const_if_match)
+    }
+
     fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
         // This should be caught by the HIR const-checker.
         item.tcx.sess.delay_span_bug(
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 65fc7cd2043..71f13c169d4 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -216,7 +216,9 @@ fn check_statement(
             check_rvalue(tcx, body, def_id, rval, span)
         }
 
-        StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) => {
+        | StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _)
+        if !tcx.features().const_if_match
+        => {
             Err((span, "loops and conditional expressions are not stable in const fn".into()))
         }
 
@@ -267,9 +269,10 @@ fn check_place(
     while let &[ref proj_base @ .., elem] = cursor {
         cursor = proj_base;
         match elem {
-            ProjectionElem::Downcast(..) => {
-                return Err((span, "`match` or `if let` in `const fn` is unstable".into()));
-            }
+            ProjectionElem::Downcast(..) if !tcx.features().const_if_match
+                => return Err((span, "`match` or `if let` in `const fn` is unstable".into())),
+            ProjectionElem::Downcast(_symbol, _variant_index) => {}
+
             ProjectionElem::Field(..) => {
                 let base_ty = Place::ty_from(&place.base, &proj_base, body, tcx).ty;
                 if let Some(def) = base_ty.ty_adt_def() {
@@ -321,10 +324,19 @@ fn check_terminator(
             check_operand(tcx, value, span, def_id, body)
         },
 
-        TerminatorKind::FalseEdges { .. } | TerminatorKind::SwitchInt { .. } => Err((
+        | TerminatorKind::FalseEdges { .. }
+        | TerminatorKind::SwitchInt { .. }
+        if !tcx.features().const_if_match
+        => Err((
             span,
             "loops and conditional expressions are not stable in const fn".into(),
         )),
+
+        TerminatorKind::FalseEdges { .. } => Ok(()),
+        TerminatorKind::SwitchInt { discr, switch_ty: _, values: _, targets: _ } => {
+            check_operand(tcx, discr, span, def_id, body)
+        }
+
         | TerminatorKind::Abort | TerminatorKind::Unreachable => {
             Err((span, "const fn with unreachable code is not stable".into()))
         }
diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs
index 9d37b4bdb76..24bc088e24a 100644
--- a/src/librustc_passes/check_const.rs
+++ b/src/librustc_passes/check_const.rs
@@ -11,16 +11,46 @@ use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
 use rustc::hir::map::Map;
 use rustc::hir;
-use rustc::session::Session;
 use rustc::ty::TyCtxt;
 use rustc::ty::query::Providers;
 use syntax::ast::Mutability;
+use syntax::feature_gate::{emit_feature_err, Features, GateIssue};
 use syntax::span_err;
-use syntax_pos::Span;
+use syntax_pos::{sym, Span};
 use rustc_error_codes::*;
 
 use std::fmt;
 
+/// An expression that is not *always* legal in a const context.
+#[derive(Clone, Copy)]
+enum NonConstExpr {
+    Loop(hir::LoopSource),
+    Match(hir::MatchSource),
+}
+
+impl NonConstExpr {
+    fn name(self) -> &'static str {
+        match self {
+            Self::Loop(src) => src.name(),
+            Self::Match(src) => src.name(),
+        }
+    }
+
+    /// Returns `true` if all feature gates required to enable this expression are turned on, or
+    /// `None` if there is no feature gate corresponding to this expression.
+    fn is_feature_gate_enabled(self, features: &Features) -> Option<bool> {
+        use hir::MatchSource::*;
+        match self {
+            | Self::Match(Normal)
+            | Self::Match(IfDesugar { .. })
+            | Self::Match(IfLetDesugar { .. })
+            => Some(features.const_if_match),
+
+            _ => None,
+        }
+    }
+}
+
 #[derive(Copy, Clone)]
 enum ConstKind {
     Static,
@@ -75,31 +105,51 @@ pub(crate) fn provide(providers: &mut Providers<'_>) {
 
 #[derive(Copy, Clone)]
 struct CheckConstVisitor<'tcx> {
-    sess: &'tcx Session,
-    hir_map: &'tcx Map<'tcx>,
+    tcx: TyCtxt<'tcx>,
     const_kind: Option<ConstKind>,
 }
 
 impl<'tcx> CheckConstVisitor<'tcx> {
     fn new(tcx: TyCtxt<'tcx>) -> Self {
         CheckConstVisitor {
-            sess: &tcx.sess,
-            hir_map: tcx.hir(),
+            tcx,
             const_kind: None,
         }
     }
 
     /// Emits an error when an unsupported expression is found in a const context.
-    fn const_check_violated(&self, bad_op: &str, span: Span) {
-        if self.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
-            self.sess.span_warn(span, "skipping const checks");
-            return;
+    fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
+        match expr.is_feature_gate_enabled(self.tcx.features()) {
+            // Don't emit an error if the user has enabled the requisite feature gates.
+            Some(true) => return,
+
+            // Users of `-Zunleash-the-miri-inside-of-you` must use feature gates when possible.
+            None if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you => {
+                self.tcx.sess.span_warn(span, "skipping const checks");
+                return;
+            }
+
+            _ => {}
         }
 
         let const_kind = self.const_kind
             .expect("`const_check_violated` may only be called inside a const context");
 
-        span_err!(self.sess, span, E0744, "`{}` is not allowed in a `{}`", bad_op, const_kind);
+        let msg = format!("`{}` is not allowed in a `{}`", expr.name(), const_kind);
+        match expr {
+            | NonConstExpr::Match(hir::MatchSource::Normal)
+            | NonConstExpr::Match(hir::MatchSource::IfDesugar { .. })
+            | NonConstExpr::Match(hir::MatchSource::IfLetDesugar { .. })
+            => emit_feature_err(
+                &self.tcx.sess.parse_sess,
+                sym::const_if_match,
+                span,
+                GateIssue::Language,
+                &msg
+            ),
+
+            _ => span_err!(self.tcx.sess, span, E0744, "{}", msg),
+        }
     }
 
     /// Saves the parent `const_kind` before calling `f` and restores it afterwards.
@@ -113,7 +163,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
 
 impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.hir_map)
+        NestedVisitorMap::OnlyBodies(&self.tcx.hir())
     }
 
     fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
@@ -122,7 +172,7 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
     }
 
     fn visit_body(&mut self, body: &'tcx hir::Body) {
-        let kind = ConstKind::for_body(body, self.hir_map);
+        let kind = ConstKind::for_body(body, self.tcx.hir());
         self.recurse_into(kind, |this| hir::intravisit::walk_body(this, body));
     }
 
@@ -132,24 +182,22 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
             _ if self.const_kind.is_none() => {}
 
             hir::ExprKind::Loop(_, _, source) => {
-                self.const_check_violated(source.name(), e.span);
+                self.const_check_violated(NonConstExpr::Loop(*source), e.span);
             }
 
             hir::ExprKind::Match(_, _, source) => {
-                use hir::MatchSource::*;
-
-                let op = match source {
-                    Normal => Some("match"),
-                    IfDesugar { .. } | IfLetDesugar { .. } => Some("if"),
-                    TryDesugar => Some("?"),
-                    AwaitDesugar => Some(".await"),
-
+                let non_const_expr = match source {
                     // These are handled by `ExprKind::Loop` above.
-                    WhileDesugar | WhileLetDesugar | ForLoopDesugar => None,
+                    | hir::MatchSource::WhileDesugar
+                    | hir::MatchSource::WhileLetDesugar
+                    | hir::MatchSource::ForLoopDesugar
+                    => None,
+
+                    _ => Some(NonConstExpr::Match(*source)),
                 };
 
-                if let Some(op) = op {
-                    self.const_check_violated(op, e.span);
+                if let Some(expr) = non_const_expr {
+                    self.const_check_violated(expr, e.span);
                 }
             }
 
diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs
index bd029514a95..fa0ab90c702 100644
--- a/src/libsyntax/feature_gate/active.rs
+++ b/src/libsyntax/feature_gate/active.rs
@@ -529,6 +529,9 @@ declare_features! (
     /// Allows using the `#[register_attr]` attribute.
     (active, register_tool, "1.41.0", Some(66079), None),
 
+    /// Allows the use of `if` and `match` in constants.
+    (active, const_if_match, "1.41.0", Some(49146), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 23ee972529a..d20d520ac55 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -203,6 +203,7 @@ symbols! {
         const_fn,
         const_fn_union,
         const_generics,
+        const_if_match,
         const_indexing,
         const_in_array_repeat_expressions,
         const_let,
diff --git a/src/test/ui/borrowck/issue-64453.stderr b/src/test/ui/borrowck/issue-64453.stderr
index f437880a165..0b66426aa2a 100644
--- a/src/test/ui/borrowck/issue-64453.stderr
+++ b/src/test/ui/borrowck/issue-64453.stderr
@@ -1,11 +1,13 @@
-error[E0744]: `match` is not allowed in a `static`
+error[E0658]: `match` is not allowed in a `static`
   --> $DIR/issue-64453.rs:4:31
    |
 LL | static settings_dir: String = format!("");
    |                               ^^^^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0744`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/const-eval/infinite_loop.stderr b/src/test/ui/consts/const-eval/infinite_loop.stderr
index 2af6af95c55..de2624d7f7a 100644
--- a/src/test/ui/consts/const-eval/infinite_loop.stderr
+++ b/src/test/ui/consts/const-eval/infinite_loop.stderr
@@ -9,11 +9,14 @@ LL | |
 LL | |         }
    | |_________^
 
-error[E0744]: `if` is not allowed in a `const`
+error[E0658]: `if` is not allowed in a `const`
   --> $DIR/infinite_loop.rs:9:17
    |
 LL |             n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 warning: Constant evaluating a complex constant, this might take some time
   --> $DIR/infinite_loop.rs:4:18
@@ -36,5 +39,5 @@ LL |             n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0080, E0744.
+Some errors have detailed explanations: E0080, E0658, E0744.
 For more information about an error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr
index 587dca4c1f2..d1ad2261dc2 100644
--- a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr
+++ b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr
@@ -1,4 +1,4 @@
-error[E0744]: `match` is not allowed in a `const`
+error[E0658]: `match` is not allowed in a `const`
   --> $DIR/match-test-ptr-null.rs:6:9
    |
 LL | /         match &1 as *const i32 as usize {
@@ -9,6 +9,9 @@ LL | |             0 => 42,
 LL | |             n => n,
 LL | |         }
    | |_________^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: casting pointers to integers in constants is unstable
   --> $DIR/match-test-ptr-null.rs:6:15
@@ -27,5 +30,5 @@ LL |         match &1 as *const i32 as usize {
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0080, E0658, E0744.
+Some errors have detailed explanations: E0080, E0658.
 For more information about an error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-if.rs b/src/test/ui/consts/const-if.rs
deleted file mode 100644
index 94cce60453d..00000000000
--- a/src/test/ui/consts/const-if.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-const _: i32 = if true { //~ ERROR `if` is not allowed in a `const`
-    5
-} else {
-    6
-};
-
-const _: i32 = match 1 { //~ ERROR `match` is not allowed in a `const`
-    2 => 3,
-    4 => 5,
-    _ => 0,
-};
-
-const fn foo() -> i32 {
-    if true { 5 } else { 6 } //~ ERROR `if` is not allowed in a `const fn`
-}
-
-const fn bar() -> i32 {
-    match 0 { 1 => 2, _ => 0 } //~ ERROR `match` is not allowed in a `const fn`
-}
-
-fn main() {}
diff --git a/src/test/ui/consts/const-if.stderr b/src/test/ui/consts/const-if.stderr
deleted file mode 100644
index 6fb2a0e1501..00000000000
--- a/src/test/ui/consts/const-if.stderr
+++ /dev/null
@@ -1,37 +0,0 @@
-error[E0744]: `if` is not allowed in a `const`
-  --> $DIR/const-if.rs:1:16
-   |
-LL |   const _: i32 = if true {
-   |  ________________^
-LL | |     5
-LL | | } else {
-LL | |     6
-LL | | };
-   | |_^
-
-error[E0744]: `match` is not allowed in a `const`
-  --> $DIR/const-if.rs:7:16
-   |
-LL |   const _: i32 = match 1 {
-   |  ________________^
-LL | |     2 => 3,
-LL | |     4 => 5,
-LL | |     _ => 0,
-LL | | };
-   | |_^
-
-error[E0744]: `if` is not allowed in a `const fn`
-  --> $DIR/const-if.rs:14:5
-   |
-LL |     if true { 5 } else { 6 }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0744]: `match` is not allowed in a `const fn`
-  --> $DIR/const-if.rs:18:5
-   |
-LL |     match 0 { 1 => 2, _ => 0 }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/consts/const-loop.rs b/src/test/ui/consts/const-loop.rs
deleted file mode 100644
index b0fe5e320f4..00000000000
--- a/src/test/ui/consts/const-loop.rs
+++ /dev/null
@@ -1,90 +0,0 @@
-const _: () = loop {}; //~ ERROR `loop` is not allowed in a `const`
-
-static FOO: i32 = loop { break 4; }; //~ ERROR `loop` is not allowed in a `static`
-
-const fn foo() {
-    loop {} //~ ERROR `loop` is not allowed in a `const fn`
-}
-
-pub trait Foo {
-    const BAR: i32 = loop { break 4; }; //~ ERROR `loop` is not allowed in a `const`
-}
-
-impl Foo for () {
-    const BAR: i32 = loop { break 4; }; //~ ERROR `loop` is not allowed in a `const`
-}
-
-fn non_const_outside() {
-    const fn const_inside() {
-        loop {} //~ ERROR `loop` is not allowed in a `const fn`
-    }
-}
-
-const fn const_outside() {
-    fn non_const_inside() {
-        loop {}
-    }
-}
-
-fn main() {
-    let x = [0; {
-        while false {}
-        //~^ ERROR `while` is not allowed in a `const`
-        4
-    }];
-}
-
-const _: i32 = {
-    let mut x = 0;
-
-    while x < 4 { //~ ERROR `while` is not allowed in a `const`
-        x += 1;
-    }
-
-    while x < 8 { //~ ERROR `while` is not allowed in a `const`
-        x += 1;
-    }
-
-    x
-};
-
-const _: i32 = {
-    let mut x = 0;
-
-    for i in 0..4 { //~ ERROR `for` is not allowed in a `const`
-        x += i;
-    }
-
-    for i in 0..4 { //~ ERROR `for` is not allowed in a `const`
-        x += i;
-    }
-
-    x
-};
-
-const _: i32 = {
-    let mut x = 0;
-
-    loop { //~ ERROR `loop` is not allowed in a `const`
-        x += 1;
-        if x == 4 { //~ ERROR `if` is not allowed in a `const`
-            break;
-        }
-    }
-
-    loop { //~ ERROR `loop` is not allowed in a `const`
-        x += 1;
-        if x == 8 { //~ ERROR `if` is not allowed in a `const`
-            break;
-        }
-    }
-
-    x
-};
-
-const _: i32 = {
-    let mut x = 0;
-    while let None = Some(x) { } //~ ERROR `while let` is not allowed in a `const`
-    while let None = Some(x) { } //~ ERROR `while let` is not allowed in a `const`
-    x
-};
diff --git a/src/test/ui/consts/const-match-pattern-arm.stderr b/src/test/ui/consts/const-match-pattern-arm.stderr
index 57ef349a377..4e7713f1422 100644
--- a/src/test/ui/consts/const-match-pattern-arm.stderr
+++ b/src/test/ui/consts/const-match-pattern-arm.stderr
@@ -1,4 +1,4 @@
-error[E0744]: `match` is not allowed in a `const`
+error[E0658]: `match` is not allowed in a `const`
   --> $DIR/const-match-pattern-arm.rs:3:17
    |
 LL |   const x: bool = match Some(true) {
@@ -7,8 +7,11 @@ LL | |     Some(value) => true,
 LL | |     _ => false
 LL | | };
    | |_^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-error[E0744]: `match` is not allowed in a `const`
+error[E0658]: `match` is not allowed in a `const`
   --> $DIR/const-match-pattern-arm.rs:9:5
    |
 LL | /     match Some(true) {
@@ -16,7 +19,10 @@ LL | |         Some(value) => true,
 LL | |         _ => false
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0744`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/control-flow/assert.both.stderr b/src/test/ui/consts/control-flow/assert.both.stderr
new file mode 100644
index 00000000000..44769175f0e
--- /dev/null
+++ b/src/test/ui/consts/control-flow/assert.both.stderr
@@ -0,0 +1,13 @@
+error: any use of this value will cause an error
+  --> $DIR/assert.rs:12:15
+   |
+LL | const _: () = assert!(false);
+   | --------------^^^^^^^^^^^^^^-
+   |               |
+   |               the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:12:15
+   |
+   = note: `#[deny(const_err)]` on by default
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/consts/control-flow/assert.if_match.stderr b/src/test/ui/consts/control-flow/assert.if_match.stderr
new file mode 100644
index 00000000000..9c8963f6c7b
--- /dev/null
+++ b/src/test/ui/consts/control-flow/assert.if_match.stderr
@@ -0,0 +1,23 @@
+error[E0658]: panicking in constants is unstable
+  --> $DIR/assert.rs:8:15
+   |
+LL | const _: () = assert!(true);
+   |               ^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/51999
+   = help: add `#![feature(const_panic)]` to the crate attributes to enable
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error[E0658]: panicking in constants is unstable
+  --> $DIR/assert.rs:12:15
+   |
+LL | const _: () = assert!(false);
+   |               ^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/51999
+   = help: add `#![feature(const_panic)]` to the crate attributes to enable
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/control-flow/assert.panic.stderr b/src/test/ui/consts/control-flow/assert.panic.stderr
new file mode 100644
index 00000000000..11550bf801a
--- /dev/null
+++ b/src/test/ui/consts/control-flow/assert.panic.stderr
@@ -0,0 +1,21 @@
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/assert.rs:8:15
+   |
+LL | const _: () = assert!(true);
+   |               ^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/assert.rs:12:15
+   |
+LL | const _: () = assert!(false);
+   |               ^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/control-flow/assert.rs b/src/test/ui/consts/control-flow/assert.rs
new file mode 100644
index 00000000000..2da42d5084b
--- /dev/null
+++ b/src/test/ui/consts/control-flow/assert.rs
@@ -0,0 +1,17 @@
+// Test that `assert` works only when both `const_if_match` and `const_panic` are enabled.
+
+// revisions: stock if_match panic both
+
+#![cfg_attr(any(both, if_match), feature(const_if_match))]
+#![cfg_attr(any(both, panic), feature(const_panic))]
+
+const _: () = assert!(true);
+//[stock,panic]~^ ERROR `if` is not allowed in a `const`
+//[if_match]~^^ ERROR panicking in constants is unstable
+
+const _: () = assert!(false);
+//[stock,panic]~^ ERROR `if` is not allowed in a `const`
+//[if_match]~^^ ERROR panicking in constants is unstable
+//[both]~^^^ ERROR any use of this value will cause an error
+
+fn main() {}
diff --git a/src/test/ui/consts/control-flow/assert.stock.stderr b/src/test/ui/consts/control-flow/assert.stock.stderr
new file mode 100644
index 00000000000..11550bf801a
--- /dev/null
+++ b/src/test/ui/consts/control-flow/assert.stock.stderr
@@ -0,0 +1,21 @@
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/assert.rs:8:15
+   |
+LL | const _: () = assert!(true);
+   |               ^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/assert.rs:12:15
+   |
+LL | const _: () = assert!(false);
+   |               ^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/control-flow/basics.rs b/src/test/ui/consts/control-flow/basics.rs
new file mode 100644
index 00000000000..8bd1929956f
--- /dev/null
+++ b/src/test/ui/consts/control-flow/basics.rs
@@ -0,0 +1,43 @@
+// Test basic functionality of `if` and `match` in a const context.
+
+// run-pass
+
+#![feature(const_panic)]
+#![feature(const_if_match)]
+
+const X: u32 = 4;
+const Y: u32 = 5;
+
+const ABS_DIFF: u32 = if X < Y {
+    Y - X
+} else {
+    X - Y
+};
+
+const fn abs_diff(a: u32, b: u32) -> u32 {
+    match (a, b) {
+        (big, little) if big > little => big - little,
+        (little, big) => big - little,
+    }
+}
+
+const fn gcd(a: u32, b: u32) -> u32 {
+    if b == 0 {
+        return a;
+    }
+
+    gcd(b, a % b)
+}
+
+fn main() {
+    const _: () = assert!(abs_diff(4, 5) == abs_diff(5, 4));
+    assert_eq!(abs_diff(4, 5), abs_diff(5, 4));
+
+    const _: () = assert!(ABS_DIFF == abs_diff(5, 4));
+    assert_eq!(ABS_DIFF, abs_diff(5, 4));
+
+    const _: () = assert!(gcd(48, 18) == 6);
+    const _: () = assert!(gcd(18, 48) == 6);
+    assert_eq!(gcd(48, 18), 6);
+    assert_eq!(gcd(18, 48), 6);
+}
diff --git a/src/test/ui/consts/control-flow/drop-failure.rs b/src/test/ui/consts/control-flow/drop-failure.rs
new file mode 100644
index 00000000000..c6bea89e6e6
--- /dev/null
+++ b/src/test/ui/consts/control-flow/drop-failure.rs
@@ -0,0 +1,35 @@
+#![feature(const_if_match)]
+
+// `x` is *not* always moved into the final value may be dropped inside the initializer.
+const _: Option<Vec<i32>> = {
+    let y: Option<Vec<i32>> = None;
+    let x = Some(Vec::new());
+    //~^ ERROR destructors cannot be evaluated at compile-time
+
+    if true {
+        x
+    } else {
+        y
+    }
+};
+
+// We only clear `NeedsDrop` if a local is moved from in entirely. This is a shortcoming of the
+// existing analysis.
+const _: Vec<i32> = {
+    let vec_tuple = (Vec::new(),);
+    //~^ ERROR destructors cannot be evaluated at compile-time
+
+    vec_tuple.0
+};
+
+// This applies to single-field enum variants as well.
+const _: Vec<i32> = {
+    let x: Result<_, Vec<i32>> = Ok(Vec::new());
+    //~^ ERROR destructors cannot be evaluated at compile-time
+
+    match x {
+        Ok(x) | Err(x) => x,
+    }
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/control-flow/drop-failure.stderr b/src/test/ui/consts/control-flow/drop-failure.stderr
new file mode 100644
index 00000000000..35ceb3b2770
--- /dev/null
+++ b/src/test/ui/consts/control-flow/drop-failure.stderr
@@ -0,0 +1,21 @@
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop-failure.rs:6:9
+   |
+LL |     let x = Some(Vec::new());
+   |         ^ constants cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop-failure.rs:19:9
+   |
+LL |     let vec_tuple = (Vec::new(),);
+   |         ^^^^^^^^^ constants cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop-failure.rs:27:9
+   |
+LL |     let x: Result<_, Vec<i32>> = Ok(Vec::new());
+   |         ^ constants cannot evaluate destructors
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0493`.
diff --git a/src/test/ui/consts/control-flow/drop-success.rs b/src/test/ui/consts/control-flow/drop-success.rs
new file mode 100644
index 00000000000..92b3f6ec92e
--- /dev/null
+++ b/src/test/ui/consts/control-flow/drop-success.rs
@@ -0,0 +1,24 @@
+// run-pass
+
+#![feature(const_if_match)]
+
+// `x` is always moved into the final value and is not dropped inside the initializer.
+const _: Option<Vec<i32>> = {
+    let y: Option<Vec<i32>> = None;
+    let x = Some(Vec::new());
+
+    if true {
+        x
+    } else {
+        x
+    }
+};
+
+const _: Option<Vec<i32>> = {
+    let x = Some(Vec::new());
+    match () {
+        () => x,
+    }
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr b/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr
new file mode 100644
index 00000000000..21e3f2af15a
--- /dev/null
+++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr
@@ -0,0 +1,14 @@
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/feature-gate-const-if-match.rs:108:1
+   |
+LL | / fn main() {
+LL | |     let _ = [0; {
+LL | |         let x = if false { 0 } else { 1 };
+LL | |
+...  |
+LL | |     }];
+LL | | }
+   | |_^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs b/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs
new file mode 100644
index 00000000000..00576d50ac6
--- /dev/null
+++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs
@@ -0,0 +1,118 @@
+// Ensure that `if`, `if let` and `match` are only allowed in the various const contexts when
+// `#![feature(const_if_match)]` is enabled. When the feature gate is removed, the `#[rustc_error]`
+// on `main` should be removed and this test converted to `check-pass`.
+
+// revisions: stock if_match
+
+#![feature(rustc_attrs)]
+#![cfg_attr(if_match, feature(const_if_match))]
+
+const _: i32 = if true { //[stock]~ ERROR `if` is not allowed in a `const`
+    5
+} else {
+    6
+};
+
+const _: i32 = if let Some(true) = Some(false) { //[stock]~ ERROR `if` is not allowed in a `const`
+    0
+} else {
+    1
+};
+
+const _: i32 = match 1 { //[stock]~ ERROR `match` is not allowed in a `const`
+    2 => 3,
+    4 => 5,
+    _ => 0,
+};
+
+static FOO: i32 = {
+    let x = if true { 0 } else { 1 };
+    //[stock]~^ ERROR `if` is not allowed in a `static`
+    let x = match x { 0 => 1, _ => 0 };
+    //[stock]~^ ERROR `match` is not allowed in a `static`
+    if let Some(x) = Some(x) { x } else { 1 }
+    //[stock]~^ ERROR `if` is not allowed in a `static`
+};
+
+static mut BAR: i32 = {
+    let x = if true { 0 } else { 1 };
+    //[stock]~^ ERROR `if` is not allowed in a `static mut`
+    let x = match x { 0 => 1, _ => 0 };
+    //[stock]~^ ERROR `match` is not allowed in a `static mut`
+    if let Some(x) = Some(x) { x } else { 1 }
+    //[stock]~^ ERROR `if` is not allowed in a `static mut`
+};
+
+const fn if_() -> i32 {
+    if true { 5 } else { 6 } //[stock]~ ERROR `if` is not allowed in a `const fn`
+}
+
+const fn if_let(a: Option<bool>) -> i32 {
+    if let Some(true) = a { //[stock]~ ERROR `if` is not allowed in a `const fn`
+        0
+    } else {
+        1
+    }
+}
+
+const fn match_(i: i32) -> i32 {
+    match i { //[stock]~ ERROR `match` is not allowed in a `const fn`
+        i if i > 10 => i,
+        1 => 2,
+        _ => 0
+    }
+}
+
+pub trait Foo {
+    const IF: i32 = if true { 5 } else { 6 };
+    //[stock]~^ ERROR `if` is not allowed in a `const`
+
+    const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
+    //[stock]~^ ERROR `if` is not allowed in a `const`
+
+    const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
+    //[stock]~^ ERROR `match` is not allowed in a `const`
+}
+
+impl Foo for () {
+    const IF: i32 = if true { 5 } else { 6 };
+    //[stock]~^ ERROR `if` is not allowed in a `const`
+
+    const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
+    //[stock]~^ ERROR `if` is not allowed in a `const`
+
+    const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
+    //[stock]~^ ERROR `match` is not allowed in a `const`
+}
+
+fn non_const_outside() {
+    const fn const_inside(y: bool) -> i32 {
+        let x = if y { 0 } else { 1 };
+        //[stock]~^ ERROR `if` is not allowed in a `const fn`
+        let x = match x { 0 => 1, _ => 0 };
+        //[stock]~^ ERROR `match` is not allowed in a `const fn`
+        if let Some(x) = Some(x) { x } else { 1 }
+        //[stock]~^ ERROR `if` is not allowed in a `const fn`
+    }
+}
+
+const fn const_outside() {
+    fn non_const_inside(y: bool) -> i32 {
+        let x = if y { 0 } else { 1 };
+        let x = match x { 0 => 1, _ => 0 };
+        if let Some(x) = Some(x) { x } else { 1 }
+    }
+}
+
+#[rustc_error]
+fn main() { //[if_match]~ ERROR fatal error triggered by #[rustc_error]
+    let _ = [0; {
+        let x = if false { 0 } else { 1 };
+        //[stock]~^ ERROR `if` is not allowed in a `const`
+        let x = match x { 0 => 1, _ => 0 };
+        //[stock]~^ ERROR `match` is not allowed in a `const`
+        if let Some(x) = Some(x) { x } else { 1 }
+        //[stock]~^ ERROR `if` is not allowed in a `const`
+        //[stock]~| ERROR constant contains unimplemented expression type
+    }];
+}
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr b/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr
new file mode 100644
index 00000000000..d3c6a51923f
--- /dev/null
+++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr
@@ -0,0 +1,249 @@
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/feature-gate-const-if-match.rs:10:16
+   |
+LL |   const _: i32 = if true {
+   |  ________________^
+LL | |     5
+LL | | } else {
+LL | |     6
+LL | | };
+   | |_^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/feature-gate-const-if-match.rs:16:16
+   |
+LL |   const _: i32 = if let Some(true) = Some(false) {
+   |  ________________^
+LL | |     0
+LL | | } else {
+LL | |     1
+LL | | };
+   | |_^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `match` is not allowed in a `const`
+  --> $DIR/feature-gate-const-if-match.rs:22:16
+   |
+LL |   const _: i32 = match 1 {
+   |  ________________^
+LL | |     2 => 3,
+LL | |     4 => 5,
+LL | |     _ => 0,
+LL | | };
+   | |_^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `static`
+  --> $DIR/feature-gate-const-if-match.rs:29:13
+   |
+LL |     let x = if true { 0 } else { 1 };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `match` is not allowed in a `static`
+  --> $DIR/feature-gate-const-if-match.rs:31:13
+   |
+LL |     let x = match x { 0 => 1, _ => 0 };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `static`
+  --> $DIR/feature-gate-const-if-match.rs:33:5
+   |
+LL |     if let Some(x) = Some(x) { x } else { 1 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `static mut`
+  --> $DIR/feature-gate-const-if-match.rs:38:13
+   |
+LL |     let x = if true { 0 } else { 1 };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `match` is not allowed in a `static mut`
+  --> $DIR/feature-gate-const-if-match.rs:40:13
+   |
+LL |     let x = match x { 0 => 1, _ => 0 };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `static mut`
+  --> $DIR/feature-gate-const-if-match.rs:42:5
+   |
+LL |     if let Some(x) = Some(x) { x } else { 1 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `const fn`
+  --> $DIR/feature-gate-const-if-match.rs:47:5
+   |
+LL |     if true { 5 } else { 6 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `const fn`
+  --> $DIR/feature-gate-const-if-match.rs:51:5
+   |
+LL | /     if let Some(true) = a {
+LL | |         0
+LL | |     } else {
+LL | |         1
+LL | |     }
+   | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `match` is not allowed in a `const fn`
+  --> $DIR/feature-gate-const-if-match.rs:59:5
+   |
+LL | /     match i {
+LL | |         i if i > 10 => i,
+LL | |         1 => 2,
+LL | |         _ => 0
+LL | |     }
+   | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `const fn`
+  --> $DIR/feature-gate-const-if-match.rs:90:17
+   |
+LL |         let x = if y { 0 } else { 1 };
+   |                 ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `match` is not allowed in a `const fn`
+  --> $DIR/feature-gate-const-if-match.rs:92:17
+   |
+LL |         let x = match x { 0 => 1, _ => 0 };
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `const fn`
+  --> $DIR/feature-gate-const-if-match.rs:94:9
+   |
+LL |         if let Some(x) = Some(x) { x } else { 1 }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/feature-gate-const-if-match.rs:110:17
+   |
+LL |         let x = if false { 0 } else { 1 };
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `match` is not allowed in a `const`
+  --> $DIR/feature-gate-const-if-match.rs:112:17
+   |
+LL |         let x = match x { 0 => 1, _ => 0 };
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/feature-gate-const-if-match.rs:114:9
+   |
+LL |         if let Some(x) = Some(x) { x } else { 1 }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/feature-gate-const-if-match.rs:67:21
+   |
+LL |     const IF: i32 = if true { 5 } else { 6 };
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/feature-gate-const-if-match.rs:70:25
+   |
+LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `match` is not allowed in a `const`
+  --> $DIR/feature-gate-const-if-match.rs:73:24
+   |
+LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/feature-gate-const-if-match.rs:78:21
+   |
+LL |     const IF: i32 = if true { 5 } else { 6 };
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/feature-gate-const-if-match.rs:81:25
+   |
+LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `match` is not allowed in a `const`
+  --> $DIR/feature-gate-const-if-match.rs:84:24
+   |
+LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0019]: constant contains unimplemented expression type
+  --> $DIR/feature-gate-const-if-match.rs:114:21
+   |
+LL |         if let Some(x) = Some(x) { x } else { 1 }
+   |                     ^
+
+error: aborting due to 25 previous errors
+
+Some errors have detailed explanations: E0019, E0658.
+For more information about an error, try `rustc --explain E0019`.
diff --git a/src/test/ui/consts/control-flow/interior-mutability.rs b/src/test/ui/consts/control-flow/interior-mutability.rs
new file mode 100644
index 00000000000..fcced75fcb0
--- /dev/null
+++ b/src/test/ui/consts/control-flow/interior-mutability.rs
@@ -0,0 +1,27 @@
+// Ensure that *any* assignment to the return place of a value with interior mutability
+// disqualifies it from promotion.
+
+#![feature(const_if_match)]
+
+use std::cell::Cell;
+
+const X: Option<Cell<i32>> = {
+    let mut x = None;
+    if false {
+        x = Some(Cell::new(4));
+    }
+    x
+};
+
+const Y: Option<Cell<i32>> = {
+    let mut y = Some(Cell::new(4));
+    if true {
+        y = None;
+    }
+    y
+};
+
+fn main() {
+    let x: &'static _ = &X; //~ ERROR temporary value dropped while borrowed
+    let y: &'static _ = &Y; //~ ERROR temporary value dropped while borrowed
+}
diff --git a/src/test/ui/consts/control-flow/interior-mutability.stderr b/src/test/ui/consts/control-flow/interior-mutability.stderr
new file mode 100644
index 00000000000..49e8ea3ade7
--- /dev/null
+++ b/src/test/ui/consts/control-flow/interior-mutability.stderr
@@ -0,0 +1,24 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/interior-mutability.rs:25:26
+   |
+LL |     let x: &'static _ = &X;
+   |            ----------    ^ creates a temporary which is freed while still in use
+   |            |
+   |            type annotation requires that borrow lasts for `'static`
+LL |     let y: &'static _ = &Y;
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/interior-mutability.rs:26:26
+   |
+LL |     let y: &'static _ = &Y;
+   |            ----------    ^ creates a temporary which is freed while still in use
+   |            |
+   |            type annotation requires that borrow lasts for `'static`
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/src/test/ui/consts/control-flow/issue-46843.if_match.stderr b/src/test/ui/consts/control-flow/issue-46843.if_match.stderr
new file mode 100644
index 00000000000..4c64d7dee8c
--- /dev/null
+++ b/src/test/ui/consts/control-flow/issue-46843.if_match.stderr
@@ -0,0 +1,9 @@
+error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/issue-46843.rs:11:26
+   |
+LL | pub const Q: i32 = match non_const() {
+   |                          ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/src/test/ui/consts/control-flow/issue-46843.rs b/src/test/ui/consts/control-flow/issue-46843.rs
new file mode 100644
index 00000000000..1fc91015ffa
--- /dev/null
+++ b/src/test/ui/consts/control-flow/issue-46843.rs
@@ -0,0 +1,18 @@
+// revisions: stock if_match
+
+#![cfg_attr(if_match, feature(const_if_match))]
+
+enum Thing { This, That }
+
+fn non_const() -> Thing {
+    Thing::This
+}
+
+pub const Q: i32 = match non_const() {
+    //[stock]~^ ERROR `match` is not allowed in a `const`
+    //[if_match]~^^ ERROR calls in constants are limited to constant functions
+    Thing::This => 1,
+    Thing::That => 0
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/control-flow/issue-46843.stock.stderr b/src/test/ui/consts/control-flow/issue-46843.stock.stderr
new file mode 100644
index 00000000000..b6f38f8ed95
--- /dev/null
+++ b/src/test/ui/consts/control-flow/issue-46843.stock.stderr
@@ -0,0 +1,18 @@
+error[E0658]: `match` is not allowed in a `const`
+  --> $DIR/issue-46843.rs:11:20
+   |
+LL |   pub const Q: i32 = match non_const() {
+   |  ____________________^
+LL | |
+LL | |
+LL | |     Thing::This => 1,
+LL | |     Thing::That => 0
+LL | | };
+   | |_^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/control-flow/issue-50577.if_match.stderr b/src/test/ui/consts/control-flow/issue-50577.if_match.stderr
new file mode 100644
index 00000000000..79572c41702
--- /dev/null
+++ b/src/test/ui/consts/control-flow/issue-50577.if_match.stderr
@@ -0,0 +1,16 @@
+error[E0317]: if may be missing an else clause
+  --> $DIR/issue-50577.rs:7:16
+   |
+LL |         Drop = assert_eq!(1, 1)
+   |                ^^^^^^^^^^^^^^^^
+   |                |
+   |                expected `()`, found `isize`
+   |                found here
+   |
+   = note: `if` expressions without `else` evaluate to `()`
+   = help: consider adding an `else` block that evaluates to the expected type
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0317`.
diff --git a/src/test/ui/consts/control-flow/issue-50577.rs b/src/test/ui/consts/control-flow/issue-50577.rs
new file mode 100644
index 00000000000..7906ec4dc68
--- /dev/null
+++ b/src/test/ui/consts/control-flow/issue-50577.rs
@@ -0,0 +1,13 @@
+// revisions: stock if_match
+
+#![cfg_attr(if_match, feature(const_if_match))]
+
+fn main() {
+    enum Foo {
+        Drop = assert_eq!(1, 1)
+        //[stock,if_match]~^ ERROR if may be missing an else clause
+        //[stock]~^^ ERROR `match` is not allowed in a `const`
+        //[stock]~| ERROR `match` is not allowed in a `const`
+        //[stock]~| ERROR `if` is not allowed in a `const`
+    }
+}
diff --git a/src/test/ui/issues/issue-50577.stderr b/src/test/ui/consts/control-flow/issue-50577.stock.stderr
index 0a150fbf53a..13b50954292 100644
--- a/src/test/ui/issues/issue-50577.stderr
+++ b/src/test/ui/consts/control-flow/issue-50577.stock.stderr
@@ -1,29 +1,35 @@
-error[E0744]: `match` is not allowed in a `const`
-  --> $DIR/issue-50577.rs:3:16
+error[E0658]: `match` is not allowed in a `const`
+  --> $DIR/issue-50577.rs:7:16
    |
 LL |         Drop = assert_eq!(1, 1)
    |                ^^^^^^^^^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
-error[E0744]: `if` is not allowed in a `const`
-  --> $DIR/issue-50577.rs:3:16
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/issue-50577.rs:7:16
    |
 LL |         Drop = assert_eq!(1, 1)
    |                ^^^^^^^^^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
-error[E0744]: `match` is not allowed in a `const`
-  --> $DIR/issue-50577.rs:3:16
+error[E0658]: `match` is not allowed in a `const`
+  --> $DIR/issue-50577.rs:7:16
    |
 LL |         Drop = assert_eq!(1, 1)
    |                ^^^^^^^^^^^^^^^^
    |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error[E0317]: if may be missing an else clause
-  --> $DIR/issue-50577.rs:3:16
+  --> $DIR/issue-50577.rs:7:16
    |
 LL |         Drop = assert_eq!(1, 1)
    |                ^^^^^^^^^^^^^^^^
@@ -37,5 +43,5 @@ LL |         Drop = assert_eq!(1, 1)
 
 error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0317, E0744.
+Some errors have detailed explanations: E0317, E0658.
 For more information about an error, try `rustc --explain E0317`.
diff --git a/src/test/ui/consts/const-loop.stderr b/src/test/ui/consts/control-flow/loop.if_match.stderr
index 2c96d181759..15b9eb02861 100644
--- a/src/test/ui/consts/const-loop.stderr
+++ b/src/test/ui/consts/control-flow/loop.if_match.stderr
@@ -1,35 +1,35 @@
 error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/const-loop.rs:1:15
+  --> $DIR/loop.rs:8:15
    |
 LL | const _: () = loop {};
    |               ^^^^^^^
 
 error[E0744]: `loop` is not allowed in a `static`
-  --> $DIR/const-loop.rs:3:19
+  --> $DIR/loop.rs:10:19
    |
 LL | static FOO: i32 = loop { break 4; };
    |                   ^^^^^^^^^^^^^^^^^
 
 error[E0744]: `loop` is not allowed in a `const fn`
-  --> $DIR/const-loop.rs:6:5
+  --> $DIR/loop.rs:13:5
    |
 LL |     loop {}
    |     ^^^^^^^
 
 error[E0744]: `loop` is not allowed in a `const fn`
-  --> $DIR/const-loop.rs:19:9
+  --> $DIR/loop.rs:26:9
    |
 LL |         loop {}
    |         ^^^^^^^
 
 error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/const-loop.rs:31:9
+  --> $DIR/loop.rs:38:9
    |
 LL |         while false {}
    |         ^^^^^^^^^^^^^^
 
 error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/const-loop.rs:40:5
+  --> $DIR/loop.rs:47:5
    |
 LL | /     while x < 4 {
 LL | |         x += 1;
@@ -37,7 +37,7 @@ LL | |     }
    | |_____^
 
 error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/const-loop.rs:44:5
+  --> $DIR/loop.rs:51:5
    |
 LL | /     while x < 8 {
 LL | |         x += 1;
@@ -45,7 +45,7 @@ LL | |     }
    | |_____^
 
 error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/const-loop.rs:54:5
+  --> $DIR/loop.rs:61:5
    |
 LL | /     for i in 0..4 {
 LL | |         x += i;
@@ -53,7 +53,7 @@ LL | |     }
    | |_____^
 
 error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/const-loop.rs:58:5
+  --> $DIR/loop.rs:65:5
    |
 LL | /     for i in 0..4 {
 LL | |         x += i;
@@ -61,7 +61,7 @@ LL | |     }
    | |_____^
 
 error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/const-loop.rs:68:5
+  --> $DIR/loop.rs:75:5
    |
 LL | /     loop {
 LL | |         x += 1;
@@ -71,16 +71,8 @@ LL | |         }
 LL | |     }
    | |_____^
 
-error[E0744]: `if` is not allowed in a `const`
-  --> $DIR/const-loop.rs:70:9
-   |
-LL | /         if x == 4 {
-LL | |             break;
-LL | |         }
-   | |_________^
-
 error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/const-loop.rs:75:5
+  --> $DIR/loop.rs:82:5
    |
 LL | /     loop {
 LL | |         x += 1;
@@ -90,38 +82,30 @@ LL | |         }
 LL | |     }
    | |_____^
 
-error[E0744]: `if` is not allowed in a `const`
-  --> $DIR/const-loop.rs:77:9
-   |
-LL | /         if x == 8 {
-LL | |             break;
-LL | |         }
-   | |_________^
-
-error[E0744]: `while let` is not allowed in a `const`
-  --> $DIR/const-loop.rs:87:5
+error[E0744]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:94:5
    |
 LL |     while let None = Some(x) { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0744]: `while let` is not allowed in a `const`
-  --> $DIR/const-loop.rs:88:5
+error[E0744]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:95:5
    |
 LL |     while let None = Some(x) { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/const-loop.rs:10:22
+  --> $DIR/loop.rs:17:22
    |
 LL |     const BAR: i32 = loop { break 4; };
    |                      ^^^^^^^^^^^^^^^^^
 
 error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/const-loop.rs:14:22
+  --> $DIR/loop.rs:21:22
    |
 LL |     const BAR: i32 = loop { break 4; };
    |                      ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 17 previous errors
+error: aborting due to 15 previous errors
 
 For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/consts/control-flow/loop.rs b/src/test/ui/consts/control-flow/loop.rs
new file mode 100644
index 00000000000..4be341f2d38
--- /dev/null
+++ b/src/test/ui/consts/control-flow/loop.rs
@@ -0,0 +1,97 @@
+// Ensure that all loops are forbidden in a const context, even if `#![feature(const_if_match)]` is
+// enabled.
+
+// revisions: stock if_match
+
+#![cfg_attr(if_match, feature(const_if_match))]
+
+const _: () = loop {}; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
+
+static FOO: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `static`
+
+const fn foo() {
+    loop {} //[stock,if_match]~ ERROR `loop` is not allowed in a `const fn`
+}
+
+pub trait Foo {
+    const BAR: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
+}
+
+impl Foo for () {
+    const BAR: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
+}
+
+fn non_const_outside() {
+    const fn const_inside() {
+        loop {} //[stock,if_match]~ ERROR `loop` is not allowed in a `const fn`
+    }
+}
+
+const fn const_outside() {
+    fn non_const_inside() {
+        loop {}
+    }
+}
+
+fn main() {
+    let x = [0; {
+        while false {}
+        //[stock,if_match]~^ ERROR `while` is not allowed in a `const`
+        4
+    }];
+}
+
+const _: i32 = {
+    let mut x = 0;
+
+    while x < 4 { //[stock,if_match]~ ERROR `while` is not allowed in a `const`
+        x += 1;
+    }
+
+    while x < 8 { //[stock,if_match]~ ERROR `while` is not allowed in a `const`
+        x += 1;
+    }
+
+    x
+};
+
+const _: i32 = {
+    let mut x = 0;
+
+    for i in 0..4 { //[stock,if_match]~ ERROR `for` is not allowed in a `const`
+        x += i;
+    }
+
+    for i in 0..4 { //[stock,if_match]~ ERROR `for` is not allowed in a `const`
+        x += i;
+    }
+
+    x
+};
+
+const _: i32 = {
+    let mut x = 0;
+
+    loop { //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
+        x += 1;
+        if x == 4 { //[stock]~ ERROR `if` is not allowed in a `const`
+            break;
+        }
+    }
+
+    loop { //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
+        x += 1;
+        if x == 8 { //[stock]~ ERROR `if` is not allowed in a `const`
+            break;
+        }
+    }
+
+    x
+};
+
+const _: i32 = {
+    let mut x = 0;
+    while let None = Some(x) { } //[stock,if_match]~ ERROR `while` is not allowed in a `const`
+    while let None = Some(x) { } //[stock,if_match]~ ERROR `while` is not allowed in a `const`
+    x
+};
diff --git a/src/test/ui/consts/control-flow/loop.stock.stderr b/src/test/ui/consts/control-flow/loop.stock.stderr
new file mode 100644
index 00000000000..bb651d23179
--- /dev/null
+++ b/src/test/ui/consts/control-flow/loop.stock.stderr
@@ -0,0 +1,134 @@
+error[E0744]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:8:15
+   |
+LL | const _: () = loop {};
+   |               ^^^^^^^
+
+error[E0744]: `loop` is not allowed in a `static`
+  --> $DIR/loop.rs:10:19
+   |
+LL | static FOO: i32 = loop { break 4; };
+   |                   ^^^^^^^^^^^^^^^^^
+
+error[E0744]: `loop` is not allowed in a `const fn`
+  --> $DIR/loop.rs:13:5
+   |
+LL |     loop {}
+   |     ^^^^^^^
+
+error[E0744]: `loop` is not allowed in a `const fn`
+  --> $DIR/loop.rs:26:9
+   |
+LL |         loop {}
+   |         ^^^^^^^
+
+error[E0744]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:38:9
+   |
+LL |         while false {}
+   |         ^^^^^^^^^^^^^^
+
+error[E0744]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:47:5
+   |
+LL | /     while x < 4 {
+LL | |         x += 1;
+LL | |     }
+   | |_____^
+
+error[E0744]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:51:5
+   |
+LL | /     while x < 8 {
+LL | |         x += 1;
+LL | |     }
+   | |_____^
+
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/loop.rs:61:5
+   |
+LL | /     for i in 0..4 {
+LL | |         x += i;
+LL | |     }
+   | |_____^
+
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/loop.rs:65:5
+   |
+LL | /     for i in 0..4 {
+LL | |         x += i;
+LL | |     }
+   | |_____^
+
+error[E0744]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:75:5
+   |
+LL | /     loop {
+LL | |         x += 1;
+LL | |         if x == 4 {
+LL | |             break;
+LL | |         }
+LL | |     }
+   | |_____^
+
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/loop.rs:77:9
+   |
+LL | /         if x == 4 {
+LL | |             break;
+LL | |         }
+   | |_________^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0744]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:82:5
+   |
+LL | /     loop {
+LL | |         x += 1;
+LL | |         if x == 8 {
+LL | |             break;
+LL | |         }
+LL | |     }
+   | |_____^
+
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/loop.rs:84:9
+   |
+LL | /         if x == 8 {
+LL | |             break;
+LL | |         }
+   | |_________^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0744]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:94:5
+   |
+LL |     while let None = Some(x) { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0744]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:95:5
+   |
+LL |     while let None = Some(x) { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0744]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:17:22
+   |
+LL |     const BAR: i32 = loop { break 4; };
+   |                      ^^^^^^^^^^^^^^^^^
+
+error[E0744]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:21:22
+   |
+LL |     const BAR: i32 = loop { break 4; };
+   |                      ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 17 previous errors
+
+Some errors have detailed explanations: E0658, E0744.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/control-flow/short-circuit-let.rs b/src/test/ui/consts/control-flow/short-circuit-let.rs
new file mode 100644
index 00000000000..8cee2a54f56
--- /dev/null
+++ b/src/test/ui/consts/control-flow/short-circuit-let.rs
@@ -0,0 +1,39 @@
+// `&&` and `||` were previously forbidden in constants alongside let bindings.
+
+// run-pass
+
+#![feature(const_if_match)]
+#![feature(const_panic)]
+
+const X: i32 = {
+    let mut x = 0;
+    let _ = true && { x = 1; false };
+    x
+};
+
+const Y: bool = {
+    let x = true && false || true;
+    x
+};
+
+const fn truthy() -> bool {
+    let x = true || return false;
+    x
+}
+
+const fn falsy() -> bool {
+    let x = true && return false;
+    x
+}
+
+fn main() {
+    const _: () = assert!(Y);
+    assert!(Y);
+
+    const _: () = assert!(X == 1);
+    assert_eq!(X, 1);
+
+    const _: () = assert!(truthy());
+    const _: () = assert!(!falsy());
+    assert!(truthy() && !falsy());
+}
diff --git a/src/test/ui/consts/control-flow/short-circuit.if_match.stderr b/src/test/ui/consts/control-flow/short-circuit.if_match.stderr
new file mode 100644
index 00000000000..f6ba28e7b72
--- /dev/null
+++ b/src/test/ui/consts/control-flow/short-circuit.if_match.stderr
@@ -0,0 +1,8 @@
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/short-circuit.rs:14:1
+   |
+LL | fn main() {}
+   | ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/consts/control-flow/short-circuit.rs b/src/test/ui/consts/control-flow/short-circuit.rs
new file mode 100644
index 00000000000..f5e54a69d4a
--- /dev/null
+++ b/src/test/ui/consts/control-flow/short-circuit.rs
@@ -0,0 +1,14 @@
+// Test that both `&&` and `||` actually short-circuit when the `const_if_match` feature flag is
+// enabled. Without the feature flag, both sides are evaluated unconditionally.
+
+// revisions: stock if_match
+
+#![feature(rustc_attrs)]
+#![feature(const_panic)]
+#![cfg_attr(if_match, feature(const_if_match))]
+
+const _: bool = true || panic!();  //[stock]~ ERROR any use of this value will cause an error
+const _: bool = false && panic!(); //[stock]~ ERROR any use of this value will cause an error
+
+#[rustc_error]
+fn main() {} //[if_match]~ ERROR fatal error triggered by #[rustc_error]
diff --git a/src/test/ui/consts/control-flow/short-circuit.stock.stderr b/src/test/ui/consts/control-flow/short-circuit.stock.stderr
new file mode 100644
index 00000000000..cf0de929593
--- /dev/null
+++ b/src/test/ui/consts/control-flow/short-circuit.stock.stderr
@@ -0,0 +1,23 @@
+error: any use of this value will cause an error
+  --> $DIR/short-circuit.rs:10:25
+   |
+LL | const _: bool = true || panic!();
+   | ------------------------^^^^^^^^-
+   |                         |
+   |                         the evaluated program panicked at 'explicit panic', $DIR/short-circuit.rs:10:25
+   |
+   = note: `#[deny(const_err)]` on by default
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: any use of this value will cause an error
+  --> $DIR/short-circuit.rs:11:26
+   |
+LL | const _: bool = false && panic!();
+   | -------------------------^^^^^^^^-
+   |                          |
+   |                          the evaluated program panicked at 'explicit panic', $DIR/short-circuit.rs:11:26
+   |
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/consts/control-flow/single_variant_match_ice.rs b/src/test/ui/consts/control-flow/single_variant_match_ice.rs
new file mode 100644
index 00000000000..823605ff034
--- /dev/null
+++ b/src/test/ui/consts/control-flow/single_variant_match_ice.rs
@@ -0,0 +1,27 @@
+// check-pass
+
+#![feature(const_if_match)]
+
+enum Foo {
+    Prob,
+}
+
+const FOO: u32 = match Foo::Prob {
+    Foo::Prob => 42,
+};
+
+const BAR: u32 = match Foo::Prob {
+    x => 42,
+};
+
+impl Foo {
+    pub const fn as_val(&self) -> u8 {
+        use self::Foo::*;
+
+        match *self {
+            Prob => 0x1,
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/control-flow/try.rs b/src/test/ui/consts/control-flow/try.rs
new file mode 100644
index 00000000000..31fe09d4f69
--- /dev/null
+++ b/src/test/ui/consts/control-flow/try.rs
@@ -0,0 +1,12 @@
+// The `?` operator is still not const-evaluatable because it calls `From::from` on the error
+// variant.
+
+#![feature(const_if_match)]
+
+const fn opt() -> Option<i32> {
+    let x = Some(2);
+    x?; //~ ERROR `?` is not allowed in a `const fn`
+    None
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/control-flow/try.stderr b/src/test/ui/consts/control-flow/try.stderr
new file mode 100644
index 00000000000..60a386ef6c8
--- /dev/null
+++ b/src/test/ui/consts/control-flow/try.stderr
@@ -0,0 +1,9 @@
+error[E0744]: `?` is not allowed in a `const fn`
+  --> $DIR/try.rs:8:5
+   |
+LL |     x?;
+   |     ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/consts/single_variant_match_ice.rs b/src/test/ui/consts/single_variant_match_ice.rs
deleted file mode 100644
index 80a92c4c965..00000000000
--- a/src/test/ui/consts/single_variant_match_ice.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-enum Foo {
-    Prob,
-}
-
-const FOO: u32 = match Foo::Prob { //~ ERROR `match` is not allowed in a `const`
-    Foo::Prob => 42,
-};
-
-const BAR: u32 = match Foo::Prob { //~ ERROR `match` is not allowed in a `const`
-    x => 42,
-};
-
-impl Foo {
-    pub const fn as_val(&self) -> u8 {
-        use self::Foo::*;
-
-        match *self { //~ ERROR `match` is not allowed in a `const fn`
-            Prob => 0x1,
-        }
-    }
-}
-
-fn main() {}
diff --git a/src/test/ui/consts/single_variant_match_ice.stderr b/src/test/ui/consts/single_variant_match_ice.stderr
deleted file mode 100644
index 780dd0dcddf..00000000000
--- a/src/test/ui/consts/single_variant_match_ice.stderr
+++ /dev/null
@@ -1,29 +0,0 @@
-error[E0744]: `match` is not allowed in a `const`
-  --> $DIR/single_variant_match_ice.rs:5:18
-   |
-LL |   const FOO: u32 = match Foo::Prob {
-   |  __________________^
-LL | |     Foo::Prob => 42,
-LL | | };
-   | |_^
-
-error[E0744]: `match` is not allowed in a `const`
-  --> $DIR/single_variant_match_ice.rs:9:18
-   |
-LL |   const BAR: u32 = match Foo::Prob {
-   |  __________________^
-LL | |     x => 42,
-LL | | };
-   | |_^
-
-error[E0744]: `match` is not allowed in a `const fn`
-  --> $DIR/single_variant_match_ice.rs:17:9
-   |
-LL | /         match *self {
-LL | |             Prob => 0x1,
-LL | |         }
-   | |_________^
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/consts/miri_unleashed/enum_discriminants.rs b/src/test/ui/enum-discriminant/niche.rs
index 76d62f069f3..8d2cdf34f37 100644
--- a/src/test/ui/consts/miri_unleashed/enum_discriminants.rs
+++ b/src/test/ui/enum-discriminant/niche.rs
@@ -1,8 +1,7 @@
-// compile-flags: -Zunleash-the-miri-inside-of-you -Awarnings
 // run-pass
 
-// miri unleashed warnings are not useful and change frequently, so they are silenced above.
 #![feature(const_panic)]
+#![feature(const_if_match)]
 
 //! Make sure that we read and write enum discriminants correctly for corner cases caused
 //! by layout optimizations.
diff --git a/src/test/ui/issues/issue-46843.rs b/src/test/ui/issues/issue-46843.rs
deleted file mode 100644
index e5b27136739..00000000000
--- a/src/test/ui/issues/issue-46843.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-enum Thing { This, That }
-
-fn non_const() -> Thing {
-    Thing::This
-}
-
-pub const Q: i32 = match non_const() {
-    //~^ ERROR `match` is not allowed in a `const`
-    Thing::This => 1,
-    Thing::That => 0
-};
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-46843.stderr b/src/test/ui/issues/issue-46843.stderr
deleted file mode 100644
index 9d533297864..00000000000
--- a/src/test/ui/issues/issue-46843.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0744]: `match` is not allowed in a `const`
-  --> $DIR/issue-46843.rs:7:20
-   |
-LL |   pub const Q: i32 = match non_const() {
-   |  ____________________^
-LL | |
-LL | |     Thing::This => 1,
-LL | |     Thing::That => 0
-LL | | };
-   | |_^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/issues/issue-50577.rs b/src/test/ui/issues/issue-50577.rs
deleted file mode 100644
index f3f680e7b8e..00000000000
--- a/src/test/ui/issues/issue-50577.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-fn main() {
-    enum Foo {
-        Drop = assert_eq!(1, 1)
-        //~^ ERROR if may be missing an else clause
-        //~| ERROR `match` is not allowed in a `const`
-        //~| ERROR `match` is not allowed in a `const`
-        //~| ERROR `if` is not allowed in a `const`
-    }
-}
diff --git a/src/test/ui/issues/issue-51714.rs b/src/test/ui/issues/issue-51714.rs
index e0fd7ff896c..782037a1fe5 100644
--- a/src/test/ui/issues/issue-51714.rs
+++ b/src/test/ui/issues/issue-51714.rs
@@ -10,5 +10,5 @@ fn main() {
 
     [(); return while let Some(n) = Some(0) {}];
     //~^ ERROR return statement outside of function body
-    //~| ERROR `while let` is not allowed in a `const`
+    //~| ERROR `while` is not allowed in a `const`
 }
diff --git a/src/test/ui/issues/issue-51714.stderr b/src/test/ui/issues/issue-51714.stderr
index a3b20cf97f8..001928c3b2f 100644
--- a/src/test/ui/issues/issue-51714.stderr
+++ b/src/test/ui/issues/issue-51714.stderr
@@ -1,4 +1,4 @@
-error[E0744]: `while let` is not allowed in a `const`
+error[E0744]: `while` is not allowed in a `const`
   --> $DIR/issue-51714.rs:11:17
    |
 LL |     [(); return while let Some(n) = Some(0) {}];
diff --git a/src/test/ui/loops/loop-break-value.rs b/src/test/ui/loops/loop-break-value.rs
index 8d88aefdb51..c4fb68c0278 100644
--- a/src/test/ui/loops/loop-break-value.rs
+++ b/src/test/ui/loops/loop-break-value.rs
@@ -33,19 +33,19 @@ fn main() {
     }
 
     while let Some(_) = Some(()) {
-        if break () { //~ ERROR `break` with value from a `while let` loop
+        if break () { //~ ERROR `break` with value from a `while` loop
         }
     }
 
     while let Some(_) = Some(()) {
         break None;
-        //~^ ERROR `break` with value from a `while let` loop
+        //~^ ERROR `break` with value from a `while` loop
     }
 
     'while_let_loop: while let Some(_) = Some(()) {
         loop {
             break 'while_let_loop "nope";
-            //~^ ERROR `break` with value from a `while let` loop
+            //~^ ERROR `break` with value from a `while` loop
             break 33;
         };
     }
diff --git a/src/test/ui/loops/loop-break-value.stderr b/src/test/ui/loops/loop-break-value.stderr
index 1707a179ad0..1f2d81ff03f 100644
--- a/src/test/ui/loops/loop-break-value.stderr
+++ b/src/test/ui/loops/loop-break-value.stderr
@@ -28,35 +28,35 @@ help: instead, use `break` on its own without a value inside this `while` loop
 LL |             break;
    |             ^^^^^
 
-error[E0571]: `break` with value from a `while let` loop
+error[E0571]: `break` with value from a `while` loop
   --> $DIR/loop-break-value.rs:36:12
    |
 LL |         if break () {
    |            ^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: instead, use `break` on its own without a value inside this `while let` loop
+help: instead, use `break` on its own without a value inside this `while` loop
    |
 LL |         if break {
    |            ^^^^^
 
-error[E0571]: `break` with value from a `while let` loop
+error[E0571]: `break` with value from a `while` loop
   --> $DIR/loop-break-value.rs:41:9
    |
 LL |         break None;
    |         ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: instead, use `break` on its own without a value inside this `while let` loop
+help: instead, use `break` on its own without a value inside this `while` loop
    |
 LL |         break;
    |         ^^^^^
 
-error[E0571]: `break` with value from a `while let` loop
+error[E0571]: `break` with value from a `while` loop
   --> $DIR/loop-break-value.rs:47:13
    |
 LL |             break 'while_let_loop "nope";
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: instead, use `break` on its own without a value inside this `while let` loop
+help: instead, use `break` on its own without a value inside this `while` loop
    |
 LL |             break;
    |             ^^^^^
diff --git a/src/test/ui/return/return-match-array-const.stderr b/src/test/ui/return/return-match-array-const.stderr
index 496e9208b61..8b8e961b726 100644
--- a/src/test/ui/return/return-match-array-const.stderr
+++ b/src/test/ui/return/return-match-array-const.stderr
@@ -1,20 +1,29 @@
-error[E0744]: `match` is not allowed in a `const`
+error[E0658]: `match` is not allowed in a `const`
   --> $DIR/return-match-array-const.rs:2:17
    |
 LL |     [(); return match 0 { n => n }];
    |                 ^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-error[E0744]: `match` is not allowed in a `const`
+error[E0658]: `match` is not allowed in a `const`
   --> $DIR/return-match-array-const.rs:6:17
    |
 LL |     [(); return match 0 { 0 => 0 }];
    |                 ^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-error[E0744]: `match` is not allowed in a `const`
+error[E0658]: `match` is not allowed in a `const`
   --> $DIR/return-match-array-const.rs:10:17
    |
 LL |     [(); return match () { 'a' => 0, _ => 0 }];
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0572]: return statement outside of function body
   --> $DIR/return-match-array-const.rs:2:10
@@ -36,5 +45,5 @@ LL |     [(); return match () { 'a' => 0, _ => 0 }];
 
 error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0572, E0744.
+Some errors have detailed explanations: E0572, E0658.
 For more information about an error, try `rustc --explain E0572`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index 05e30a8010a..f24ea0505e7 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -513,23 +513,32 @@ warning: the feature `let_chains` is incomplete and may cause the compiler to cr
 LL | #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test.
    |            ^^^^^^^^^^
 
-error[E0744]: `match` is not allowed in a `const`
+error[E0658]: `match` is not allowed in a `const`
   --> $DIR/disallowed-positions.rs:218:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-error[E0744]: `match` is not allowed in a `const`
+error[E0658]: `match` is not allowed in a `const`
   --> $DIR/disallowed-positions.rs:223:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-error[E0744]: `match` is not allowed in a `const`
+error[E0658]: `match` is not allowed in a `const`
   --> $DIR/disallowed-positions.rs:228:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:32:8
@@ -952,5 +961,5 @@ LL |         let 0 = 0?;
 
 error: aborting due to 106 previous errors
 
-Some errors have detailed explanations: E0277, E0308, E0600, E0614, E0744.
+Some errors have detailed explanations: E0277, E0308, E0600, E0614, E0658.
 For more information about an error, try `rustc --explain E0277`.