about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-12-15 01:28:28 +0000
committerbors <bors@rust-lang.org>2019-12-15 01:28:28 +0000
commitfc6b5d6efe163060bde31cc1c801086ed7ebc8f1 (patch)
treeaf12b3b107ab3059dc240c1a913e9b8068ed0577
parent6f829840f7e5897745bc7b5ff951b006a2c4e0e3 (diff)
parentfaa52d1cdaa8806201d56484df0c45bf550bf565 (diff)
downloadrust-fc6b5d6efe163060bde31cc1c801086ed7ebc8f1.tar.gz
rust-fc6b5d6efe163060bde31cc1c801086ed7ebc8f1.zip
Auto merge of #67216 - ecstatic-morse:const-loop, r=oli-obk
Enable `loop` and `while` in constants behind a feature flag

This PR is an initial implementation of #52000. It adds a `const_loop` feature gate, which allows `while` and `loop` expressions through both HIR and MIR const-checkers if enabled. `for` expressions remain forbidden by the HIR const-checker, since they desugar to a call to `IntoIterator::into_iter`, which will be rejected anyways.

`while` loops also require [`#![feature(const_if_match)]`](https://github.com/rust-lang/rust/pull/66507), since they have a conditional built into them. The diagnostics from the HIR const checker will suggest this to the user.

r? @oli-obk
cc @rust-lang/wg-const-eval
-rw-r--r--src/librustc_error_codes/error_codes/E0744.md2
-rw-r--r--src/librustc_feature/active.rs14
-rw-r--r--src/librustc_mir/transform/check_consts/ops.rs4
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs6
-rw-r--r--src/librustc_passes/check_const.rs87
-rw-r--r--src/librustc_passes/lib.rs1
-rw-r--r--src/libsyntax_pos/symbol.rs1
-rw-r--r--src/test/ui/closures/issue-52437.stderr7
-rw-r--r--src/test/ui/consts/const-eval/infinite_loop.stderr8
-rw-r--r--src/test/ui/consts/const-eval/issue-52442.stderr7
-rw-r--r--src/test/ui/consts/const-eval/issue-52475.stderr8
-rw-r--r--src/test/ui/consts/const-eval/issue-62272.stderr12
-rw-r--r--src/test/ui/consts/const-labeled-break.stderr8
-rw-r--r--src/test/ui/consts/control-flow/basics.rs61
-rw-r--r--src/test/ui/consts/control-flow/drop-failure.rs26
-rw-r--r--src/test/ui/consts/control-flow/drop-failure.stderr14
-rw-r--r--src/test/ui/consts/control-flow/drop-success.rs21
-rw-r--r--src/test/ui/consts/control-flow/interior-mutability.rs20
-rw-r--r--src/test/ui/consts/control-flow/interior-mutability.stderr19
-rw-r--r--src/test/ui/consts/control-flow/loop.both.stderr19
-rw-r--r--src/test/ui/consts/control-flow/loop.if_match.stderr98
-rw-r--r--src/test/ui/consts/control-flow/loop.loop_.stderr96
-rw-r--r--src/test/ui/consts/control-flow/loop.rs28
-rw-r--r--src/test/ui/consts/control-flow/loop.stock.stderr104
-rw-r--r--src/test/ui/consts/min_const_fn/loop_ice.stderr7
-rw-r--r--src/test/ui/issues/issue-51714.stderr8
26 files changed, 559 insertions, 127 deletions
diff --git a/src/librustc_error_codes/error_codes/E0744.md b/src/librustc_error_codes/error_codes/E0744.md
index b299102fd69..602fbc50a71 100644
--- a/src/librustc_error_codes/error_codes/E0744.md
+++ b/src/librustc_error_codes/error_codes/E0744.md
@@ -3,7 +3,7 @@ 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
+```compile_fail,E0658
 const _: i32 = {
     let mut x = 0;
     loop {
diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs
index 1e3413b32f0..a386cbf56af 100644
--- a/src/librustc_feature/active.rs
+++ b/src/librustc_feature/active.rs
@@ -52,6 +52,17 @@ macro_rules! declare_features {
             pub fn walk_feature_fields(&self, mut f: impl FnMut(&str, bool)) {
                 $(f(stringify!($feature), self.$feature);)+
             }
+
+            /// Is the given feature enabled?
+            ///
+            /// Panics if the symbol doesn't correspond to a declared feature.
+            pub fn enabled(&self, feature: Symbol) -> bool {
+                match feature {
+                    $( sym::$feature => self.$feature, )*
+
+                    _ => panic!("`{}` was not listed in `declare_features`", feature),
+                }
+            }
         }
     };
 }
@@ -525,6 +536,9 @@ declare_features! (
     /// Allows using `&mut` in constant functions.
     (active, const_mut_refs, "1.41.0", Some(57349), None),
 
+    /// Allows the use of `loop` and `while` in constants.
+    (active, const_loop, "1.41.0", Some(52000), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs
index 393ae9442a1..3df60993d9a 100644
--- a/src/librustc_mir/transform/check_consts/ops.rs
+++ b/src/librustc_mir/transform/check_consts/ops.rs
@@ -170,6 +170,10 @@ impl NonConstOp for LiveDrop {
 #[derive(Debug)]
 pub struct Loop;
 impl NonConstOp for Loop {
+    fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
+        Some(tcx.features().const_loop)
+    }
+
     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 1c95155e7ff..e2530795749 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -390,8 +390,12 @@ fn check_terminator(
             cleanup: _,
         } => check_operand(tcx, cond, span, def_id, body),
 
+        | TerminatorKind::FalseUnwind { .. }
+        if feature_allowed(tcx, def_id, sym::const_loop)
+        => Ok(()),
+
         TerminatorKind::FalseUnwind { .. } => {
             Err((span, "loops are not allowed in const fn".into()))
-        },
+        }
     }
 }
diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs
index 63c6e60de79..725a742382e 100644
--- a/src/librustc_passes/check_const.rs
+++ b/src/librustc_passes/check_const.rs
@@ -13,11 +13,11 @@ use rustc::hir::map::Map;
 use rustc::hir;
 use rustc::ty::TyCtxt;
 use rustc::ty::query::Providers;
-use rustc_feature::Features;
+use rustc::session::config::nightly_options;
 use syntax::ast::Mutability;
 use syntax::feature_gate::feature_err;
 use syntax::span_err;
-use syntax_pos::{sym, Span};
+use syntax_pos::{sym, Span, Symbol};
 use rustc_error_codes::*;
 
 use std::fmt;
@@ -37,18 +37,31 @@ impl NonConstExpr {
         }
     }
 
-    /// 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> {
+    fn required_feature_gates(self) -> Option<&'static [Symbol]> {
         use hir::MatchSource::*;
-        match self {
+        use hir::LoopSource::*;
+
+        let gates: &[_] = match self {
             | Self::Match(Normal)
             | Self::Match(IfDesugar { .. })
             | Self::Match(IfLetDesugar { .. })
-            => Some(features.const_if_match),
+            => &[sym::const_if_match],
 
-            _ => None,
-        }
+            | Self::Loop(Loop)
+            => &[sym::const_loop],
+
+            | Self::Loop(While)
+            | Self::Loop(WhileLet)
+            | Self::Match(WhileDesugar)
+            | Self::Match(WhileLetDesugar)
+            => &[sym::const_loop, sym::const_if_match],
+
+            // A `for` loop's desugaring contains a call to `IntoIterator::into_iter`,
+            // so they are not yet allowed with `#![feature(const_loop)]`.
+            _ => return None,
+        };
+
+        Some(gates)
     }
 }
 
@@ -120,11 +133,15 @@ impl<'tcx> CheckConstVisitor<'tcx> {
 
     /// Emits an error when an unsupported expression is found in a const context.
     fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
-        match expr.is_feature_gate_enabled(self.tcx.features()) {
+        let features = self.tcx.features();
+        let required_gates = expr.required_feature_gates();
+        match required_gates {
             // Don't emit an error if the user has enabled the requisite feature gates.
-            Some(true) => return,
+            Some(gates) if gates.iter().all(|&g| features.enabled(g)) => return,
 
-            // Users of `-Zunleash-the-miri-inside-of-you` must use feature gates when possible.
+            // `-Zunleash-the-miri-inside-of-you` only works for expressions that don't have a
+            // corresponding feature gate. This encourages nightly users to 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;
@@ -135,15 +152,47 @@ impl<'tcx> CheckConstVisitor<'tcx> {
 
         let const_kind = self.const_kind
             .expect("`const_check_violated` may only be called inside a const context");
-
         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 { .. })
-            => feature_err(&self.tcx.sess.parse_sess, sym::const_if_match, span, &msg).emit(),
 
-            _ => span_err!(self.tcx.sess, span, E0744, "{}", msg),
+        let required_gates = required_gates.unwrap_or(&[]);
+        let missing_gates: Vec<_> = required_gates
+            .iter()
+            .copied()
+            .filter(|&g| !features.enabled(g))
+            .collect();
+
+        match missing_gates.as_slice() {
+            &[] => span_err!(self.tcx.sess, span, E0744, "{}", msg),
+
+            // If the user enabled `#![feature(const_loop)]` but not `#![feature(const_if_match)]`,
+            // explain why their `while` loop is being rejected.
+            &[gate @ sym::const_if_match] if required_gates.contains(&sym::const_loop) => {
+                feature_err(&self.tcx.sess.parse_sess, gate, span, &msg)
+                    .note("`#![feature(const_loop)]` alone is not sufficient, \
+                           since this loop expression contains an implicit conditional")
+                    .emit();
+            }
+
+            &[missing_primary, ref missing_secondary @ ..] => {
+                let mut err = feature_err(&self.tcx.sess.parse_sess, missing_primary, span, &msg);
+
+                // If multiple feature gates would be required to enable this expression, include
+                // them as help messages. Don't emit a separate error for each missing feature gate.
+                //
+                // FIXME(ecstaticmorse): Maybe this could be incorporated into `feature_err`? This
+                // is a pretty narrow case, however.
+                if nightly_options::is_nightly_build() {
+                    for gate in missing_secondary {
+                        let note = format!(
+                            "add `#![feature({})]` to the crate attributes to enable",
+                            gate,
+                        );
+                        err.help(&note);
+                    }
+                }
+
+                err.emit();
+            }
         }
     }
 
diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs
index 81f06a14d95..f01867f32c6 100644
--- a/src/librustc_passes/lib.rs
+++ b/src/librustc_passes/lib.rs
@@ -8,6 +8,7 @@
 
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
+#![feature(slice_patterns)]
 
 #![recursion_limit="256"]
 
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index c7e4182de6b..ae34064c926 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -213,6 +213,7 @@ symbols! {
         const_indexing,
         const_in_array_repeat_expressions,
         const_let,
+        const_loop,
         const_mut_refs,
         const_panic,
         const_raw_ptr_deref,
diff --git a/src/test/ui/closures/issue-52437.stderr b/src/test/ui/closures/issue-52437.stderr
index b4b40336aa9..4d13a80e4cc 100644
--- a/src/test/ui/closures/issue-52437.stderr
+++ b/src/test/ui/closures/issue-52437.stderr
@@ -4,11 +4,14 @@ error: invalid label name `'static`
 LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
    |             ^^^^^^^
 
-error[E0744]: `loop` is not allowed in a `const`
+error[E0658]: `loop` is not allowed in a `const`
   --> $DIR/issue-52437.rs:2:13
    |
 LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 error[E0282]: type annotations needed
   --> $DIR/issue-52437.rs:2:30
@@ -18,5 +21,5 @@ LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0282, E0744.
+Some errors have detailed explanations: E0282, E0658.
 For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/consts/const-eval/infinite_loop.stderr b/src/test/ui/consts/const-eval/infinite_loop.stderr
index de2624d7f7a..ed3c66db2cd 100644
--- a/src/test/ui/consts/const-eval/infinite_loop.stderr
+++ b/src/test/ui/consts/const-eval/infinite_loop.stderr
@@ -1,4 +1,4 @@
-error[E0744]: `while` is not allowed in a `const`
+error[E0658]: `while` is not allowed in a `const`
   --> $DIR/infinite_loop.rs:7:9
    |
 LL | /         while n != 0 {
@@ -8,6 +8,10 @@ LL | |
 LL | |
 LL | |         }
    | |_________^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
   --> $DIR/infinite_loop.rs:9:17
@@ -39,5 +43,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, 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-eval/issue-52442.stderr b/src/test/ui/consts/const-eval/issue-52442.stderr
index fa2272f8d63..c8ac4b1a762 100644
--- a/src/test/ui/consts/const-eval/issue-52442.stderr
+++ b/src/test/ui/consts/const-eval/issue-52442.stderr
@@ -1,8 +1,11 @@
-error[E0744]: `loop` is not allowed in a `const`
+error[E0658]: `loop` is not allowed in a `const`
   --> $DIR/issue-52442.rs:2:14
    |
 LL |     [();  { &loop { break } as *const _ as usize } ];
    |              ^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 error[E0658]: casting pointers to integers in constants is unstable
   --> $DIR/issue-52442.rs:2:13
@@ -21,5 +24,5 @@ LL |     [();  { &loop { break } as *const _ 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-eval/issue-52475.stderr b/src/test/ui/consts/const-eval/issue-52475.stderr
index b8267f495de..7c0c735f9a4 100644
--- a/src/test/ui/consts/const-eval/issue-52475.stderr
+++ b/src/test/ui/consts/const-eval/issue-52475.stderr
@@ -1,4 +1,4 @@
-error[E0744]: `while` is not allowed in a `const`
+error[E0658]: `while` is not allowed in a `const`
   --> $DIR/issue-52475.rs:6:9
    |
 LL | /         while n < 5 {
@@ -7,6 +7,10 @@ LL | |             n = (n + 1) % 5;
 LL | |             x = &0; // Materialize a new AllocId
 LL | |         }
    | |_________^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 warning: Constant evaluating a complex constant, this might take some time
   --> $DIR/issue-52475.rs:2:18
@@ -29,5 +33,5 @@ LL |             n = (n + 1) % 5;
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0080, 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-eval/issue-62272.stderr b/src/test/ui/consts/const-eval/issue-62272.stderr
index 573d04f5e47..a02bbe557cf 100644
--- a/src/test/ui/consts/const-eval/issue-62272.stderr
+++ b/src/test/ui/consts/const-eval/issue-62272.stderr
@@ -1,15 +1,21 @@
-error[E0744]: `loop` is not allowed in a `const`
+error[E0658]: `loop` is not allowed in a `const`
   --> $DIR/issue-62272.rs:7:17
    |
 LL | const FOO: () = loop { break; };
    |                 ^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const`
+error[E0658]: `loop` is not allowed in a `const`
   --> $DIR/issue-62272.rs:10:20
    |
 LL |     [FOO; { let x; loop { x = 5; break; } x }];
    |                    ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` 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/const-labeled-break.stderr b/src/test/ui/consts/const-labeled-break.stderr
index ec32386439f..1282008fb63 100644
--- a/src/test/ui/consts/const-labeled-break.stderr
+++ b/src/test/ui/consts/const-labeled-break.stderr
@@ -1,9 +1,13 @@
-error[E0744]: `while` is not allowed in a `const`
+error[E0658]: `while` is not allowed in a `const`
   --> $DIR/const-labeled-break.rs:10:19
    |
 LL | const CRASH: () = 'a: while break 'a {};
    |                   ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = 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 E0744`.
+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
index b9ff0409158..a53293743d5 100644
--- a/src/test/ui/consts/control-flow/basics.rs
+++ b/src/test/ui/consts/control-flow/basics.rs
@@ -1,9 +1,10 @@
-// Test basic functionality of `if` and `match` in a const context.
+// Test basic functionality of control flow in a const context.
 
 // run-pass
 
 #![feature(const_panic)]
 #![feature(const_if_match)]
+#![feature(const_loop)]
 #![feature(const_fn)]
 
 const X: u32 = 4;
@@ -30,15 +31,57 @@ const fn gcd(a: u32, b: u32) -> u32 {
     gcd(b, a % b)
 }
 
+const fn fib(n: u64) -> u64 {
+    if n == 0 {
+        return 0;
+    }
+
+    let mut fib = (0, 1);
+    let mut i = 1;
+    while i < n {
+        fib = (fib.1, fib.0 + fib.1);
+        i += 1;
+    }
+
+    fib.1
+}
+
+const fn is_prime(n: u64) -> bool {
+    if n % 2 == 0 {
+        return false;
+    }
+
+    let mut div = 3;
+    loop {
+        if n % div == 0 {
+            return false;
+        }
+
+        if div * div > n {
+            return true;
+        }
+
+        div += 2;
+    }
+}
+
+macro_rules! const_assert {
+    ($expr:expr) => {
+        const _: () = assert!($expr);
+        assert!($expr);
+    }
+}
+
 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(4, 5) == abs_diff(5, 4));
+    const_assert!(ABS_DIFF == abs_diff(5, 4));
+
+    const_assert!(gcd(48, 18) == 6);
+    const_assert!(gcd(18, 48) == 6);
 
-    const _: () = assert!(ABS_DIFF == abs_diff(5, 4));
-    assert_eq!(ABS_DIFF, abs_diff(5, 4));
+    const_assert!(fib(2) == 1);
+    const_assert!(fib(8) == 21);
 
-    const _: () = assert!(gcd(48, 18) == 6);
-    const _: () = assert!(gcd(18, 48) == 6);
-    assert_eq!(gcd(48, 18), 6);
-    assert_eq!(gcd(18, 48), 6);
+    const_assert!(is_prime(113));
+    const_assert!(!is_prime(117));
 }
diff --git a/src/test/ui/consts/control-flow/drop-failure.rs b/src/test/ui/consts/control-flow/drop-failure.rs
index c6bea89e6e6..9da5546976c 100644
--- a/src/test/ui/consts/control-flow/drop-failure.rs
+++ b/src/test/ui/consts/control-flow/drop-failure.rs
@@ -1,4 +1,5 @@
 #![feature(const_if_match)]
+#![feature(const_loop)]
 
 // `x` is *not* always moved into the final value may be dropped inside the initializer.
 const _: Option<Vec<i32>> = {
@@ -32,4 +33,29 @@ const _: Vec<i32> = {
     }
 };
 
+const _: Option<Vec<i32>> = {
+    let mut some = Some(Vec::new());
+    let mut tmp = None;
+    //~^ ERROR destructors cannot be evaluated at compile-time
+
+    let mut i = 0;
+    while i < 10 {
+        tmp = some;
+        some = None;
+
+        // We can escape the loop with `Some` still in `tmp`,
+        // which would require that it be dropped at the end of the block.
+        if i > 100 {
+            break;
+        }
+
+        some = tmp;
+        tmp = None;
+
+        i += 1;
+    }
+
+    some
+};
+
 fn main() {}
diff --git a/src/test/ui/consts/control-flow/drop-failure.stderr b/src/test/ui/consts/control-flow/drop-failure.stderr
index 35ceb3b2770..3eec3a929a0 100644
--- a/src/test/ui/consts/control-flow/drop-failure.stderr
+++ b/src/test/ui/consts/control-flow/drop-failure.stderr
@@ -1,21 +1,27 @@
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/drop-failure.rs:6:9
+  --> $DIR/drop-failure.rs:7: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
+  --> $DIR/drop-failure.rs:20: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
+  --> $DIR/drop-failure.rs:28:9
    |
 LL |     let x: Result<_, Vec<i32>> = Ok(Vec::new());
    |         ^ constants cannot evaluate destructors
 
-error: aborting due to 3 previous errors
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop-failure.rs:38:9
+   |
+LL |     let mut tmp = None;
+   |         ^^^^^^^ constants cannot evaluate destructors
+
+error: aborting due to 4 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
index 92b3f6ec92e..185d6b63996 100644
--- a/src/test/ui/consts/control-flow/drop-success.rs
+++ b/src/test/ui/consts/control-flow/drop-success.rs
@@ -1,6 +1,7 @@
 // run-pass
 
 #![feature(const_if_match)]
+#![feature(const_loop)]
 
 // `x` is always moved into the final value and is not dropped inside the initializer.
 const _: Option<Vec<i32>> = {
@@ -21,4 +22,24 @@ const _: Option<Vec<i32>> = {
     }
 };
 
+const _: Option<Vec<i32>> = {
+    let mut some = Some(Vec::new());
+    let mut tmp = None;
+
+    let mut i = 0;
+    while i < 10 {
+        tmp = some;
+        some = None;
+
+        // We can never exit the loop with `Some` in `tmp`.
+
+        some = tmp;
+        tmp = None;
+
+        i += 1;
+    }
+
+    some
+};
+
 fn main() {}
diff --git a/src/test/ui/consts/control-flow/interior-mutability.rs b/src/test/ui/consts/control-flow/interior-mutability.rs
index fcced75fcb0..c2439f4a7bf 100644
--- a/src/test/ui/consts/control-flow/interior-mutability.rs
+++ b/src/test/ui/consts/control-flow/interior-mutability.rs
@@ -2,6 +2,7 @@
 // disqualifies it from promotion.
 
 #![feature(const_if_match)]
+#![feature(const_loop)]
 
 use std::cell::Cell;
 
@@ -21,7 +22,26 @@ const Y: Option<Cell<i32>> = {
     y
 };
 
+const Z: Option<Cell<i32>> = {
+    let mut z = None;
+    let mut i = 0;
+    while i < 10 {
+        if i == 8 {
+            z = Some(Cell::new(4));
+        }
+
+        if i == 9 {
+            z = None;
+        }
+
+        i += 1;
+    }
+    z
+};
+
+
 fn main() {
     let x: &'static _ = &X; //~ ERROR temporary value dropped while borrowed
     let y: &'static _ = &Y; //~ ERROR temporary value dropped while borrowed
+    let z: &'static _ = &Z; //~ 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
index 49e8ea3ade7..0977c84d12d 100644
--- a/src/test/ui/consts/control-flow/interior-mutability.stderr
+++ b/src/test/ui/consts/control-flow/interior-mutability.stderr
@@ -1,24 +1,35 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/interior-mutability.rs:25:26
+  --> $DIR/interior-mutability.rs:44: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
+  --> $DIR/interior-mutability.rs:45: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 |     let z: &'static _ = &Z;
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/interior-mutability.rs:46:26
+   |
+LL |     let z: &'static _ = &Z;
+   |            ----------    ^ 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
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0716`.
diff --git a/src/test/ui/consts/control-flow/loop.both.stderr b/src/test/ui/consts/control-flow/loop.both.stderr
new file mode 100644
index 00000000000..71d96b216f9
--- /dev/null
+++ b/src/test/ui/consts/control-flow/loop.both.stderr
@@ -0,0 +1,19 @@
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/loop.rs:63:5
+   |
+LL | /     for i in 0..4 {
+LL | |         x += i;
+LL | |     }
+   | |_____^
+
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/loop.rs:67:5
+   |
+LL | /     for i in 0..4 {
+LL | |         x += i;
+LL | |     }
+   | |_____^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/consts/control-flow/loop.if_match.stderr b/src/test/ui/consts/control-flow/loop.if_match.stderr
index 15b9eb02861..e01081638ec 100644
--- a/src/test/ui/consts/control-flow/loop.if_match.stderr
+++ b/src/test/ui/consts/control-flow/loop.if_match.stderr
@@ -1,51 +1,72 @@
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:8:15
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:10:15
    |
 LL | const _: () = loop {};
    |               ^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `static`
-  --> $DIR/loop.rs:10:19
+error[E0658]: `loop` is not allowed in a `static`
+  --> $DIR/loop.rs:12:19
    |
 LL | static FOO: i32 = loop { break 4; };
    |                   ^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const fn`
-  --> $DIR/loop.rs:13:5
+error[E0658]: `loop` is not allowed in a `const fn`
+  --> $DIR/loop.rs:15:5
    |
 LL |     loop {}
    |     ^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const fn`
-  --> $DIR/loop.rs:26:9
+error[E0658]: `loop` is not allowed in a `const fn`
+  --> $DIR/loop.rs:28:9
    |
 LL |         loop {}
    |         ^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:38:9
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:40:9
    |
 LL |         while false {}
    |         ^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:47:5
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:49:5
    |
 LL | /     while x < 4 {
 LL | |         x += 1;
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:51:5
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:53:5
    |
 LL | /     while x < 8 {
 LL | |         x += 1;
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/loop.rs:61:5
+  --> $DIR/loop.rs:63:5
    |
 LL | /     for i in 0..4 {
 LL | |         x += i;
@@ -53,15 +74,15 @@ LL | |     }
    | |_____^
 
 error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/loop.rs:65:5
+  --> $DIR/loop.rs:67: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
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:77:5
    |
 LL | /     loop {
 LL | |         x += 1;
@@ -70,9 +91,12 @@ LL | |             break;
 LL | |         }
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:82:5
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:84:5
    |
 LL | /     loop {
 LL | |         x += 1;
@@ -81,31 +105,47 @@ LL | |             break;
 LL | |         }
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:94:5
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:96:5
    |
 LL |     while let None = Some(x) { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:95:5
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:97:5
    |
 LL |     while let None = Some(x) { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:17:22
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:19:22
    |
 LL |     const BAR: i32 = loop { break 4; };
    |                      ^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:21:22
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:23:22
    |
 LL |     const BAR: i32 = loop { break 4; };
    |                      ^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 error: aborting due to 15 previous errors
 
-For more information about this error, try `rustc --explain E0744`.
+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/loop.loop_.stderr b/src/test/ui/consts/control-flow/loop.loop_.stderr
new file mode 100644
index 00000000000..cf871c9a78c
--- /dev/null
+++ b/src/test/ui/consts/control-flow/loop.loop_.stderr
@@ -0,0 +1,96 @@
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:40:9
+   |
+LL |         while 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
+   = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
+
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:49:5
+   |
+LL | /     while x < 4 {
+LL | |         x += 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
+   = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
+
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:53:5
+   |
+LL | /     while x < 8 {
+LL | |         x += 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
+   = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
+
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/loop.rs:63:5
+   |
+LL | /     for i in 0..4 {
+LL | |         x += i;
+LL | |     }
+   | |_____^
+
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/loop.rs:67:5
+   |
+LL | /     for i in 0..4 {
+LL | |         x += i;
+LL | |     }
+   | |_____^
+
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/loop.rs:79: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[E0658]: `if` is not allowed in a `const`
+  --> $DIR/loop.rs:86: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[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:96:5
+   |
+LL |     while let None = Some(x) { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
+
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:97:5
+   |
+LL |     while let None = Some(x) { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
+
+error: aborting due to 9 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/loop.rs b/src/test/ui/consts/control-flow/loop.rs
index 4be341f2d38..bc57f7568a7 100644
--- a/src/test/ui/consts/control-flow/loop.rs
+++ b/src/test/ui/consts/control-flow/loop.rs
@@ -1,9 +1,11 @@
-// Ensure that all loops are forbidden in a const context, even if `#![feature(const_if_match)]` is
-// enabled.
+// Ensure that loops are forbidden in a const context unless `#![feature(const_loop)]` is enabled.
+// `while` loops require `#![feature(const_if_match)]` to be enabled as well.
 
-// revisions: stock if_match
+// gate-test-const_loop
+// revisions: stock if_match loop_ both
 
-#![cfg_attr(if_match, feature(const_if_match))]
+#![cfg_attr(any(both, if_match), feature(const_if_match))]
+#![cfg_attr(any(both, loop_), feature(const_loop))]
 
 const _: () = loop {}; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
 
@@ -36,7 +38,7 @@ const fn const_outside() {
 fn main() {
     let x = [0; {
         while false {}
-        //[stock,if_match]~^ ERROR `while` is not allowed in a `const`
+        //[stock,if_match,loop_]~^ ERROR `while` is not allowed in a `const`
         4
     }];
 }
@@ -44,11 +46,11 @@ fn main() {
 const _: i32 = {
     let mut x = 0;
 
-    while x < 4 { //[stock,if_match]~ ERROR `while` is not allowed in a `const`
+    while x < 4 { //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
         x += 1;
     }
 
-    while x < 8 { //[stock,if_match]~ ERROR `while` is not allowed in a `const`
+    while x < 8 { //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
         x += 1;
     }
 
@@ -58,11 +60,11 @@ const _: i32 = {
 const _: i32 = {
     let mut x = 0;
 
-    for i in 0..4 { //[stock,if_match]~ ERROR `for` is not allowed in a `const`
+    for i in 0..4 { //[stock,if_match,loop_,both]~ 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`
+    for i in 0..4 { //[stock,if_match,loop_,both]~ ERROR `for` is not allowed in a `const`
         x += i;
     }
 
@@ -74,14 +76,14 @@ const _: i32 = {
 
     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`
+        if x == 4 { //[stock,loop_]~ 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`
+        if x == 8 { //[stock,loop_]~ ERROR `if` is not allowed in a `const`
             break;
         }
     }
@@ -91,7 +93,7 @@ const _: i32 = {
 
 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`
+    while let None = Some(x) { } //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
+    while let None = Some(x) { } //[stock,if_match,loop_]~ 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
index bb651d23179..e3687cf12ac 100644
--- a/src/test/ui/consts/control-flow/loop.stock.stderr
+++ b/src/test/ui/consts/control-flow/loop.stock.stderr
@@ -1,51 +1,75 @@
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:8:15
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:10:15
    |
 LL | const _: () = loop {};
    |               ^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `static`
-  --> $DIR/loop.rs:10:19
+error[E0658]: `loop` is not allowed in a `static`
+  --> $DIR/loop.rs:12:19
    |
 LL | static FOO: i32 = loop { break 4; };
    |                   ^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const fn`
-  --> $DIR/loop.rs:13:5
+error[E0658]: `loop` is not allowed in a `const fn`
+  --> $DIR/loop.rs:15:5
    |
 LL |     loop {}
    |     ^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const fn`
-  --> $DIR/loop.rs:26:9
+error[E0658]: `loop` is not allowed in a `const fn`
+  --> $DIR/loop.rs:28:9
    |
 LL |         loop {}
    |         ^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:38:9
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:40:9
    |
 LL |         while false {}
    |         ^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:47:5
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:49:5
    |
 LL | /     while x < 4 {
 LL | |         x += 1;
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:51:5
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:53:5
    |
 LL | /     while x < 8 {
 LL | |         x += 1;
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/loop.rs:61:5
+  --> $DIR/loop.rs:63:5
    |
 LL | /     for i in 0..4 {
 LL | |         x += i;
@@ -53,15 +77,15 @@ LL | |     }
    | |_____^
 
 error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/loop.rs:65:5
+  --> $DIR/loop.rs:67: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
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:77:5
    |
 LL | /     loop {
 LL | |         x += 1;
@@ -70,9 +94,12 @@ LL | |             break;
 LL | |         }
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/loop.rs:77:9
+  --> $DIR/loop.rs:79:9
    |
 LL | /         if x == 4 {
 LL | |             break;
@@ -82,8 +109,8 @@ 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
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:84:5
    |
 LL | /     loop {
 LL | |         x += 1;
@@ -92,9 +119,12 @@ LL | |             break;
 LL | |         }
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/loop.rs:84:9
+  --> $DIR/loop.rs:86:9
    |
 LL | /         if x == 8 {
 LL | |             break;
@@ -104,29 +134,43 @@ 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
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:96:5
    |
 LL |     while let None = Some(x) { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:95:5
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:97:5
    |
 LL |     while let None = Some(x) { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:17:22
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:19:22
    |
 LL |     const BAR: i32 = loop { break 4; };
    |                      ^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:21:22
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:23:22
    |
 LL |     const BAR: i32 = loop { break 4; };
    |                      ^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 error: aborting due to 17 previous errors
 
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 87db65fbb7d..58d1d421133 100644
--- a/src/test/ui/consts/min_const_fn/loop_ice.stderr
+++ b/src/test/ui/consts/min_const_fn/loop_ice.stderr
@@ -1,9 +1,12 @@
-error[E0744]: `loop` is not allowed in a `const fn`
+error[E0658]: `loop` is not allowed in a `const fn`
   --> $DIR/loop_ice.rs:2:5
    |
 LL |     loop {}
    |     ^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 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/issues/issue-51714.stderr b/src/test/ui/issues/issue-51714.stderr
index 001928c3b2f..c3b880200f8 100644
--- a/src/test/ui/issues/issue-51714.stderr
+++ b/src/test/ui/issues/issue-51714.stderr
@@ -1,8 +1,12 @@
-error[E0744]: `while` is not allowed in a `const`
+error[E0658]: `while` is not allowed in a `const`
   --> $DIR/issue-51714.rs:11:17
    |
 LL |     [(); return while let Some(n) = Some(0) {}];
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0572]: return statement outside of function body
   --> $DIR/issue-51714.rs:2:14
@@ -30,5 +34,5 @@ LL |     [(); return while let Some(n) = Some(0) {}];
 
 error: aborting due to 5 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`.