about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-11-13 20:10:54 +0000
committerbors <bors@rust-lang.org>2019-11-13 20:10:54 +0000
commitded5ee0013f6126f885baf5e072c20ba8b86ee6a (patch)
tree01bfb70673480a89165ef0063a47fc5a3d37be8c
parent695fe965173795f9242dfcad6d1c07d7a17b106a (diff)
parent7552bd662f89c67c54e61e2f7c1c1979f6b510e2 (diff)
downloadrust-ded5ee0013f6126f885baf5e072c20ba8b86ee6a.tar.gz
rust-ded5ee0013f6126f885baf5e072c20ba8b86ee6a.zip
Auto merge of #66170 - ecstatic-morse:hir-const-check, r=Centril,oli-obk
Add a HIR pass to check consts for `if`, `loop`, etc.

Resolves #66125.

This PR adds a HIR pass to check for high-level control flow constructs that are forbidden in a const-context. The MIR const-checker is unable to provide good spans for these since they are lowered to control flow primitives (e.g., `Goto` and `SwitchInt`), and these often don't map back to the underlying statement as a whole. This PR is intended only to improve diagnostics once `if` and `match` become commonplace in constants (behind a feature flag). The MIR const-checker will continue to operate unchanged, and will catch anything this check might miss.

In this implementation, the HIR const-checking pass is run much earlier than the MIR one, so it will supersede any errors from the latter. I will need some mentoring if we wish to change this, since I'm not familiar with the diagnostics system. Moving this pass into the same phase as the MIR const-checker could also help keep backwards compatibility for items like `const _: () = loop { break; };`, which are currently (erroneously?) accepted by the MIR const-checker (see #62272).

r? @Centril
cc @eddyb (since they filed #62272)
-rw-r--r--src/librustc/hir/map/mod.rs35
-rw-r--r--src/librustc/query/mod.rs5
-rw-r--r--src/librustc_interface/passes.rs1
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs9
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs15
-rw-r--r--src/librustc_passes/check_const.rs160
-rw-r--r--src/librustc_passes/error_codes.rs22
-rw-r--r--src/librustc_passes/lib.rs2
-rw-r--r--src/test/compile-fail/consts/const-fn-error.rs3
-rw-r--r--src/test/compile-fail/issue-52443.rs8
-rw-r--r--src/test/ui/borrowck/issue-64453.rs5
-rw-r--r--src/test/ui/borrowck/issue-64453.stderr29
-rw-r--r--src/test/ui/closures/issue-52437.rs1
-rw-r--r--src/test/ui/closures/issue-52437.stderr11
-rw-r--r--src/test/ui/consts/const-eval/infinite_loop.rs4
-rw-r--r--src/test/ui/consts/const-eval/infinite_loop.stderr22
-rw-r--r--src/test/ui/consts/const-eval/issue-52442.rs1
-rw-r--r--src/test/ui/consts/const-eval/issue-52442.stderr10
-rw-r--r--src/test/ui/consts/const-eval/issue-52475.rs3
-rw-r--r--src/test/ui/consts/const-eval/issue-52475.stderr17
-rw-r--r--src/test/ui/consts/const-eval/issue-62272.rs12
-rw-r--r--src/test/ui/consts/const-eval/issue-62272.stderr15
-rw-r--r--src/test/ui/consts/const-eval/match-test-ptr-null.rs4
-rw-r--r--src/test/ui/consts/const-eval/match-test-ptr-null.stderr30
-rw-r--r--src/test/ui/consts/const-if.rs22
-rw-r--r--src/test/ui/consts/const-if.stderr42
-rw-r--r--src/test/ui/consts/const-labeled-break.rs8
-rw-r--r--src/test/ui/consts/const-labeled-break.stderr9
-rw-r--r--src/test/ui/consts/const-loop.rs68
-rw-r--r--src/test/ui/consts/const-loop.stderr139
-rw-r--r--src/test/ui/consts/const-match-pattern-arm.rs8
-rw-r--r--src/test/ui/consts/const-match-pattern-arm.stderr39
-rw-r--r--src/test/ui/consts/min_const_fn/loop_ice.rs2
-rw-r--r--src/test/ui/consts/min_const_fn/loop_ice.stderr7
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.rs4
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.stderr50
-rw-r--r--src/test/ui/consts/miri_unleashed/enum_discriminants.rs10
-rw-r--r--src/test/ui/consts/miri_unleashed/enum_discriminants.stderr47
-rw-r--r--src/test/ui/consts/single_variant_match_ice.rs7
-rw-r--r--src/test/ui/consts/single_variant_match_ice.stderr38
-rw-r--r--src/test/ui/issues/issue-46843.rs5
-rw-r--r--src/test/ui/issues/issue-46843.stderr30
-rw-r--r--src/test/ui/issues/issue-50577.rs3
-rw-r--r--src/test/ui/issues/issue-50577.stderr29
-rw-r--r--src/test/ui/issues/issue-50582.rs1
-rw-r--r--src/test/ui/issues/issue-50582.stderr11
-rw-r--r--src/test/ui/issues/issue-50585.rs1
-rw-r--r--src/test/ui/issues/issue-50585.stderr11
-rw-r--r--src/test/ui/issues/issue-51714.rs1
-rw-r--r--src/test/ui/issues/issue-51714.stderr11
-rw-r--r--src/test/ui/return/return-match-array-const.rs12
-rw-r--r--src/test/ui/return/return-match-array-const.stderr27
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs9
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr66
54 files changed, 784 insertions, 357 deletions
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index d7b1676c1d4..83372dd8ade 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -79,6 +79,33 @@ impl<'hir> Entry<'hir> {
         }
     }
 
+    fn fn_sig(&self) -> Option<&'hir FnSig> {
+        match &self.node {
+            Node::Item(item) => {
+                match &item.kind {
+                    ItemKind::Fn(sig, _, _) => Some(sig),
+                    _ => None,
+                }
+            }
+
+            Node::TraitItem(item) => {
+                match &item.kind {
+                    TraitItemKind::Method(sig, _) => Some(sig),
+                    _ => None
+                }
+            }
+
+            Node::ImplItem(item) => {
+                match &item.kind {
+                    ImplItemKind::Method(sig, _) => Some(sig),
+                    _ => None,
+                }
+            }
+
+            _ => None,
+        }
+    }
+
     fn associated_body(self) -> Option<BodyId> {
         match self.node {
             Node::Item(item) => {
@@ -450,6 +477,14 @@ impl<'hir> Map<'hir> {
         }
     }
 
+    pub fn fn_sig_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnSig> {
+        if let Some(entry) = self.find_entry(hir_id) {
+            entry.fn_sig()
+        } else {
+            bug!("no entry for hir_id `{}`", hir_id)
+        }
+    }
+
     /// Returns the `HirId` that corresponds to the definition of
     /// which this is the body of, i.e., a `fn`, `const` or `static`
     /// item (possibly associated), a closure, or a `hir::AnonConst`.
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index bd7b77b0abb..9bd2a933c1c 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -329,6 +329,11 @@ rustc_queries! {
             desc { |tcx| "checking for unstable API usage in {}", key.describe_as_module(tcx) }
         }
 
+        /// Checks the const bodies in the module for illegal operations (e.g. `if` or `loop`).
+        query check_mod_const_bodies(key: DefId) -> () {
+            desc { |tcx| "checking consts in {}", key.describe_as_module(tcx) }
+        }
+
         /// Checks the loops in the module.
         query check_mod_loops(key: DefId) -> () {
             desc { |tcx| "checking loops in {}", key.describe_as_module(tcx) }
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index c57622b8b8f..83b936dd7aa 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -875,6 +875,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
                 tcx.ensure().check_mod_loops(local_def_id);
                 tcx.ensure().check_mod_attrs(local_def_id);
                 tcx.ensure().check_mod_unstable_api_usage(local_def_id);
+                tcx.ensure().check_mod_const_bodies(local_def_id);
             });
         });
     });
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index 244d434a51e..88f16299dc0 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -461,7 +461,14 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
                 self.super_statement(statement, location);
             }
             StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) => {
-                self.check_op(ops::IfOrMatch);
+                // FIXME: make this the `emit_error` impl of `ops::IfOrMatch` once the const
+                // checker is no longer run in compatability mode.
+                if !self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
+                    self.tcx.sess.delay_span_bug(
+                        self.span,
+                        "complex control flow is forbidden in a const context",
+                    );
+                }
             }
             // FIXME(eddyb) should these really do nothing?
             StatementKind::FakeRead(..) |
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 39720af4cb5..255e71db89d 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -723,8 +723,12 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
                     bb = target;
                 }
                 _ => {
-                    self.not_const(ops::Loop);
-                    validator.check_op(ops::Loop);
+                    if !self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
+                        self.tcx.sess.delay_span_bug(
+                            self.span,
+                            "complex control flow is forbidden in a const context",
+                        );
+                    }
                     break;
                 }
             }
@@ -1253,7 +1257,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                 self.super_statement(statement, location);
             }
             StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) => {
-                self.not_const(ops::IfOrMatch);
+                if !self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
+                    self.tcx.sess.delay_span_bug(
+                        self.span,
+                        "complex control flow is forbidden in a const context",
+                    );
+                }
             }
             // FIXME(eddyb) should these really do nothing?
             StatementKind::FakeRead(..) |
diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs
new file mode 100644
index 00000000000..a6d7eeabc88
--- /dev/null
+++ b/src/librustc_passes/check_const.rs
@@ -0,0 +1,160 @@
+//! This pass checks HIR bodies that may be evaluated at compile-time (e.g., `const`, `static`,
+//! `const fn`) for structured control flow (e.g. `if`, `while`), which is forbidden in a const
+//! context.
+//!
+//! By the time the MIR const-checker runs, these high-level constructs have been lowered to
+//! control-flow primitives (e.g., `Goto`, `SwitchInt`), making it tough to properly attribute
+//! errors. We still look for those primitives in the MIR const-checker to ensure nothing slips
+//! through, but errors for structured control flow in a `const` should be emitted here.
+
+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::span_err;
+use syntax_pos::Span;
+
+use std::fmt;
+
+#[derive(Copy, Clone)]
+enum ConstKind {
+    Static,
+    StaticMut,
+    ConstFn,
+    Const,
+    AnonConst,
+}
+
+impl ConstKind {
+    fn for_body(body: &hir::Body, hir_map: &Map<'_>) -> Option<Self> {
+        let is_const_fn = |id| hir_map.fn_sig_by_hir_id(id).unwrap().header.is_const();
+
+        let owner = hir_map.body_owner(body.id());
+        let const_kind = match hir_map.body_owner_kind(owner) {
+            hir::BodyOwnerKind::Const => Self::Const,
+            hir::BodyOwnerKind::Static(Mutability::Mutable) => Self::StaticMut,
+            hir::BodyOwnerKind::Static(Mutability::Immutable) => Self::Static,
+
+            hir::BodyOwnerKind::Fn if is_const_fn(owner) => Self::ConstFn,
+            hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => return None,
+        };
+
+        Some(const_kind)
+    }
+}
+
+impl fmt::Display for ConstKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let s = match self {
+            Self::Static => "static",
+            Self::StaticMut => "static mut",
+            Self::Const | Self::AnonConst => "const",
+            Self::ConstFn => "const fn",
+        };
+
+        write!(f, "{}", s)
+    }
+}
+
+fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: DefId) {
+    let mut vis = CheckConstVisitor::new(tcx);
+    tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
+}
+
+pub(crate) fn provide(providers: &mut Providers<'_>) {
+    *providers = Providers {
+        check_mod_const_bodies,
+        ..*providers
+    };
+}
+
+#[derive(Copy, Clone)]
+struct CheckConstVisitor<'tcx> {
+    sess: &'tcx Session,
+    hir_map: &'tcx Map<'tcx>,
+    const_kind: Option<ConstKind>,
+}
+
+impl<'tcx> CheckConstVisitor<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>) -> Self {
+        CheckConstVisitor {
+            sess: &tcx.sess,
+            hir_map: tcx.hir(),
+            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;
+        }
+
+        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);
+    }
+
+    /// Saves the parent `const_kind` before calling `f` and restores it afterwards.
+    fn recurse_into(&mut self, kind: Option<ConstKind>, f: impl FnOnce(&mut Self)) {
+        let parent_kind = self.const_kind;
+        self.const_kind = kind;
+        f(self);
+        self.const_kind = parent_kind;
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.hir_map)
+    }
+
+    fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
+        let kind = Some(ConstKind::AnonConst);
+        self.recurse_into(kind, |this| hir::intravisit::walk_anon_const(this, anon));
+    }
+
+    fn visit_body(&mut self, body: &'tcx hir::Body) {
+        let kind = ConstKind::for_body(body, self.hir_map);
+        self.recurse_into(kind, |this| hir::intravisit::walk_body(this, body));
+    }
+
+    fn visit_expr(&mut self, e: &'tcx hir::Expr) {
+        match &e.kind {
+            // Skip the following checks if we are not currently in a const context.
+            _ if self.const_kind.is_none() => {}
+
+            hir::ExprKind::Loop(_, _, source) => {
+                self.const_check_violated(source.name(), 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"),
+
+                    // These are handled by `ExprKind::Loop` above.
+                    WhileDesugar | WhileLetDesugar | ForLoopDesugar => None,
+                };
+
+                if let Some(op) = op {
+                    self.const_check_violated(op, e.span);
+                }
+            }
+
+            _ => {},
+        }
+
+        hir::intravisit::walk_expr(self, e);
+    }
+}
diff --git a/src/librustc_passes/error_codes.rs b/src/librustc_passes/error_codes.rs
index e22e69a0697..72cf0c7ed77 100644
--- a/src/librustc_passes/error_codes.rs
+++ b/src/librustc_passes/error_codes.rs
@@ -626,6 +626,28 @@ async fn foo() {}
 Switch to the Rust 2018 edition to use `async fn`.
 "##,
 
+E0744: r##"
+Control-flow expressions are not allowed inside a const context.
+
+At the moment, `if` and `match`, as well as the looping constructs `for`,
+`while`, and `loop`, are forbidden inside a `const`, `static`, or `const fn`.
+
+```compile_fail,E0744
+const _: i32 = {
+    let mut x = 0;
+    loop {
+        x += 1;
+        if x == 4 {
+            break;
+        }
+    }
+
+    x
+};
+```
+
+"##,
+
 ;
     E0226, // only a single explicit lifetime bound is permitted
     E0472, // asm! is unsupported on this target
diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs
index db59d8e101f..1cbe6a652af 100644
--- a/src/librustc_passes/lib.rs
+++ b/src/librustc_passes/lib.rs
@@ -23,6 +23,7 @@ use rustc::ty::query::Providers;
 pub mod error_codes;
 
 pub mod ast_validation;
+mod check_const;
 pub mod hir_stats;
 pub mod layout_test;
 pub mod loops;
@@ -32,6 +33,7 @@ mod liveness;
 mod intrinsicck;
 
 pub fn provide(providers: &mut Providers<'_>) {
+    check_const::provide(providers);
     entry::provide(providers);
     loops::provide(providers);
     liveness::provide(providers);
diff --git a/src/test/compile-fail/consts/const-fn-error.rs b/src/test/compile-fail/consts/const-fn-error.rs
index 1de23f2a5e9..4adad16a570 100644
--- a/src/test/compile-fail/consts/const-fn-error.rs
+++ b/src/test/compile-fail/consts/const-fn-error.rs
@@ -7,9 +7,8 @@ const fn f(x: usize) -> usize {
     for i in 0..x {
         //~^ ERROR E0015
         //~| ERROR E0017
-        //~| ERROR E0019
-        //~| ERROR E0019
         //~| ERROR E0080
+        //~| ERROR E0744
         sum += i;
     }
     sum
diff --git a/src/test/compile-fail/issue-52443.rs b/src/test/compile-fail/issue-52443.rs
index 28d9937b5e8..04eecb5687f 100644
--- a/src/test/compile-fail/issue-52443.rs
+++ b/src/test/compile-fail/issue-52443.rs
@@ -1,14 +1,14 @@
 fn main() {
     [(); & { loop { continue } } ]; //~ ERROR mismatched types
+    //~^ ERROR `loop` is not allowed in a `const`
     [(); loop { break }]; //~ ERROR mismatched types
+    //~^ ERROR `loop` is not allowed in a `const`
     [(); {while true {break}; 0}];
-    //~^ ERROR constant contains unimplemented expression type
-    //~| ERROR constant contains unimplemented expression type
+    //~^ ERROR `while` is not allowed in a `const`
     //~| WARN denote infinite loops with
     [(); { for _ in 0usize.. {}; 0}];
     //~^ ERROR calls in constants are limited to constant functions
+    //~| ERROR `for` is not allowed in a `const`
     //~| ERROR references in constants may only refer to immutable values
-    //~| ERROR constant contains unimplemented expression type
-    //~| ERROR constant contains unimplemented expression type
     //~| ERROR evaluation of constant value failed
 }
diff --git a/src/test/ui/borrowck/issue-64453.rs b/src/test/ui/borrowck/issue-64453.rs
index d8ab6b6e25f..8a405edb046 100644
--- a/src/test/ui/borrowck/issue-64453.rs
+++ b/src/test/ui/borrowck/issue-64453.rs
@@ -2,9 +2,7 @@ struct Project;
 struct Value;
 
 static settings_dir: String = format!("");
-//~^ ERROR [E0019]
-//~| ERROR [E0015]
-//~| ERROR [E0015]
+//~^ ERROR `match` is not allowed in a `static`
 
 fn from_string(_: String) -> Value {
     Value
@@ -13,7 +11,6 @@ fn set_editor(_: Value) {}
 
 fn main() {
     let settings_data = from_string(settings_dir);
-    //~^ ERROR cannot move out of static item `settings_dir` [E0507]
     let args: i32 = 0;
 
     match args {
diff --git a/src/test/ui/borrowck/issue-64453.stderr b/src/test/ui/borrowck/issue-64453.stderr
index 6987417fe19..f437880a165 100644
--- a/src/test/ui/borrowck/issue-64453.stderr
+++ b/src/test/ui/borrowck/issue-64453.stderr
@@ -1,26 +1,4 @@
-error[E0507]: cannot move out of static item `settings_dir`
-  --> $DIR/issue-64453.rs:15:37
-   |
-LL |     let settings_data = from_string(settings_dir);
-   |                                     ^^^^^^^^^^^^ move occurs because `settings_dir` has type `std::string::String`, which does not implement the `Copy` trait
-
-error[E0019]: static contains unimplemented expression type
-  --> $DIR/issue-64453.rs:4:31
-   |
-LL | static settings_dir: String = format!("");
-   |                               ^^^^^^^^^^^
-   |
-   = 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[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/issue-64453.rs:4:31
-   |
-LL | static settings_dir: String = format!("");
-   |                               ^^^^^^^^^^^
-   |
-   = 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[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0744]: `match` is not allowed in a `static`
   --> $DIR/issue-64453.rs:4:31
    |
 LL | static settings_dir: String = format!("");
@@ -28,7 +6,6 @@ LL | static settings_dir: String = format!("");
    |
    = 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 4 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0015, E0019, E0507.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/closures/issue-52437.rs b/src/test/ui/closures/issue-52437.rs
index 6ac5380a5aa..1e649a556e0 100644
--- a/src/test/ui/closures/issue-52437.rs
+++ b/src/test/ui/closures/issue-52437.rs
@@ -1,5 +1,6 @@
 fn main() {
     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
     //~^ ERROR: invalid label name `'static`
+    //~| ERROR: `loop` is not allowed in a `const`
     //~| ERROR: type annotations needed
 }
diff --git a/src/test/ui/closures/issue-52437.stderr b/src/test/ui/closures/issue-52437.stderr
index e76f942e9ba..b4b40336aa9 100644
--- a/src/test/ui/closures/issue-52437.stderr
+++ b/src/test/ui/closures/issue-52437.stderr
@@ -4,12 +4,19 @@ error: invalid label name `'static`
 LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
    |             ^^^^^^^
 
+error[E0744]: `loop` is not allowed in a `const`
+  --> $DIR/issue-52437.rs:2:13
+   |
+LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0282]: type annotations needed
   --> $DIR/issue-52437.rs:2:30
    |
 LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
    |                              ^ consider giving this closure parameter a type
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0282`.
+Some errors have detailed explanations: E0282, E0744.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/consts/const-eval/infinite_loop.rs b/src/test/ui/consts/const-eval/infinite_loop.rs
index 8fa5b0a961f..af5e7658d48 100644
--- a/src/test/ui/consts/const-eval/infinite_loop.rs
+++ b/src/test/ui/consts/const-eval/infinite_loop.rs
@@ -5,10 +5,10 @@ fn main() {
         //~^ WARNING Constant evaluating a complex constant, this might take some time
         let mut n = 113383; // #20 in https://oeis.org/A006884
         while n != 0 {
-        //~^ ERROR constant contains unimplemented expression type
-        //~| ERROR constant contains unimplemented expression type
+        //~^ ERROR `while` is not allowed in a `const`
             n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
             //~^ ERROR evaluation of constant value failed
+            //~| ERROR `if` is not allowed in a `const`
         }
         n
     }];
diff --git a/src/test/ui/consts/const-eval/infinite_loop.stderr b/src/test/ui/consts/const-eval/infinite_loop.stderr
index 68e7fdb1251..2af6af95c55 100644
--- a/src/test/ui/consts/const-eval/infinite_loop.stderr
+++ b/src/test/ui/consts/const-eval/infinite_loop.stderr
@@ -1,20 +1,20 @@
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/infinite_loop.rs:7:15
-   |
-LL |         while n != 0 {
-   |               ^^^^^^
-
-error[E0019]: constant contains unimplemented expression type
+error[E0744]: `while` is not allowed in a `const`
   --> $DIR/infinite_loop.rs:7:9
    |
 LL | /         while n != 0 {
 LL | |
-LL | |
 LL | |             n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
 LL | |
+LL | |
 LL | |         }
    | |_________^
 
+error[E0744]: `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 };
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 warning: Constant evaluating a complex constant, this might take some time
   --> $DIR/infinite_loop.rs:4:18
    |
@@ -29,12 +29,12 @@ LL | |     }];
    | |_____^
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/infinite_loop.rs:10:20
+  --> $DIR/infinite_loop.rs:9:20
    |
 LL |             n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
    |                    ^^^^^^^^^^ duplicate interpreter state observed here, const evaluation will never terminate
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0019, E0080.
-For more information about an error, try `rustc --explain E0019`.
+Some errors have detailed explanations: E0080, E0744.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/issue-52442.rs b/src/test/ui/consts/const-eval/issue-52442.rs
index ea24578c7dd..d820c705161 100644
--- a/src/test/ui/consts/const-eval/issue-52442.rs
+++ b/src/test/ui/consts/const-eval/issue-52442.rs
@@ -1,5 +1,6 @@
 fn main() {
     [();  { &loop { break } as *const _ as usize } ];
     //~^ ERROR casting pointers to integers in constants is unstable
+    //~| ERROR `loop` is not allowed in a `const`
     //~| ERROR evaluation of constant value failed
 }
diff --git a/src/test/ui/consts/const-eval/issue-52442.stderr b/src/test/ui/consts/const-eval/issue-52442.stderr
index 5bd4979bdb3..fa2272f8d63 100644
--- a/src/test/ui/consts/const-eval/issue-52442.stderr
+++ b/src/test/ui/consts/const-eval/issue-52442.stderr
@@ -1,3 +1,9 @@
+error[E0744]: `loop` is not allowed in a `const`
+  --> $DIR/issue-52442.rs:2:14
+   |
+LL |     [();  { &loop { break } as *const _ as usize } ];
+   |              ^^^^^^^^^^^^^^
+
 error[E0658]: casting pointers to integers in constants is unstable
   --> $DIR/issue-52442.rs:2:13
    |
@@ -13,7 +19,7 @@ error[E0080]: evaluation of constant value failed
 LL |     [();  { &loop { break } as *const _ as usize } ];
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0080, E0658.
+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/issue-52475.rs b/src/test/ui/consts/const-eval/issue-52475.rs
index b42249e57fa..3788167f449 100644
--- a/src/test/ui/consts/const-eval/issue-52475.rs
+++ b/src/test/ui/consts/const-eval/issue-52475.rs
@@ -4,8 +4,7 @@ fn main() {
         let mut x = &0;
         let mut n = 0;
         while n < 5 {
-        //~^ ERROR constant contains unimplemented expression type
-        //~| ERROR constant contains unimplemented expression type
+        //~^ ERROR `while` is not allowed in a `const`
             n = (n + 1) % 5; //~ ERROR evaluation of constant value failed
             x = &0; // Materialize a new AllocId
         }
diff --git a/src/test/ui/consts/const-eval/issue-52475.stderr b/src/test/ui/consts/const-eval/issue-52475.stderr
index 1e83cbcff2b..b8267f495de 100644
--- a/src/test/ui/consts/const-eval/issue-52475.stderr
+++ b/src/test/ui/consts/const-eval/issue-52475.stderr
@@ -1,15 +1,8 @@
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/issue-52475.rs:6:15
-   |
-LL |         while n < 5 {
-   |               ^^^^^
-
-error[E0019]: constant contains unimplemented expression type
+error[E0744]: `while` is not allowed in a `const`
   --> $DIR/issue-52475.rs:6:9
    |
 LL | /         while n < 5 {
 LL | |
-LL | |
 LL | |             n = (n + 1) % 5;
 LL | |             x = &0; // Materialize a new AllocId
 LL | |         }
@@ -29,12 +22,12 @@ LL | |     }];
    | |_____^
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/issue-52475.rs:9:17
+  --> $DIR/issue-52475.rs:8:17
    |
 LL |             n = (n + 1) % 5;
    |                 ^^^^^^^^^^^ duplicate interpreter state observed here, const evaluation will never terminate
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0019, E0080.
-For more information about an error, try `rustc --explain E0019`.
+Some errors have detailed explanations: E0080, E0744.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/issue-62272.rs b/src/test/ui/consts/const-eval/issue-62272.rs
index ad8589c7378..19abd91252d 100644
--- a/src/test/ui/consts/const-eval/issue-62272.rs
+++ b/src/test/ui/consts/const-eval/issue-62272.rs
@@ -1,9 +1,11 @@
-// run-pass
+// `loop`s unconditionally-broken-from used to be allowed in constants, but are now forbidden by
+// the HIR const-checker.
+//
+// See https://github.com/rust-lang/rust/pull/66170 and
+// https://github.com/rust-lang/rust/issues/62272.
 
-// Tests that `loop`s unconditionally-broken-from are allowed in constants.
-
-const FOO: () = loop { break; };
+const FOO: () = loop { break; }; //~ ERROR `loop` is not allowed in a `const`
 
 fn main() {
-    [FOO; { let x; loop { x = 5; break; } x }];
+    [FOO; { let x; loop { x = 5; break; } x }]; //~ ERROR `loop` is not allowed in a `const`
 }
diff --git a/src/test/ui/consts/const-eval/issue-62272.stderr b/src/test/ui/consts/const-eval/issue-62272.stderr
new file mode 100644
index 00000000000..573d04f5e47
--- /dev/null
+++ b/src/test/ui/consts/const-eval/issue-62272.stderr
@@ -0,0 +1,15 @@
+error[E0744]: `loop` is not allowed in a `const`
+  --> $DIR/issue-62272.rs:7:17
+   |
+LL | const FOO: () = loop { break; };
+   |                 ^^^^^^^^^^^^^^^
+
+error[E0744]: `loop` is not allowed in a `const`
+  --> $DIR/issue-62272.rs:10:20
+   |
+LL |     [FOO; { let x; loop { x = 5; break; } x }];
+   |                    ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.rs b/src/test/ui/consts/const-eval/match-test-ptr-null.rs
index 5b89b0262ac..80494d16629 100644
--- a/src/test/ui/consts/const-eval/match-test-ptr-null.rs
+++ b/src/test/ui/consts/const-eval/match-test-ptr-null.rs
@@ -5,9 +5,9 @@ fn main() {
     let _: [u8; 0] = [4; {
         match &1 as *const i32 as usize {
             //~^ ERROR casting pointers to integers in constants
-            //~| ERROR constant contains unimplemented expression type
+            //~| ERROR `match` is not allowed in a `const`
             //~| ERROR evaluation of constant value failed
-            0 => 42, //~ ERROR constant contains unimplemented expression type
+            0 => 42,
             n => n,
         }
     }];
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 3d34ac42662..587dca4c1f2 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,3 +1,15 @@
+error[E0744]: `match` is not allowed in a `const`
+  --> $DIR/match-test-ptr-null.rs:6:9
+   |
+LL | /         match &1 as *const i32 as usize {
+LL | |
+LL | |
+LL | |
+LL | |             0 => 42,
+LL | |             n => n,
+LL | |         }
+   | |_________^
+
 error[E0658]: casting pointers to integers in constants is unstable
   --> $DIR/match-test-ptr-null.rs:6:15
    |
@@ -7,25 +19,13 @@ LL |         match &1 as *const i32 as usize {
    = note: for more information, see https://github.com/rust-lang/rust/issues/51910
    = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/match-test-ptr-null.rs:6:15
-   |
-LL |         match &1 as *const i32 as usize {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/match-test-ptr-null.rs:10:13
-   |
-LL |             0 => 42,
-   |             ^
-
 error[E0080]: evaluation of constant value failed
   --> $DIR/match-test-ptr-null.rs:6:15
    |
 LL |         match &1 as *const i32 as usize {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0019, E0080, E0658.
-For more information about an error, try `rustc --explain E0019`.
+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-if.rs b/src/test/ui/consts/const-if.rs
index 9bb5bcc499e..94cce60453d 100644
--- a/src/test/ui/consts/const-if.rs
+++ b/src/test/ui/consts/const-if.rs
@@ -1,5 +1,21 @@
-const _X: i32 = if true { 5 } else { 6 };
-//~^ ERROR constant contains unimplemented expression type
-//~| ERROR constant contains unimplemented expression type
+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
index 655fcdae587..6fb2a0e1501 100644
--- a/src/test/ui/consts/const-if.stderr
+++ b/src/test/ui/consts/const-if.stderr
@@ -1,15 +1,37 @@
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const-if.rs:1:20
+error[E0744]: `if` is not allowed in a `const`
+  --> $DIR/const-if.rs:1:16
    |
-LL | const _X: i32 = if true { 5 } else { 6 };
-   |                    ^^^^
+LL |   const _: i32 = if true {
+   |  ________________^
+LL | |     5
+LL | | } else {
+LL | |     6
+LL | | };
+   | |_^
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const-if.rs:1:17
+error[E0744]: `match` is not allowed in a `const`
+  --> $DIR/const-if.rs:7:16
    |
-LL | const _X: i32 = if true { 5 } else { 6 };
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |   const _: i32 = match 1 {
+   |  ________________^
+LL | |     2 => 3,
+LL | |     4 => 5,
+LL | |     _ => 0,
+LL | | };
+   | |_^
 
-error: aborting due to 2 previous errors
+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 E0019`.
+For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/consts/const-labeled-break.rs b/src/test/ui/consts/const-labeled-break.rs
index 7cdbb22f924..45e3cf43888 100644
--- a/src/test/ui/consts/const-labeled-break.rs
+++ b/src/test/ui/consts/const-labeled-break.rs
@@ -1,10 +1,12 @@
-// build-pass
-
 // Using labeled break in a while loop has caused an illegal instruction being
 // generated, and an ICE later.
 //
 // See https://github.com/rust-lang/rust/issues/51350 for more information.
+//
+// It is now forbidden by the HIR const-checker.
+//
+// See https://github.com/rust-lang/rust/pull/66170.
 
-const CRASH: () = 'a: while break 'a {};
+const CRASH: () = 'a: while break 'a {}; //~ ERROR `while` is not allowed in a `const`
 
 fn main() {}
diff --git a/src/test/ui/consts/const-labeled-break.stderr b/src/test/ui/consts/const-labeled-break.stderr
new file mode 100644
index 00000000000..ec32386439f
--- /dev/null
+++ b/src/test/ui/consts/const-labeled-break.stderr
@@ -0,0 +1,9 @@
+error[E0744]: `while` is not allowed in a `const`
+  --> $DIR/const-labeled-break.rs:10:19
+   |
+LL | const CRASH: () = 'a: while break 'a {};
+   |                   ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+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
index 954f269d30e..b0fe5e320f4 100644
--- a/src/test/ui/consts/const-loop.rs
+++ b/src/test/ui/consts/const-loop.rs
@@ -1,13 +1,47 @@
+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 constant contains unimplemented expression type
-        //~| ERROR constant contains unimplemented expression type
+    while x < 4 { //~ ERROR `while` is not allowed in a `const`
         x += 1;
     }
 
-    while x < 8 {
+    while x < 8 { //~ ERROR `while` is not allowed in a `const`
         x += 1;
     }
 
@@ -17,16 +51,11 @@ const _: i32 = {
 const _: i32 = {
     let mut x = 0;
 
-    for i in 0..4 {
-        //~^ ERROR constant contains unimplemented expression type
-        //~| ERROR constant contains unimplemented expression type
-        //~| ERROR references in constants may only refer to immutable values
-        //~| ERROR calls in constants are limited to constant functions, tuple
-        //         structs and tuple variants
+    for i in 0..4 { //~ ERROR `for` is not allowed in a `const`
         x += i;
     }
 
-    for i in 0..4 {
+    for i in 0..4 { //~ ERROR `for` is not allowed in a `const`
         x += i;
     }
 
@@ -36,18 +65,16 @@ const _: i32 = {
 const _: i32 = {
     let mut x = 0;
 
-    loop {
+    loop { //~ ERROR `loop` is not allowed in a `const`
         x += 1;
-        if x == 4 {
-            //~^ ERROR constant contains unimplemented expression type
-            //~| ERROR constant contains unimplemented expression type
+        if x == 4 { //~ ERROR `if` is not allowed in a `const`
             break;
         }
     }
 
-    loop {
+    loop { //~ ERROR `loop` is not allowed in a `const`
         x += 1;
-        if x == 8 {
+        if x == 8 { //~ ERROR `if` is not allowed in a `const`
             break;
         }
     }
@@ -55,4 +82,9 @@ const _: i32 = {
     x
 };
 
-fn main() {}
+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-loop.stderr b/src/test/ui/consts/const-loop.stderr
index e6e4e2f5bb8..2c96d181759 100644
--- a/src/test/ui/consts/const-loop.stderr
+++ b/src/test/ui/consts/const-loop.stderr
@@ -1,60 +1,127 @@
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const-loop.rs:4:11
+error[E0744]: `loop` is not allowed in a `const`
+  --> $DIR/const-loop.rs:1:15
    |
-LL |     while x < 4 {
-   |           ^^^^^
+LL | const _: () = loop {};
+   |               ^^^^^^^
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const-loop.rs:4:5
+error[E0744]: `loop` is not allowed in a `static`
+  --> $DIR/const-loop.rs:3:19
+   |
+LL | static FOO: i32 = loop { break 4; };
+   |                   ^^^^^^^^^^^^^^^^^
+
+error[E0744]: `loop` is not allowed in a `const fn`
+  --> $DIR/const-loop.rs:6:5
+   |
+LL |     loop {}
+   |     ^^^^^^^
+
+error[E0744]: `loop` is not allowed in a `const fn`
+  --> $DIR/const-loop.rs:19:9
+   |
+LL |         loop {}
+   |         ^^^^^^^
+
+error[E0744]: `while` is not allowed in a `const`
+  --> $DIR/const-loop.rs:31:9
+   |
+LL |         while false {}
+   |         ^^^^^^^^^^^^^^
+
+error[E0744]: `while` is not allowed in a `const`
+  --> $DIR/const-loop.rs:40:5
    |
 LL | /     while x < 4 {
-LL | |
-LL | |
 LL | |         x += 1;
 LL | |     }
    | |_____^
 
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/const-loop.rs:20:14
+error[E0744]: `while` is not allowed in a `const`
+  --> $DIR/const-loop.rs:44:5
+   |
+LL | /     while x < 8 {
+LL | |         x += 1;
+LL | |     }
+   | |_____^
+
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/const-loop.rs:54:5
    |
-LL |     for i in 0..4 {
-   |              ^^^^
+LL | /     for i in 0..4 {
+LL | |         x += i;
+LL | |     }
+   | |_____^
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const-loop.rs:20:14
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/const-loop.rs:58:5
    |
-LL |     for i in 0..4 {
-   |              ^^^^
+LL | /     for i in 0..4 {
+LL | |         x += i;
+LL | |     }
+   | |_____^
 
-error[E0017]: references in constants may only refer to immutable values
-  --> $DIR/const-loop.rs:20:14
+error[E0744]: `loop` is not allowed in a `const`
+  --> $DIR/const-loop.rs:68:5
    |
-LL |     for i in 0..4 {
-   |              ^^^^ constants require immutable values
+LL | /     loop {
+LL | |         x += 1;
+LL | |         if x == 4 {
+LL | |             break;
+LL | |         }
+LL | |     }
+   | |_____^
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const-loop.rs:20:9
+error[E0744]: `if` is not allowed in a `const`
+  --> $DIR/const-loop.rs:70:9
    |
-LL |     for i in 0..4 {
-   |         ^
+LL | /         if x == 4 {
+LL | |             break;
+LL | |         }
+   | |_________^
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const-loop.rs:41:12
+error[E0744]: `loop` is not allowed in a `const`
+  --> $DIR/const-loop.rs:75:5
    |
-LL |         if x == 4 {
-   |            ^^^^^^
+LL | /     loop {
+LL | |         x += 1;
+LL | |         if x == 8 {
+LL | |             break;
+LL | |         }
+LL | |     }
+   | |_____^
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const-loop.rs:41:9
+error[E0744]: `if` is not allowed in a `const`
+  --> $DIR/const-loop.rs:77:9
    |
-LL | /         if x == 4 {
-LL | |
-LL | |
+LL | /         if x == 8 {
 LL | |             break;
 LL | |         }
    | |_________^
 
-error: aborting due to 8 previous errors
+error[E0744]: `while let` is not allowed in a `const`
+  --> $DIR/const-loop.rs:87:5
+   |
+LL |     while let None = Some(x) { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0744]: `while let` is not allowed in a `const`
+  --> $DIR/const-loop.rs:88:5
+   |
+LL |     while let None = Some(x) { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0744]: `loop` is not allowed in a `const`
+  --> $DIR/const-loop.rs:10:22
+   |
+LL |     const BAR: i32 = loop { break 4; };
+   |                      ^^^^^^^^^^^^^^^^^
+
+error[E0744]: `loop` is not allowed in a `const`
+  --> $DIR/const-loop.rs:14:22
+   |
+LL |     const BAR: i32 = loop { break 4; };
+   |                      ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 17 previous errors
 
-Some errors have detailed explanations: E0015, E0017, E0019.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/consts/const-match-pattern-arm.rs b/src/test/ui/consts/const-match-pattern-arm.rs
index 6ed3ac23562..0482f7f7dae 100644
--- a/src/test/ui/consts/const-match-pattern-arm.rs
+++ b/src/test/ui/consts/const-match-pattern-arm.rs
@@ -1,17 +1,13 @@
 #![allow(warnings)]
 
-const x: bool = match Some(true) {
-    //~^ ERROR: constant contains unimplemented expression type [E0019]
+const x: bool = match Some(true) { //~ ERROR `match` is not allowed in a `const`
     Some(value) => true,
-    //~^ ERROR: constant contains unimplemented expression type [E0019]
     _ => false
 };
 
 const y: bool = {
-    match Some(true) {
-    //~^ ERROR: constant contains unimplemented expression type [E0019]
+    match Some(true) { //~ ERROR `match` is not allowed in a `const`
         Some(value) => true,
-        //~^ ERROR: constant contains unimplemented expression type [E0019]
         _ => false
     }
 };
diff --git a/src/test/ui/consts/const-match-pattern-arm.stderr b/src/test/ui/consts/const-match-pattern-arm.stderr
index 709b66b7bf0..57ef349a377 100644
--- a/src/test/ui/consts/const-match-pattern-arm.stderr
+++ b/src/test/ui/consts/const-match-pattern-arm.stderr
@@ -1,27 +1,22 @@
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const-match-pattern-arm.rs:3:23
+error[E0744]: `match` is not allowed in a `const`
+  --> $DIR/const-match-pattern-arm.rs:3:17
    |
-LL | const x: bool = match Some(true) {
-   |                       ^^^^^^^^^^
+LL |   const x: bool = match Some(true) {
+   |  _________________^
+LL | |     Some(value) => true,
+LL | |     _ => false
+LL | | };
+   | |_^
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const-match-pattern-arm.rs:5:5
+error[E0744]: `match` is not allowed in a `const`
+  --> $DIR/const-match-pattern-arm.rs:9:5
    |
-LL |     Some(value) => true,
-   |     ^^^^^^^^^^^
+LL | /     match Some(true) {
+LL | |         Some(value) => true,
+LL | |         _ => false
+LL | |     }
+   | |_____^
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const-match-pattern-arm.rs:11:11
-   |
-LL |     match Some(true) {
-   |           ^^^^^^^^^^
-
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const-match-pattern-arm.rs:13:9
-   |
-LL |         Some(value) => true,
-   |         ^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0019`.
+For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/consts/min_const_fn/loop_ice.rs b/src/test/ui/consts/min_const_fn/loop_ice.rs
index 4278a8e2d00..754a1d7c2a3 100644
--- a/src/test/ui/consts/min_const_fn/loop_ice.rs
+++ b/src/test/ui/consts/min_const_fn/loop_ice.rs
@@ -1,5 +1,5 @@
 const fn foo() {
-    loop {} //~ ERROR loops are not allowed in const fn
+    loop {} //~ ERROR `loop` is not allowed in a `const fn`
 }
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/loop_ice.stderr b/src/test/ui/consts/min_const_fn/loop_ice.stderr
index edf983fc56b..87db65fbb7d 100644
--- a/src/test/ui/consts/min_const_fn/loop_ice.stderr
+++ b/src/test/ui/consts/min_const_fn/loop_ice.stderr
@@ -1,12 +1,9 @@
-error[E0723]: loops are not allowed in const fn
+error[E0744]: `loop` is not allowed in a `const fn`
   --> $DIR/loop_ice.rs:2:5
    |
 LL |     loop {}
    |     ^^^^^^^
-   |
-   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0723`.
+For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs
index db68a05905a..c3436d4840a 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs
@@ -97,10 +97,6 @@ const fn foo30_2(x: *mut u32) -> usize { x as usize }
 //~^ ERROR casting pointers to ints is unstable
 const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
 //~^ ERROR casting pointers to ints is unstable
-const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
-//~^ ERROR loops and conditional expressions are not stable in const fn
-const fn foo30_5(b: bool) { while b { } }
-//~^ ERROR loops are not allowed in const fn
 const fn foo30_6() -> bool { let x = true; x }
 const fn foo36(a: bool, b: bool) -> bool { a && b }
 //~^ ERROR loops and conditional expressions are not stable in const fn
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
index 64b2ce83da2..5ce21e378cd 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
@@ -161,25 +161,7 @@ LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: loops and conditional expressions are not stable in const fn
-  --> $DIR/min_const_fn.rs:100:38
-   |
-LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
-   |                                      ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
-
-error[E0723]: loops are not allowed in const fn
-  --> $DIR/min_const_fn.rs:102:29
-   |
-LL | const fn foo30_5(b: bool) { while b { } }
-   |                             ^^^^^^^^^^^
-   |
-   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
-
-error[E0723]: loops and conditional expressions are not stable in const fn
-  --> $DIR/min_const_fn.rs:105:44
+  --> $DIR/min_const_fn.rs:101:44
    |
 LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
    |                                            ^^^^^^
@@ -188,7 +170,7 @@ LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: loops and conditional expressions are not stable in const fn
-  --> $DIR/min_const_fn.rs:107:44
+  --> $DIR/min_const_fn.rs:103:44
    |
 LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
    |                                            ^^^^^^
@@ -197,7 +179,7 @@ LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: mutable references in const fn are unstable
-  --> $DIR/min_const_fn.rs:109:14
+  --> $DIR/min_const_fn.rs:105:14
    |
 LL | const fn inc(x: &mut i32) { *x += 1 }
    |              ^
@@ -206,7 +188,7 @@ LL | const fn inc(x: &mut i32) { *x += 1 }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:114:6
+  --> $DIR/min_const_fn.rs:110:6
    |
 LL | impl<T: std::fmt::Debug> Foo<T> {
    |      ^
@@ -215,7 +197,7 @@ LL | impl<T: std::fmt::Debug> Foo<T> {
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:119:6
+  --> $DIR/min_const_fn.rs:115:6
    |
 LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
    |      ^
@@ -224,7 +206,7 @@ LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:124:6
+  --> $DIR/min_const_fn.rs:120:6
    |
 LL | impl<T: Sync + Sized> Foo<T> {
    |      ^
@@ -233,7 +215,7 @@ LL | impl<T: Sync + Sized> Foo<T> {
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: `impl Trait` in const fn is unstable
-  --> $DIR/min_const_fn.rs:130:24
+  --> $DIR/min_const_fn.rs:126:24
    |
 LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -242,7 +224,7 @@ LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:132:34
+  --> $DIR/min_const_fn.rs:128:34
    |
 LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
    |                                  ^^^^^^^^^^^^^^^^^^^^
@@ -251,7 +233,7 @@ LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:134:22
+  --> $DIR/min_const_fn.rs:130:22
    |
 LL | const fn no_apit(_x: impl std::fmt::Debug) {}
    |                      ^^^^^^^^^^^^^^^^^^^^
@@ -260,7 +242,7 @@ LL | const fn no_apit(_x: impl std::fmt::Debug) {}
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: `impl Trait` in const fn is unstable
-  --> $DIR/min_const_fn.rs:135:23
+  --> $DIR/min_const_fn.rs:131:23
    |
 LL | const fn no_rpit() -> impl std::fmt::Debug {}
    |                       ^^^^^^^^^^^^^^^^^^^^
@@ -269,7 +251,7 @@ LL | const fn no_rpit() -> impl std::fmt::Debug {}
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:136:23
+  --> $DIR/min_const_fn.rs:132:23
    |
 LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
    |                       ^^
@@ -278,7 +260,7 @@ LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:137:32
+  --> $DIR/min_const_fn.rs:133:32
    |
 LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -287,7 +269,7 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:142:41
+  --> $DIR/min_const_fn.rs:138:41
    |
 LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -296,7 +278,7 @@ LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: function pointers in const fn are unstable
-  --> $DIR/min_const_fn.rs:145:21
+  --> $DIR/min_const_fn.rs:141:21
    |
 LL | const fn no_fn_ptrs(_x: fn()) {}
    |                     ^^
@@ -305,7 +287,7 @@ LL | const fn no_fn_ptrs(_x: fn()) {}
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: function pointers in const fn are unstable
-  --> $DIR/min_const_fn.rs:147:27
+  --> $DIR/min_const_fn.rs:143:27
    |
 LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
    |                           ^^^^
@@ -313,7 +295,7 @@ LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
    = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
-error: aborting due to 36 previous errors
+error: aborting due to 34 previous errors
 
 Some errors have detailed explanations: E0493, E0723.
 For more information about an error, try `rustc --explain E0493`.
diff --git a/src/test/ui/consts/miri_unleashed/enum_discriminants.rs b/src/test/ui/consts/miri_unleashed/enum_discriminants.rs
index 623fa2a1547..d7cdb0babc5 100644
--- a/src/test/ui/consts/miri_unleashed/enum_discriminants.rs
+++ b/src/test/ui/consts/miri_unleashed/enum_discriminants.rs
@@ -20,9 +20,9 @@ const OVERFLOW: usize = {
         C(WithWraparoundInvalidValues),
     }
 
-    let x = Foo::B; //~ WARNING skipping const checks
-    match x {
-        Foo::B => 0, //~ WARNING skipping const checks
+    let x = Foo::B;
+    match x { //~ WARNING skipping const checks
+        Foo::B => 0,
         _ => panic!(),
     }
 };
@@ -87,18 +87,20 @@ const MORE_OVERFLOW: usize = {
 
     if let E1::V2 { .. } = (E1::V1 { f: true }) {
         //~^ WARNING skipping const checks
-        //~| WARNING skipping const checks
         unreachable!()
     }
     if let E1::V1 { .. } = (E1::V1 { f: true }) {
+        //~^ WARNING skipping const checks
     } else {
         unreachable!()
     }
 
     if let E2::V1 { .. } = E2::V3::<Infallible> {
+        //~^ WARNING skipping const checks
         unreachable!()
     }
     if let E2::V3 { .. } = E2::V3::<Infallible> {
+        //~^ WARNING skipping const checks
     } else {
         unreachable!()
     }
diff --git a/src/test/ui/consts/miri_unleashed/enum_discriminants.stderr b/src/test/ui/consts/miri_unleashed/enum_discriminants.stderr
index df366ba22e4..b7fce223af8 100644
--- a/src/test/ui/consts/miri_unleashed/enum_discriminants.stderr
+++ b/src/test/ui/consts/miri_unleashed/enum_discriminants.stderr
@@ -1,24 +1,47 @@
 warning: skipping const checks
-  --> $DIR/enum_discriminants.rs:23:13
+  --> $DIR/enum_discriminants.rs:24:5
    |
-LL |     let x = Foo::B;
-   |             ^^^^^^
+LL | /     match x {
+LL | |         Foo::B => 0,
+LL | |         _ => panic!(),
+LL | |     }
+   | |_____^
 
 warning: skipping const checks
-  --> $DIR/enum_discriminants.rs:25:9
+  --> $DIR/enum_discriminants.rs:88:5
    |
-LL |         Foo::B => 0,
-   |         ^^^^^^
+LL | /     if let E1::V2 { .. } = (E1::V1 { f: true }) {
+LL | |
+LL | |         unreachable!()
+LL | |     }
+   | |_____^
 
 warning: skipping const checks
-  --> $DIR/enum_discriminants.rs:88:28
+  --> $DIR/enum_discriminants.rs:92:5
    |
-LL |     if let E1::V2 { .. } = (E1::V1 { f: true }) {
-   |                            ^^^^^^^^^^^^^^^^^^^^
+LL | /     if let E1::V1 { .. } = (E1::V1 { f: true }) {
+LL | |
+LL | |     } else {
+LL | |         unreachable!()
+LL | |     }
+   | |_____^
 
 warning: skipping const checks
-  --> $DIR/enum_discriminants.rs:88:12
+  --> $DIR/enum_discriminants.rs:98:5
    |
-LL |     if let E1::V2 { .. } = (E1::V1 { f: true }) {
-   |            ^^^^^^^^^^^^^
+LL | /     if let E2::V1 { .. } = E2::V3::<Infallible> {
+LL | |
+LL | |         unreachable!()
+LL | |     }
+   | |_____^
+
+warning: skipping const checks
+  --> $DIR/enum_discriminants.rs:102:5
+   |
+LL | /     if let E2::V3 { .. } = E2::V3::<Infallible> {
+LL | |
+LL | |     } else {
+LL | |         unreachable!()
+LL | |     }
+   | |_____^
 
diff --git a/src/test/ui/consts/single_variant_match_ice.rs b/src/test/ui/consts/single_variant_match_ice.rs
index 75793c90483..80a92c4c965 100644
--- a/src/test/ui/consts/single_variant_match_ice.rs
+++ b/src/test/ui/consts/single_variant_match_ice.rs
@@ -2,11 +2,11 @@ enum Foo {
     Prob,
 }
 
-const FOO: u32 = match Foo::Prob { //~ ERROR unimplemented expression type
+const FOO: u32 = match Foo::Prob { //~ ERROR `match` is not allowed in a `const`
     Foo::Prob => 42,
 };
 
-const BAR: u32 = match Foo::Prob { //~ ERROR unimplemented expression type
+const BAR: u32 = match Foo::Prob { //~ ERROR `match` is not allowed in a `const`
     x => 42,
 };
 
@@ -14,8 +14,7 @@ impl Foo {
     pub const fn as_val(&self) -> u8 {
         use self::Foo::*;
 
-        match *self {
-            //~^ ERROR loops and conditional expressions are not stable in const fn
+        match *self { //~ ERROR `match` is not allowed in a `const fn`
             Prob => 0x1,
         }
     }
diff --git a/src/test/ui/consts/single_variant_match_ice.stderr b/src/test/ui/consts/single_variant_match_ice.stderr
index 3f37a6c6450..780dd0dcddf 100644
--- a/src/test/ui/consts/single_variant_match_ice.stderr
+++ b/src/test/ui/consts/single_variant_match_ice.stderr
@@ -1,25 +1,29 @@
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/single_variant_match_ice.rs:5:24
+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 |   const FOO: u32 = match Foo::Prob {
+   |  __________________^
+LL | |     Foo::Prob => 42,
+LL | | };
+   | |_^
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/single_variant_match_ice.rs:9:24
+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 |   const BAR: u32 = match Foo::Prob {
+   |  __________________^
+LL | |     x => 42,
+LL | | };
+   | |_^
 
-error[E0723]: loops and conditional expressions are not stable in const fn
-  --> $DIR/single_variant_match_ice.rs:17:15
+error[E0744]: `match` is not allowed in a `const fn`
+  --> $DIR/single_variant_match_ice.rs:17:9
    |
-LL |         match *self {
-   |               ^^^^^
-   |
-   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+LL | /         match *self {
+LL | |             Prob => 0x1,
+LL | |         }
+   | |_________^
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0019, E0723.
-For more information about an error, try `rustc --explain E0019`.
+For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/issues/issue-46843.rs b/src/test/ui/issues/issue-46843.rs
index aa252efea46..e5b27136739 100644
--- a/src/test/ui/issues/issue-46843.rs
+++ b/src/test/ui/issues/issue-46843.rs
@@ -5,9 +5,8 @@ fn non_const() -> Thing {
 }
 
 pub const Q: i32 = match non_const() {
-    //~^ ERROR E0015
-    //~^^ ERROR unimplemented expression type
-    Thing::This => 1, //~ ERROR unimplemented expression type
+    //~^ ERROR `match` is not allowed in a `const`
+    Thing::This => 1,
     Thing::That => 0
 };
 
diff --git a/src/test/ui/issues/issue-46843.stderr b/src/test/ui/issues/issue-46843.stderr
index 92ee154552c..9d533297864 100644
--- a/src/test/ui/issues/issue-46843.stderr
+++ b/src/test/ui/issues/issue-46843.stderr
@@ -1,22 +1,14 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/issue-46843.rs:7:26
+error[E0744]: `match` is not allowed in a `const`
+  --> $DIR/issue-46843.rs:7:20
    |
-LL | pub const Q: i32 = match non_const() {
-   |                          ^^^^^^^^^^^
+LL |   pub const Q: i32 = match non_const() {
+   |  ____________________^
+LL | |
+LL | |     Thing::This => 1,
+LL | |     Thing::That => 0
+LL | | };
+   | |_^
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/issue-46843.rs:7:26
-   |
-LL | pub const Q: i32 = match non_const() {
-   |                          ^^^^^^^^^^^
-
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/issue-46843.rs:10:5
-   |
-LL |     Thing::This => 1,
-   |     ^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0015, E0019.
-For more information about an error, try `rustc --explain E0015`.
+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
index f0f1dc6c286..f3f680e7b8e 100644
--- a/src/test/ui/issues/issue-50577.rs
+++ b/src/test/ui/issues/issue-50577.rs
@@ -2,5 +2,8 @@ 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-50577.stderr b/src/test/ui/issues/issue-50577.stderr
index 0c3ba2ea4f9..055a71f468d 100644
--- a/src/test/ui/issues/issue-50577.stderr
+++ b/src/test/ui/issues/issue-50577.stderr
@@ -1,3 +1,27 @@
+error[E0744]: `match` is not allowed in a `const`
+  --> $DIR/issue-50577.rs:3:16
+   |
+LL |         Drop = assert_eq!(1, 1)
+   |                ^^^^^^^^^^^^^^^^
+   |
+   = 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
+   |
+LL |         Drop = assert_eq!(1, 1)
+   |                ^^^^^^^^^^^^^^^^
+   |
+   = 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
+   |
+LL |         Drop = assert_eq!(1, 1)
+   |                ^^^^^^^^^^^^^^^^
+   |
+   = 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
    |
@@ -13,6 +37,7 @@ LL |         Drop = assert_eq!(1, 1)
    = 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
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0317`.
+Some errors have detailed explanations: E0317, E0744.
+For more information about an error, try `rustc --explain E0317`.
diff --git a/src/test/ui/issues/issue-50582.rs b/src/test/ui/issues/issue-50582.rs
index 1358e0bde4c..2d5c9358752 100644
--- a/src/test/ui/issues/issue-50582.rs
+++ b/src/test/ui/issues/issue-50582.rs
@@ -1,4 +1,5 @@
 fn main() {
     Vec::<[(); 1 + for x in 0..1 {}]>::new();
     //~^ ERROR cannot add
+    //~| ERROR `for` is not allowed in a `const`
 }
diff --git a/src/test/ui/issues/issue-50582.stderr b/src/test/ui/issues/issue-50582.stderr
index 226f5a3f0fe..13f6c4d7633 100644
--- a/src/test/ui/issues/issue-50582.stderr
+++ b/src/test/ui/issues/issue-50582.stderr
@@ -1,3 +1,9 @@
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/issue-50582.rs:2:20
+   |
+LL |     Vec::<[(); 1 + for x in 0..1 {}]>::new();
+   |                    ^^^^^^^^^^^^^^^^
+
 error[E0277]: cannot add `()` to `{integer}`
   --> $DIR/issue-50582.rs:2:18
    |
@@ -6,6 +12,7 @@ LL |     Vec::<[(); 1 + for x in 0..1 {}]>::new();
    |
    = help: the trait `std::ops::Add<()>` is not implemented for `{integer}`
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0744.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/issues/issue-50585.rs b/src/test/ui/issues/issue-50585.rs
index ca2ece8d53b..a2f11c98d5a 100644
--- a/src/test/ui/issues/issue-50585.rs
+++ b/src/test/ui/issues/issue-50585.rs
@@ -1,4 +1,5 @@
 fn main() {
     |y: Vec<[(); for x in 0..2 {}]>| {};
     //~^ ERROR mismatched types
+    //~| ERROR `for` is not allowed in a `const`
 }
diff --git a/src/test/ui/issues/issue-50585.stderr b/src/test/ui/issues/issue-50585.stderr
index 4c41da8fc33..8e57c9806e3 100644
--- a/src/test/ui/issues/issue-50585.stderr
+++ b/src/test/ui/issues/issue-50585.stderr
@@ -1,3 +1,9 @@
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/issue-50585.rs:2:18
+   |
+LL |     |y: Vec<[(); for x in 0..2 {}]>| {};
+   |                  ^^^^^^^^^^^^^^^^
+
 error[E0308]: mismatched types
   --> $DIR/issue-50585.rs:2:18
    |
@@ -7,6 +13,7 @@ LL |     |y: Vec<[(); for x in 0..2 {}]>| {};
    = note: expected type `usize`
               found type `()`
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0308, E0744.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-51714.rs b/src/test/ui/issues/issue-51714.rs
index 0dc588d75c6..e0fd7ff896c 100644
--- a/src/test/ui/issues/issue-51714.rs
+++ b/src/test/ui/issues/issue-51714.rs
@@ -10,4 +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`
 }
diff --git a/src/test/ui/issues/issue-51714.stderr b/src/test/ui/issues/issue-51714.stderr
index 023d9013ab4..a3b20cf97f8 100644
--- a/src/test/ui/issues/issue-51714.stderr
+++ b/src/test/ui/issues/issue-51714.stderr
@@ -1,3 +1,9 @@
+error[E0744]: `while let` is not allowed in a `const`
+  --> $DIR/issue-51714.rs:11:17
+   |
+LL |     [(); return while let Some(n) = Some(0) {}];
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0572]: return statement outside of function body
   --> $DIR/issue-51714.rs:2:14
    |
@@ -22,6 +28,7 @@ error[E0572]: return statement outside of function body
 LL |     [(); return while let Some(n) = Some(0) {}];
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0572`.
+Some errors have detailed explanations: E0572, E0744.
+For more information about an error, try `rustc --explain E0572`.
diff --git a/src/test/ui/return/return-match-array-const.rs b/src/test/ui/return/return-match-array-const.rs
index bbcd9600b22..9f3b9651642 100644
--- a/src/test/ui/return/return-match-array-const.rs
+++ b/src/test/ui/return/return-match-array-const.rs
@@ -1,7 +1,13 @@
 fn main() {
-    [(); return match 0 { n => n }]; //~ ERROR: return statement outside of function body
+    [(); return match 0 { n => n }];
+    //~^ ERROR: return statement outside of function body
+    //~| ERROR: `match` is not allowed in a `const`
 
-    [(); return match 0 { 0 => 0 }]; //~ ERROR: return statement outside of function body
+    [(); return match 0 { 0 => 0 }];
+    //~^ ERROR: return statement outside of function body
+    //~| ERROR: `match` is not allowed in a `const`
 
-    [(); return match () { 'a' => 0, _ => 0 }]; //~ ERROR: return statement outside of function body
+    [(); return match () { 'a' => 0, _ => 0 }];
+    //~^ ERROR: return statement outside of function body
+    //~| ERROR: `match` is not allowed in a `const`
 }
diff --git a/src/test/ui/return/return-match-array-const.stderr b/src/test/ui/return/return-match-array-const.stderr
index 6e8c9ed40bb..496e9208b61 100644
--- a/src/test/ui/return/return-match-array-const.stderr
+++ b/src/test/ui/return/return-match-array-const.stderr
@@ -1,3 +1,21 @@
+error[E0744]: `match` is not allowed in a `const`
+  --> $DIR/return-match-array-const.rs:2:17
+   |
+LL |     [(); return match 0 { n => n }];
+   |                 ^^^^^^^^^^^^^^^^^^
+
+error[E0744]: `match` is not allowed in a `const`
+  --> $DIR/return-match-array-const.rs:6:17
+   |
+LL |     [(); return match 0 { 0 => 0 }];
+   |                 ^^^^^^^^^^^^^^^^^^
+
+error[E0744]: `match` is not allowed in a `const`
+  --> $DIR/return-match-array-const.rs:10:17
+   |
+LL |     [(); return match () { 'a' => 0, _ => 0 }];
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0572]: return statement outside of function body
   --> $DIR/return-match-array-const.rs:2:10
    |
@@ -5,17 +23,18 @@ LL |     [(); return match 0 { n => n }];
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0572]: return statement outside of function body
-  --> $DIR/return-match-array-const.rs:4:10
+  --> $DIR/return-match-array-const.rs:6:10
    |
 LL |     [(); return match 0 { 0 => 0 }];
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0572]: return statement outside of function body
-  --> $DIR/return-match-array-const.rs:6:10
+  --> $DIR/return-match-array-const.rs:10:10
    |
 LL |     [(); return match () { 'a' => 0, _ => 0 }];
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0572`.
+Some errors have detailed explanations: E0572, E0744.
+For more information about an error, try `rustc --explain E0572`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
index 7d1e5c3d64d..d5756737f17 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
@@ -216,20 +216,17 @@ fn inside_const_generic_arguments() {
 
     if let A::<{
         true && let 1 = 1 //~ ERROR `let` expressions are not supported here
-        //~^ ERROR constant contains unimplemented expression type
-        //~| ERROR constant contains unimplemented expression type
+        //~| ERROR `match` is not allowed in a `const`
     }>::O = 5 {}
 
     while let A::<{
         true && let 1 = 1 //~ ERROR `let` expressions are not supported here
-        //~^ ERROR constant contains unimplemented expression type
-        //~| ERROR constant contains unimplemented expression type
+        //~| ERROR `match` is not allowed in a `const`
     }>::O = 5 {}
 
     if A::<{
         true && let 1 = 1 //~ ERROR `let` expressions are not supported here
-        //~^ ERROR constant contains unimplemented expression type
-        //~| ERROR constant contains unimplemented expression type
+        //~| ERROR `match` is not allowed in a `const`
     }>::O == 5 {}
 
     // In the cases above we have `ExprKind::Block` to help us out.
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 65de150b100..aa7c342819e 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
@@ -1,5 +1,5 @@
 error: expected one of `,` or `>`, found `&&`
-  --> $DIR/disallowed-positions.rs:242:14
+  --> $DIR/disallowed-positions.rs:239:14
    |
 LL |         true && let 1 = 1
    |              ^^ expected one of `,` or `>`
@@ -482,7 +482,7 @@ LL |         true && let 1 = 1
    = note: as well as when nested within `&&` and parenthesis in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:224:17
+  --> $DIR/disallowed-positions.rs:223:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -491,7 +491,7 @@ LL |         true && let 1 = 1
    = note: as well as when nested within `&&` and parenthesis in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:230:17
+  --> $DIR/disallowed-positions.rs:228:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -513,6 +513,24 @@ 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`
+  --> $DIR/disallowed-positions.rs:218:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^^^^^^^
+
+error[E0744]: `match` is not allowed in a `const`
+  --> $DIR/disallowed-positions.rs:223:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^^^^^^^
+
+error[E0744]: `match` is not allowed in a `const`
+  --> $DIR/disallowed-positions.rs:228:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^^^^^^^
+
 error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:32:8
    |
@@ -953,43 +971,7 @@ LL |         let 0 = 0?;
    = help: the trait `std::ops::Try` is not implemented for `{integer}`
    = note: required by `std::ops::Try::into_result`
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/disallowed-positions.rs:218:25
-   |
-LL |         true && let 1 = 1
-   |                         ^
-
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/disallowed-positions.rs:218:21
-   |
-LL |         true && let 1 = 1
-   |                     ^
-
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/disallowed-positions.rs:224:25
-   |
-LL |         true && let 1 = 1
-   |                         ^
-
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/disallowed-positions.rs:224:21
-   |
-LL |         true && let 1 = 1
-   |                     ^
-
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/disallowed-positions.rs:230:25
-   |
-LL |         true && let 1 = 1
-   |                         ^
-
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/disallowed-positions.rs:230:21
-   |
-LL |         true && let 1 = 1
-   |                     ^
-
-error: aborting due to 109 previous errors
+error: aborting due to 106 previous errors
 
-Some errors have detailed explanations: E0019, E0277, E0308, E0600, E0614.
-For more information about an error, try `rustc --explain E0019`.
+Some errors have detailed explanations: E0277, E0308, E0600, E0614, E0744.
+For more information about an error, try `rustc --explain E0277`.