about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/lib.rs1
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/mod.rs40
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/ops.rs244
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs13
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/validation.rs367
-rw-r--r--library/alloc/src/borrow.rs2
-rw-r--r--library/alloc/src/lib.rs2
-rw-r--r--library/alloc/src/raw_vec.rs1
-rw-r--r--library/alloc/tests/lib.rs1
-rw-r--r--library/core/src/alloc/layout.rs1
-rw-r--r--library/core/src/future/mod.rs1
-rw-r--r--library/core/src/lib.rs2
-rw-r--r--library/proc_macro/src/bridge/client.rs5
-rw-r--r--library/proc_macro/src/bridge/scoped_cell.rs1
-rw-r--r--library/proc_macro/src/lib.rs1
-rw-r--r--library/std/src/lib.rs2
-rw-r--r--library/std/src/sys_common/thread_local_key.rs1
-rw-r--r--library/std/src/thread/local.rs2
-rw-r--r--src/test/compile-fail/consts/const-fn-error.rs4
-rw-r--r--src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs4
-rw-r--r--src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr12
-rw-r--r--src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs2
-rw-r--r--src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr9
-rw-r--r--src/test/ui/consts/const-fn-not-safe-for-const.rs2
-rw-r--r--src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs3
-rw-r--r--src/test/ui/consts/const_let_assign3.rs2
-rw-r--r--src/test/ui/consts/const_let_assign3.stderr13
-rw-r--r--src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs5
-rw-r--r--src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr26
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.rs20
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.stderr40
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs9
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr27
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs2
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr9
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs9
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr27
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs6
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr16
-rw-r--r--src/test/ui/consts/miri_unleashed/abi-mismatch.stderr10
-rw-r--r--src/test/ui/consts/unsizing-cast-non-null.rs2
-rw-r--r--src/test/ui/consts/unsizing-cast-non-null.stderr2
-rw-r--r--src/test/ui/consts/unstable-const-fn-in-libcore.rs1
-rw-r--r--src/test/ui/consts/unstable-const-fn-in-libcore.stderr6
-rw-r--r--src/test/ui/parser/fn-header-semantic-fail.rs3
-rw-r--r--src/test/ui/parser/fn-header-semantic-fail.stderr64
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr7
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/stability.rs2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/stability.stderr8
-rw-r--r--src/test/ui/unsafe/ranged_ints2_const.rs4
54 files changed, 791 insertions, 259 deletions
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index 76b84d9da83..480a5d2f18e 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -7,6 +7,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
 #![feature(box_syntax)]
 #![feature(const_fn)] // For the `transmute` in `P::new`
+#![feature(const_fn_transmute)]
 #![feature(const_panic)]
 #![feature(crate_visibility_modifier)]
 #![feature(label_break_value)]
diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs
index c1b4cb5f1a8..8d4efd8ae80 100644
--- a/compiler/rustc_mir/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs
@@ -51,6 +51,12 @@ impl ConstCx<'mir, 'tcx> {
     pub fn const_kind(&self) -> hir::ConstContext {
         self.const_kind.expect("`const_kind` must not be called on a non-const fn")
     }
+
+    pub fn is_const_stable_const_fn(&self) -> bool {
+        self.const_kind == Some(hir::ConstContext::ConstFn)
+            && self.tcx.features().staged_api
+            && is_const_stable_const_fn(self.tcx, self.def_id.to_def_id())
+    }
 }
 
 /// Returns `true` if this `DefId` points to one of the official `panic` lang items.
@@ -63,3 +69,37 @@ pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: S
     attr::allow_internal_unstable(&tcx.sess, attrs)
         .map_or(false, |mut features| features.any(|name| name == feature_gate))
 }
+
+// Returns `true` if the given `const fn` is "const-stable".
+//
+// Panics if the given `DefId` does not refer to a `const fn`.
+//
+// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable"
+// functions can be called in a const-context by users of the stable compiler. "const-stable"
+// functions are subject to more stringent restrictions than "const-unstable" functions: They
+// cannot use unstable features and can only call other "const-stable" functions.
+pub fn is_const_stable_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
+    use attr::{ConstStability, Stability, StabilityLevel};
+
+    // Const-stability is only relevant for `const fn`.
+    assert!(tcx.is_const_fn_raw(def_id));
+
+    // Functions with `#[rustc_const_unstable]` are const-unstable.
+    match tcx.lookup_const_stability(def_id) {
+        Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. }) => return false,
+        Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => return true,
+        None => {}
+    }
+
+    // Functions with `#[unstable]` are const-unstable.
+    //
+    // FIXME(ecstaticmorse): We should keep const-stability attributes wholly separate from normal stability
+    // attributes. `#[unstable]` should be irrelevant.
+    if let Some(Stability { level: StabilityLevel::Unstable { .. }, .. }) =
+        tcx.lookup_stability(def_id)
+    {
+        return false;
+    }
+
+    true
+}
diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs
index 032cbc23a3f..e14dcf92b89 100644
--- a/compiler/rustc_mir/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs
@@ -10,33 +10,34 @@ use rustc_span::{Span, Symbol};
 
 use super::ConstCx;
 
-/// Emits an error if `op` is not allowed in the given const context.
-pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) {
+/// Emits an error and returns `true` if `op` is not allowed in the given const context.
+pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) -> bool {
     debug!("illegal_op: op={:?}", op);
 
     let gate = match op.status_in_item(ccx) {
-        Status::Allowed => return,
+        Status::Allowed => return false,
 
         Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => {
-            let unstable_in_stable = ccx.const_kind() == hir::ConstContext::ConstFn
-                && ccx.tcx.features().enabled(sym::staged_api)
-                && !ccx.tcx.has_attr(ccx.def_id.to_def_id(), sym::rustc_const_unstable)
+            let unstable_in_stable = ccx.is_const_stable_const_fn()
                 && !super::allow_internal_unstable(ccx.tcx, ccx.def_id.to_def_id(), gate);
 
             if unstable_in_stable {
                 ccx.tcx.sess
-                    .struct_span_err(span, &format!("`#[feature({})]` cannot be depended on in a const-stable function", gate.as_str()))
+                    .struct_span_err(
+                        span,
+                        &format!("const-stable function cannot use `#[feature({})]`", gate.as_str()),
+                    )
                     .span_suggestion(
                         ccx.body.span,
                         "if it is not part of the public API, make this function unstably const",
                         concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(),
                         Applicability::HasPlaceholders,
                     )
-                    .help("otherwise `#[allow_internal_unstable]` can be used to bypass stability checks")
+                    .note("otherwise `#[allow_internal_unstable]` can be used to bypass stability checks")
                     .emit();
             }
 
-            return;
+            return unstable_in_stable;
         }
 
         Status::Unstable(gate) => Some(gate),
@@ -45,12 +46,14 @@ pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) {
 
     if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
         ccx.tcx.sess.miri_unleashed_feature(span, gate);
-        return;
+        return false;
     }
 
     op.emit_error(ccx, span);
+    true
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum Status {
     Allowed,
     Unstable(Symbol),
@@ -59,6 +62,8 @@ pub enum Status {
 
 /// An operation that is not *always* allowed in a const context.
 pub trait NonConstOp: std::fmt::Debug {
+    const STOPS_CONST_CHECKING: bool = false;
+
     /// Returns an enum indicating whether this operation is allowed within the given item.
     fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
         Status::Forbidden
@@ -93,6 +98,34 @@ pub trait NonConstOp: std::fmt::Debug {
     }
 }
 
+#[derive(Debug)]
+pub struct Abort;
+impl NonConstOp for Abort {
+    const STOPS_CONST_CHECKING: bool = true;
+
+    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+        mcf_status_in_item(ccx)
+    }
+
+    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+        mcf_emit_error(ccx, span, "abort is not stable in const fn")
+    }
+}
+
+#[derive(Debug)]
+pub struct NonPrimitiveOp;
+impl NonConstOp for NonPrimitiveOp {
+    const STOPS_CONST_CHECKING: bool = true;
+
+    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+        mcf_status_in_item(ccx)
+    }
+
+    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+        mcf_emit_error(ccx, span, "only int, `bool` and `char` operations are stable in const fn")
+    }
+}
+
 /// A function call where the callee is a pointer.
 #[derive(Debug)]
 pub struct FnCallIndirect;
@@ -125,7 +158,8 @@ impl NonConstOp for FnCallNonConst {
 ///
 /// Contains the name of the feature that would allow the use of this function.
 #[derive(Debug)]
-pub struct FnCallUnstable(pub DefId, pub Symbol);
+pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
+
 impl NonConstOp for FnCallUnstable {
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
         let FnCallUnstable(def_id, feature) = *self;
@@ -134,14 +168,52 @@ impl NonConstOp for FnCallUnstable {
             span,
             &format!("`{}` is not yet stable as a const fn", ccx.tcx.def_path_str(def_id)),
         );
-        if nightly_options::is_nightly_build() {
-            err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
+
+        if ccx.is_const_stable_const_fn() {
+            err.help("Const-stable functions can only call other const-stable functions");
+        } else if nightly_options::is_nightly_build() {
+            if let Some(feature) = feature {
+                err.help(&format!(
+                    "add `#![feature({})]` to the crate attributes to enable",
+                    feature
+                ));
+            }
         }
         err.emit();
     }
 }
 
 #[derive(Debug)]
+pub struct FnPtrCast;
+impl NonConstOp for FnPtrCast {
+    const STOPS_CONST_CHECKING: bool = true;
+
+    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+        mcf_status_in_item(ccx)
+    }
+
+    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+        mcf_emit_error(ccx, span, "function pointer casts are not allowed in const fn");
+    }
+}
+
+#[derive(Debug)]
+pub struct Generator;
+impl NonConstOp for Generator {
+    const STOPS_CONST_CHECKING: bool = true;
+
+    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+        // FIXME: This means generator-only MIR is only forbidden in const fn. This is for
+        // compatibility with the old code. Such MIR should be forbidden everywhere.
+        mcf_status_in_item(ccx)
+    }
+
+    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+        mcf_emit_error(ccx, span, "const fn generators are unstable");
+    }
+}
+
+#[derive(Debug)]
 pub struct HeapAllocation;
 impl NonConstOp for HeapAllocation {
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -404,6 +476,24 @@ impl NonConstOp for ThreadLocalAccess {
 }
 
 #[derive(Debug)]
+pub struct Transmute;
+impl NonConstOp for Transmute {
+    const STOPS_CONST_CHECKING: bool = true;
+
+    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+        if ccx.const_kind() != hir::ConstContext::ConstFn {
+            Status::Allowed
+        } else {
+            Status::Unstable(sym::const_fn_transmute)
+        }
+    }
+
+    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+        mcf_emit_error(ccx, span, "can only call `transmute` from const items, not `const fn`");
+    }
+}
+
+#[derive(Debug)]
 pub struct UnionAccess;
 impl NonConstOp for UnionAccess {
     fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
@@ -425,3 +515,131 @@ impl NonConstOp for UnionAccess {
         .emit();
     }
 }
+
+/// See [#64992].
+///
+/// [#64992]: https://github.com/rust-lang/rust/issues/64992
+#[derive(Debug)]
+pub struct UnsizingCast;
+impl NonConstOp for UnsizingCast {
+    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+        mcf_status_in_item(ccx)
+    }
+
+    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+        mcf_emit_error(
+            ccx,
+            span,
+            "unsizing casts to types besides slices are not allowed in const fn",
+        );
+    }
+}
+
+pub mod ty {
+    use super::*;
+
+    #[derive(Debug)]
+    pub struct MutRef;
+    impl NonConstOp for MutRef {
+        const STOPS_CONST_CHECKING: bool = true;
+
+        fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
+            Status::Unstable(sym::const_mut_refs)
+        }
+
+        fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+            mcf_emit_error(ccx, span, "mutable references in const fn are unstable");
+        }
+    }
+
+    #[derive(Debug)]
+    pub struct FnPtr;
+    impl NonConstOp for FnPtr {
+        const STOPS_CONST_CHECKING: bool = true;
+
+        fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+            // FIXME: This attribute a hack to allow the specialization of the `futures` API. See
+            // #59739. We should have a proper feature gate for this.
+            if ccx.tcx.has_attr(ccx.def_id.to_def_id(), sym::rustc_allow_const_fn_ptr) {
+                Status::Allowed
+            } else {
+                mcf_status_in_item(ccx)
+            }
+        }
+
+        fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+            mcf_emit_error(ccx, span, "function pointers in const fn are unstable");
+        }
+    }
+
+    #[derive(Debug)]
+    pub struct ImplTrait;
+    impl NonConstOp for ImplTrait {
+        const STOPS_CONST_CHECKING: bool = true;
+
+        fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+            mcf_status_in_item(ccx)
+        }
+
+        fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+            mcf_emit_error(ccx, span, "`impl Trait` in const fn is unstable");
+        }
+    }
+
+    #[derive(Debug)]
+    pub struct TraitBound;
+    impl NonConstOp for TraitBound {
+        const STOPS_CONST_CHECKING: bool = true;
+
+        fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+            mcf_status_in_item(ccx)
+        }
+
+        fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+            mcf_emit_error(
+                ccx,
+                span,
+                "trait bounds other than `Sized` on const fn parameters are unstable",
+            );
+        }
+    }
+
+    /// A trait bound with the `?const Trait` opt-out
+    #[derive(Debug)]
+    pub struct TraitBoundNotConst;
+    impl NonConstOp for TraitBoundNotConst {
+        const STOPS_CONST_CHECKING: bool = true;
+
+        fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+            Status::Unstable(sym::const_trait_bound_opt_out)
+        }
+
+        fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+            feature_err(
+                &ccx.tcx.sess.parse_sess,
+                sym::const_trait_bound_opt_out,
+                span,
+                "`?const Trait` syntax is unstable",
+            )
+            .emit()
+        }
+    }
+}
+
+fn mcf_status_in_item(ccx: &ConstCx<'_, '_>) -> Status {
+    if ccx.const_kind() != hir::ConstContext::ConstFn {
+        Status::Allowed
+    } else {
+        Status::Unstable(sym::const_fn)
+    }
+}
+
+fn mcf_emit_error(ccx: &ConstCx<'_, '_>, span: Span, msg: &str) {
+    struct_span_err!(ccx.tcx.sess, span, E0723, "{}", msg)
+        .note(
+            "see issue #57563 <https://github.com/rust-lang/rust/issues/57563> \
+             for more information",
+        )
+        .help("add `#![feature(const_fn)]` to the crate attributes to enable")
+        .emit();
+}
diff --git a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
index 0228f2d7de0..0c171bbc464 100644
--- a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
@@ -2,7 +2,7 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{self, BasicBlock, Location};
 use rustc_middle::ty::TyCtxt;
-use rustc_span::{sym, Span};
+use rustc_span::Span;
 
 use super::ops;
 use super::qualifs::{NeedsDrop, Qualif};
@@ -11,13 +11,13 @@ use super::ConstCx;
 
 /// Returns `true` if we should use the more precise live drop checker that runs after drop
 /// elaboration.
-pub fn checking_enabled(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
+pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool {
     // Const-stable functions must always use the stable live drop checker.
-    if tcx.features().staged_api && !tcx.has_attr(def_id.to_def_id(), sym::rustc_const_unstable) {
+    if ccx.is_const_stable_const_fn() {
         return false;
     }
 
-    tcx.features().const_precise_live_drops
+    ccx.tcx.features().const_precise_live_drops
 }
 
 /// Look for live drops in a const context.
@@ -30,12 +30,11 @@ pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body<
         return;
     }
 
-    if !checking_enabled(tcx, def_id) {
+    let ccx = ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) };
+    if !checking_enabled(&ccx) {
         return;
     }
 
-    let ccx = ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) };
-
     let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() };
 
     visitor.visit_body(body);
diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index 0501302b761..7ea3c1d5a6f 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -7,19 +7,21 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::cast::CastTy;
-use rustc_middle::ty::{self, Instance, InstanceDef, TyCtxt};
-use rustc_span::Span;
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::{
+    self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt, TypeAndMut,
+};
+use rustc_span::{sym, Span};
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::{self, TraitEngine};
 
-use std::borrow::Cow;
 use std::ops::Deref;
 
 use super::ops::{self, NonConstOp};
 use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop};
 use super::resolver::FlowSensitiveAnalysis;
 use super::{is_lang_panic_fn, ConstCx, Qualif};
-use crate::const_eval::{is_const_fn, is_unstable_const_fn};
+use crate::const_eval::is_unstable_const_fn;
 use crate::dataflow::impls::MaybeMutBorrowedLocals;
 use crate::dataflow::{self, Analysis};
 
@@ -176,6 +178,8 @@ pub struct Validator<'mir, 'tcx> {
 
     /// The span of the current statement.
     span: Span,
+
+    const_checking_stopped: bool,
 }
 
 impl Deref for Validator<'mir, 'tcx> {
@@ -188,30 +192,60 @@ impl Deref for Validator<'mir, 'tcx> {
 
 impl Validator<'mir, 'tcx> {
     pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self {
-        Validator { span: ccx.body.span, ccx, qualifs: Default::default() }
+        Validator {
+            span: ccx.body.span,
+            ccx,
+            qualifs: Default::default(),
+            const_checking_stopped: false,
+        }
     }
 
     pub fn check_body(&mut self) {
-        let ConstCx { tcx, body, def_id, const_kind, .. } = *self.ccx;
-
-        let use_min_const_fn_checks = (const_kind == Some(hir::ConstContext::ConstFn)
-            && crate::const_eval::is_min_const_fn(tcx, def_id.to_def_id()))
-            && !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you;
-
-        if use_min_const_fn_checks {
-            // Enforce `min_const_fn` for stable `const fn`s.
-            use crate::transform::qualify_min_const_fn::is_min_const_fn;
-            if let Err((span, err)) = is_min_const_fn(tcx, def_id.to_def_id(), &body) {
-                error_min_const_fn_violation(tcx, span, err);
-                return;
+        let ConstCx { tcx, body, def_id, .. } = *self.ccx;
+
+        // HACK: This function has side-effects???? Make sure we call it.
+        let _ = crate::const_eval::is_min_const_fn(tcx, def_id.to_def_id());
+
+        // The local type and predicate checks are not free and only relevant for `const fn`s.
+        if self.const_kind() == hir::ConstContext::ConstFn {
+            // Prevent const trait methods from being annotated as `stable`.
+            // FIXME: Do this as part of stability checking.
+            if self.is_const_stable_const_fn() {
+                let hir_id = tcx.hir().local_def_id_to_hir_id(self.def_id);
+                if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) {
+                    struct_span_err!(
+                        self.ccx.tcx.sess,
+                        self.span,
+                        E0723,
+                        "trait methods cannot be stable const fn"
+                    )
+                    .emit();
+                }
             }
+
+            self.check_item_predicates();
+
+            for local in &body.local_decls {
+                if local.internal {
+                    continue;
+                }
+
+                self.span = local.source_info.span;
+                self.check_local_or_return_ty(local.ty);
+            }
+
+            // impl trait is gone in MIR, so check the return type of a const fn by its signature
+            // instead of the type of the return place.
+            self.span = body.local_decls[RETURN_PLACE].source_info.span;
+            let return_ty = tcx.fn_sig(def_id).output();
+            self.check_local_or_return_ty(return_ty.skip_binder());
         }
 
         self.visit_body(&body);
 
         // Ensure that the end result is `Sync` in a non-thread local `static`.
-        let should_check_for_sync = const_kind
-            == Some(hir::ConstContext::Static(hir::Mutability::Not))
+        let should_check_for_sync = self.const_kind()
+            == hir::ConstContext::Static(hir::Mutability::Not)
             && !tcx.is_thread_local_static(def_id.to_def_id());
 
         if should_check_for_sync {
@@ -226,13 +260,22 @@ impl Validator<'mir, 'tcx> {
 
     /// Emits an error if an expression cannot be evaluated in the current context.
     pub fn check_op(&mut self, op: impl NonConstOp) {
-        ops::non_const(self.ccx, op, self.span);
+        self.check_op_spanned(op, self.span);
     }
 
     /// Emits an error at the given `span` if an expression cannot be evaluated in the current
     /// context.
-    pub fn check_op_spanned(&mut self, op: impl NonConstOp, span: Span) {
-        ops::non_const(self.ccx, op, span);
+    pub fn check_op_spanned<O: NonConstOp>(&mut self, op: O, span: Span) {
+        // HACK: This is for strict equivalence with the old `qualify_min_const_fn` pass, which
+        // only emitted one error per function. It should be removed and the test output updated.
+        if self.const_checking_stopped {
+            return;
+        }
+
+        let err_emitted = ops::non_const(self.ccx, op, span);
+        if err_emitted && O::STOPS_CONST_CHECKING {
+            self.const_checking_stopped = true;
+        }
     }
 
     fn check_static(&mut self, def_id: DefId, span: Span) {
@@ -242,6 +285,100 @@ impl Validator<'mir, 'tcx> {
         );
         self.check_op_spanned(ops::StaticAccess, span)
     }
+
+    fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>) {
+        for ty in ty.walk() {
+            let ty = match ty.unpack() {
+                GenericArgKind::Type(ty) => ty,
+
+                // No constraints on lifetimes or constants, except potentially
+                // constants' types, but `walk` will get to them as well.
+                GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue,
+            };
+
+            match *ty.kind() {
+                ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef),
+                ty::Opaque(..) => self.check_op(ops::ty::ImplTrait),
+                ty::FnPtr(..) => self.check_op(ops::ty::FnPtr),
+
+                ty::Dynamic(preds, _) => {
+                    for pred in preds.iter() {
+                        match pred.skip_binder() {
+                            ty::ExistentialPredicate::AutoTrait(_)
+                            | ty::ExistentialPredicate::Projection(_) => {
+                                self.check_op(ops::ty::TraitBound)
+                            }
+                            ty::ExistentialPredicate::Trait(trait_ref) => {
+                                if Some(trait_ref.def_id) != self.tcx.lang_items().sized_trait() {
+                                    self.check_op(ops::ty::TraitBound)
+                                }
+                            }
+                        }
+                    }
+                }
+                _ => {}
+            }
+        }
+    }
+
+    fn check_item_predicates(&mut self) {
+        let ConstCx { tcx, def_id, .. } = *self.ccx;
+
+        let mut current = def_id.to_def_id();
+        loop {
+            let predicates = tcx.predicates_of(current);
+            for (predicate, _) in predicates.predicates {
+                match predicate.skip_binders() {
+                    ty::PredicateAtom::RegionOutlives(_)
+                    | ty::PredicateAtom::TypeOutlives(_)
+                    | ty::PredicateAtom::WellFormed(_)
+                    | ty::PredicateAtom::Projection(_)
+                    | ty::PredicateAtom::ConstEvaluatable(..)
+                    | ty::PredicateAtom::ConstEquate(..)
+                    | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue,
+                    ty::PredicateAtom::ObjectSafe(_) => {
+                        bug!("object safe predicate on function: {:#?}", predicate)
+                    }
+                    ty::PredicateAtom::ClosureKind(..) => {
+                        bug!("closure kind predicate on function: {:#?}", predicate)
+                    }
+                    ty::PredicateAtom::Subtype(_) => {
+                        bug!("subtype predicate on function: {:#?}", predicate)
+                    }
+                    ty::PredicateAtom::Trait(pred, constness) => {
+                        if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
+                            continue;
+                        }
+                        match pred.self_ty().kind() {
+                            ty::Param(p) => {
+                                let generics = tcx.generics_of(current);
+                                let def = generics.type_param(p, tcx);
+                                let span = tcx.def_span(def.def_id);
+
+                                if constness == hir::Constness::Const {
+                                    self.check_op_spanned(ops::ty::TraitBound, span);
+                                } else if !tcx.features().const_fn
+                                    || self.ccx.is_const_stable_const_fn()
+                                {
+                                    // HACK: We shouldn't need the conditional above, but trait
+                                    // bounds on containing impl blocks are wrongly being marked as
+                                    // "not-const".
+                                    self.check_op_spanned(ops::ty::TraitBound, span);
+                                }
+                            }
+                            // other kinds of bounds are either tautologies
+                            // or cause errors in other passes
+                            _ => continue,
+                        }
+                    }
+                }
+            }
+            match predicates.parent {
+                Some(parent) => current = parent,
+                None => break,
+            }
+        }
+    }
 }
 
 impl Visitor<'tcx> for Validator<'mir, 'tcx> {
@@ -309,11 +446,6 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
 
             Rvalue::Use(_)
             | Rvalue::Repeat(..)
-            | Rvalue::UnaryOp(UnOp::Neg, _)
-            | Rvalue::UnaryOp(UnOp::Not, _)
-            | Rvalue::NullaryOp(NullOp::SizeOf, _)
-            | Rvalue::CheckedBinaryOp(..)
-            | Rvalue::Cast(CastKind::Pointer(_), ..)
             | Rvalue::Discriminant(..)
             | Rvalue::Len(_)
             | Rvalue::Aggregate(..) => {}
@@ -363,6 +495,35 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                 }
             }
 
+            Rvalue::Cast(
+                CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer),
+                _,
+                _,
+            ) => {}
+
+            Rvalue::Cast(
+                CastKind::Pointer(
+                    PointerCast::UnsafeFnPointer
+                    | PointerCast::ClosureFnPointer(_)
+                    | PointerCast::ReifyFnPointer,
+                ),
+                _,
+                _,
+            ) => self.check_op(ops::FnPtrCast),
+
+            Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, cast_ty) => {
+                if let Some(TypeAndMut { ty, .. }) = cast_ty.builtin_deref(true) {
+                    let unsized_ty = self.tcx.struct_tail_erasing_lifetimes(ty, self.param_env);
+
+                    // Casting/coercing things to slices is fine.
+                    if let ty::Slice(_) | ty::Str = unsized_ty.kind() {
+                        return;
+                    }
+                }
+
+                self.check_op(ops::UnsizingCast);
+            }
+
             Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
                 let operand_ty = operand.ty(self.body, self.tcx);
                 let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
@@ -373,8 +534,23 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                 }
             }
 
-            Rvalue::BinaryOp(op, ref lhs, _) => {
-                if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() {
+            Rvalue::NullaryOp(NullOp::SizeOf, _) => {}
+            Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation),
+
+            Rvalue::UnaryOp(_, ref operand) => {
+                let ty = operand.ty(self.body, self.tcx);
+                if !(ty.is_integral() || ty.is_bool()) {
+                    self.check_op(ops::NonPrimitiveOp)
+                }
+            }
+
+            Rvalue::BinaryOp(op, ref lhs, ref rhs)
+            | Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
+                let lhs_ty = lhs.ty(self.body, self.tcx);
+                let rhs_ty = rhs.ty(self.body, self.tcx);
+
+                if let ty::RawPtr(_) | ty::FnPtr(..) = lhs_ty.kind() {
+                    assert_eq!(lhs_ty, rhs_ty);
                     assert!(
                         op == BinOp::Eq
                             || op == BinOp::Ne
@@ -387,10 +563,12 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
 
                     self.check_op(ops::RawPtrComparison);
                 }
-            }
 
-            Rvalue::NullaryOp(NullOp::Box, _) => {
-                self.check_op(ops::HeapAllocation);
+                if !(lhs_ty.is_integral() || lhs_ty.is_bool() || lhs_ty.is_char())
+                    || !(rhs_ty.is_integral() || rhs_ty.is_bool() || rhs_ty.is_char())
+                {
+                    self.check_op(ops::NonPrimitiveOp)
+                }
             }
         }
     }
@@ -491,14 +669,19 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
     }
 
     fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
+        use rustc_target::spec::abi::Abi::RustIntrinsic;
+
         trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
         self.super_terminator(terminator, location);
 
         match &terminator.kind {
             TerminatorKind::Call { func, .. } => {
-                let fn_ty = func.ty(self.body, self.tcx);
+                let ConstCx { tcx, body, def_id: caller, param_env, .. } = *self.ccx;
+                let caller = caller.to_def_id();
+
+                let fn_ty = func.ty(body, tcx);
 
-                let (def_id, substs) = match *fn_ty.kind() {
+                let (mut callee, substs) = match *fn_ty.kind() {
                     ty::FnDef(def_id, substs) => (def_id, substs),
 
                     ty::FnPtr(_) => {
@@ -510,38 +693,80 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                     }
                 };
 
-                // At this point, we are calling a function whose `DefId` is known...
-                if is_const_fn(self.tcx, def_id) {
-                    return;
-                }
-
-                // See if this is a trait method for a concrete type whose impl of that trait is
-                // `const`.
+                // Resolve a trait method call to its concrete implementation, which may be in a
+                // `const` trait impl.
                 if self.tcx.features().const_trait_impl {
-                    let instance = Instance::resolve(self.tcx, self.param_env, def_id, substs);
-                    debug!("Resolving ({:?}) -> {:?}", def_id, instance);
+                    let instance = Instance::resolve(tcx, param_env, callee, substs);
+                    debug!("Resolving ({:?}) -> {:?}", callee, instance);
                     if let Ok(Some(func)) = instance {
                         if let InstanceDef::Item(def) = func.def {
-                            if is_const_fn(self.tcx, def.did) {
-                                return;
-                            }
+                            callee = def.did;
                         }
                     }
                 }
 
-                if is_lang_panic_fn(self.tcx, def_id) {
+                // At this point, we are calling a function, `callee`, whose `DefId` is known...
+
+                if is_lang_panic_fn(tcx, callee) {
                     self.check_op(ops::Panic);
-                } else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) {
-                    // Exempt unstable const fns inside of macros or functions with
-                    // `#[allow_internal_unstable]`.
-                    use crate::transform::qualify_min_const_fn::lib_feature_allowed;
-                    if !self.span.allows_unstable(feature)
-                        && !lib_feature_allowed(self.tcx, self.def_id.to_def_id(), feature)
-                    {
-                        self.check_op(ops::FnCallUnstable(def_id, feature));
+                    return;
+                }
+
+                // HACK: This is to "unstabilize" the `transmute` intrinsic
+                // within const fns. `transmute` is allowed in all other const contexts.
+                // This won't really scale to more intrinsics or functions. Let's allow const
+                // transmutes in const fn before we add more hacks to this.
+                if tcx.fn_sig(callee).abi() == RustIntrinsic
+                    && tcx.item_name(callee) == sym::transmute
+                {
+                    self.check_op(ops::Transmute);
+                    return;
+                }
+
+                if !tcx.is_const_fn_raw(callee) {
+                    self.check_op(ops::FnCallNonConst(callee));
+                    return;
+                }
+
+                // If the `const fn` we are trying to call is not const-stable, ensure that we have
+                // the proper feature gate enabled.
+                if let Some(gate) = is_unstable_const_fn(tcx, callee) {
+                    if self.span.allows_unstable(gate) {
+                        return;
+                    }
+
+                    // Calling an unstable function *always* requires that the corresponding gate
+                    // be enabled, even if the function has `#[allow_internal_unstable(the_gate)]`.
+                    if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate) {
+                        self.check_op(ops::FnCallUnstable(callee, Some(gate)));
+                        return;
+                    }
+
+                    // If this crate is not using stability attributes, or the caller is not claiming to be a
+                    // stable `const fn`, that is all that is required.
+                    if !self.ccx.is_const_stable_const_fn() {
+                        return;
+                    }
+
+                    // Otherwise, we are something const-stable calling a const-unstable fn.
+
+                    if super::allow_internal_unstable(tcx, caller, gate) {
+                        return;
+                    }
+
+                    self.check_op(ops::FnCallUnstable(callee, Some(gate)));
+                    return;
+                }
+
+                // FIXME(ecstaticmorse); For compatibility, we consider `unstable` callees that
+                // have no `rustc_const_stable` attributes to be const-unstable as well. This
+                // should be fixed later.
+                let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none()
+                    && tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable());
+                if callee_is_unstable_unmarked {
+                    if self.ccx.is_const_stable_const_fn() {
+                        self.check_op(ops::FnCallUnstable(callee, None));
                     }
-                } else {
-                    self.check_op(ops::FnCallNonConst(def_id));
                 }
             }
 
@@ -551,7 +776,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
             | TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
                 // If we are checking live drops after drop-elaboration, don't emit duplicate
                 // errors here.
-                if super::post_drop_elaboration::checking_enabled(self.tcx, self.def_id) {
+                if super::post_drop_elaboration::checking_enabled(self.ccx) {
                     return;
                 }
 
@@ -582,37 +807,25 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                 }
             }
 
-            TerminatorKind::InlineAsm { .. } => {
-                self.check_op(ops::InlineAsm);
+            TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),
+            TerminatorKind::Abort => self.check_op(ops::Abort),
+
+            TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
+                self.check_op(ops::Generator)
             }
 
-            // FIXME: Some of these are only caught by `min_const_fn`, but should error here
-            // instead.
-            TerminatorKind::Abort
-            | TerminatorKind::Assert { .. }
+            TerminatorKind::Assert { .. }
             | TerminatorKind::FalseEdge { .. }
             | TerminatorKind::FalseUnwind { .. }
-            | TerminatorKind::GeneratorDrop
             | TerminatorKind::Goto { .. }
             | TerminatorKind::Resume
             | TerminatorKind::Return
             | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::Unreachable
-            | TerminatorKind::Yield { .. } => {}
+            | TerminatorKind::Unreachable => {}
         }
     }
 }
 
-fn error_min_const_fn_violation(tcx: TyCtxt<'_>, span: Span, msg: Cow<'_, str>) {
-    struct_span_err!(tcx.sess, span, E0723, "{}", msg)
-        .note(
-            "see issue #57563 <https://github.com/rust-lang/rust/issues/57563> \
-             for more information",
-        )
-        .help("add `#![feature(const_fn)]` to the crate attributes to enable")
-        .emit();
-}
-
 fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) {
     let ty = body.return_ty();
     tcx.infer_ctxt().enter(|infcx| {
diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs
index e7260f3956c..f801c1ac75b 100644
--- a/library/alloc/src/borrow.rs
+++ b/library/alloc/src/borrow.rs
@@ -217,6 +217,7 @@ impl<B: ?Sized + ToOwned> Cow<'_, B> {
     /// assert!(!bull.is_borrowed());
     /// ```
     #[unstable(feature = "cow_is_borrowed", issue = "65143")]
+    #[rustc_const_unstable(feature = "const_cow_is_borrowed", issue = "65143")]
     pub const fn is_borrowed(&self) -> bool {
         match *self {
             Borrowed(_) => true,
@@ -239,6 +240,7 @@ impl<B: ?Sized + ToOwned> Cow<'_, B> {
     /// assert!(!bull.is_owned());
     /// ```
     #[unstable(feature = "cow_is_borrowed", issue = "65143")]
+    #[rustc_const_unstable(feature = "const_cow_is_borrowed", issue = "65143")]
     pub const fn is_owned(&self) -> bool {
         !self.is_borrowed()
     }
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 5ae4b7cf36a..b33cb3ad8e8 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -86,9 +86,11 @@
 #![feature(cfg_target_has_atomic)]
 #![feature(coerce_unsized)]
 #![feature(const_btree_new)]
+#![feature(const_fn)]
 #![feature(const_generics)]
 #![feature(const_in_array_repeat_expressions)]
 #![feature(cow_is_borrowed)]
+#![feature(const_cow_is_borrowed)]
 #![feature(dispatch_from_dyn)]
 #![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index e33dddc4f98..e6da5990060 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -150,6 +150,7 @@ impl<T> RawVec<T, Global> {
 impl<T, A: AllocRef> RawVec<T, A> {
     /// Like `new`, but parameterized over the choice of allocator for
     /// the returned `RawVec`.
+    #[allow_internal_unstable(const_fn)]
     pub const fn new_in(alloc: A) -> Self {
         // `cap: 0` means "unallocated". zero-sized types are ignored.
         Self { ptr: Unique::dangling(), cap: 0, alloc }
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index 3ee0cfbe747..cff8ff9ac7a 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -1,6 +1,7 @@
 #![feature(allocator_api)]
 #![feature(box_syntax)]
 #![feature(cow_is_borrowed)]
+#![feature(const_cow_is_borrowed)]
 #![feature(drain_filter)]
 #![feature(exact_size_is_empty)]
 #![feature(new_uninit)]
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index a5ddf7619b6..a3fbed2ec12 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -177,6 +177,7 @@ impl Layout {
     /// sentinel value. Types that lazily allocate must track initialization by
     /// some other means.
     #[unstable(feature = "alloc_layout_extra", issue = "55724")]
+    #[rustc_const_unstable(feature = "alloc_layout_extra", issue = "55724")]
     #[inline]
     pub const fn dangling(&self) -> NonNull<u8> {
         // SAFETY: align is guaranteed to be non-zero
diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs
index bec3adfa984..fa5655ca35f 100644
--- a/library/core/src/future/mod.rs
+++ b/library/core/src/future/mod.rs
@@ -56,6 +56,7 @@ unsafe impl Sync for ResumeTy {}
 #[lang = "from_generator"]
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
+#[rustc_const_unstable(feature = "gen_future", issue = "50547")]
 #[inline]
 pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
 where
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 9de0f76cbdd..86eda843c5b 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -75,11 +75,13 @@
 #![feature(const_float_bits_conv)]
 #![feature(const_overflowing_int_methods)]
 #![feature(const_int_unchecked_arith)]
+#![feature(const_mut_refs)]
 #![feature(const_int_pow)]
 #![feature(constctlz)]
 #![feature(const_panic)]
 #![feature(const_pin)]
 #![feature(const_fn_union)]
+#![feature(const_fn)]
 #![feature(const_generics)]
 #![feature(const_option)]
 #![feature(const_precise_live_drops)]
diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs
index 39daad4da12..ba3d4c075e1 100644
--- a/library/proc_macro/src/bridge/client.rs
+++ b/library/proc_macro/src/bridge/client.rs
@@ -401,6 +401,7 @@ fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>(
 }
 
 impl Client<fn(crate::TokenStream) -> crate::TokenStream> {
+    #[allow_internal_unstable(const_fn)]
     pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self {
         extern "C" fn run(
             bridge: Bridge<'_>,
@@ -413,6 +414,7 @@ impl Client<fn(crate::TokenStream) -> crate::TokenStream> {
 }
 
 impl Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> {
+    #[allow_internal_unstable(const_fn)]
     pub const fn expand2(
         f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
     ) -> Self {
@@ -457,6 +459,7 @@ impl ProcMacro {
         }
     }
 
+    #[allow_internal_unstable(const_fn)]
     pub const fn custom_derive(
         trait_name: &'static str,
         attributes: &'static [&'static str],
@@ -465,6 +468,7 @@ impl ProcMacro {
         ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) }
     }
 
+    #[allow_internal_unstable(const_fn)]
     pub const fn attr(
         name: &'static str,
         expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
@@ -472,6 +476,7 @@ impl ProcMacro {
         ProcMacro::Attr { name, client: Client::expand2(expand) }
     }
 
+    #[allow_internal_unstable(const_fn)]
     pub const fn bang(
         name: &'static str,
         expand: fn(crate::TokenStream) -> crate::TokenStream,
diff --git a/library/proc_macro/src/bridge/scoped_cell.rs b/library/proc_macro/src/bridge/scoped_cell.rs
index 2cde1f65adf..daa577f74ba 100644
--- a/library/proc_macro/src/bridge/scoped_cell.rs
+++ b/library/proc_macro/src/bridge/scoped_cell.rs
@@ -35,6 +35,7 @@ impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> {
 pub struct ScopedCell<T: LambdaL>(Cell<<T as ApplyL<'static>>::Out>);
 
 impl<T: LambdaL> ScopedCell<T> {
+    #[allow_internal_unstable(const_fn)]
     pub const fn new(value: <T as ApplyL<'static>>::Out) -> Self {
         ScopedCell(Cell::new(value))
     }
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index c5a871e09a6..f81ffd2bb94 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -20,6 +20,7 @@
 )]
 #![feature(nll)]
 #![feature(staged_api)]
+#![feature(const_fn)]
 #![feature(allow_internal_unstable)]
 #![feature(decl_macro)]
 #![feature(extern_types)]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 70533189d8e..309657e7042 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -237,6 +237,7 @@
 #![feature(concat_idents)]
 #![feature(const_cstr_unchecked)]
 #![feature(const_fn_transmute)]
+#![feature(const_fn)]
 #![feature(const_ipv6)]
 #![feature(const_raw_ptr_deref)]
 #![feature(const_ipv4)]
@@ -306,6 +307,7 @@
 #![feature(str_internals)]
 #![feature(test)]
 #![feature(thread_local)]
+#![feature(thread_local_internals)]
 #![feature(toowned_clone_into)]
 #![feature(total_cmp)]
 #![feature(trace_macros)]
diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs
index 3a2218854a7..676eadd1fac 100644
--- a/library/std/src/sys_common/thread_local_key.rs
+++ b/library/std/src/sys_common/thread_local_key.rs
@@ -117,6 +117,7 @@ pub struct Key {
 pub const INIT: StaticKey = StaticKey::new(None);
 
 impl StaticKey {
+    #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
     pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> StaticKey {
         StaticKey { key: atomic::AtomicUsize::new(0), dtor }
     }
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 60a05dc5d54..784b376fcdc 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -225,6 +225,7 @@ impl<T: 'static> LocalKey<T> {
         reason = "recently added to create a key",
         issue = "none"
     )]
+    #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
     pub const unsafe fn new(inner: unsafe fn() -> Option<&'static T>) -> LocalKey<T> {
         LocalKey { inner }
     }
@@ -497,6 +498,7 @@ pub mod os {
     }
 
     impl<T: 'static> Key<T> {
+        #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
         pub const fn new() -> Key<T> {
             Key { os: OsStaticKey::new(Some(destroy_value::<T>)), marker: marker::PhantomData }
         }
diff --git a/src/test/compile-fail/consts/const-fn-error.rs b/src/test/compile-fail/consts/const-fn-error.rs
index 7dbf7d1a386..64474878603 100644
--- a/src/test/compile-fail/consts/const-fn-error.rs
+++ b/src/test/compile-fail/consts/const-fn-error.rs
@@ -5,9 +5,7 @@ const X : usize = 2;
 const fn f(x: usize) -> usize {
     let mut sum = 0;
     for i in 0..x {
-        //~^ ERROR E0015
-        //~| ERROR E0015
-        //~| ERROR E0658
+        //~^ ERROR mutable references
         //~| ERROR E0080
         //~| ERROR E0744
         sum += i;
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs
index 6469a65700d..e18e0a83573 100644
--- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs
+++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs
@@ -7,7 +7,7 @@ extern "C" {
 const extern fn bar() {
     unsafe {
         regular_in_block();
-        //~^ ERROR: can only call other `const fn` within a `const fn`
+        //~^ ERROR: calls in constant functions
     }
 }
 
@@ -16,7 +16,7 @@ extern fn regular() {}
 const extern fn foo() {
     unsafe {
         regular();
-        //~^ ERROR: can only call other `const fn` within a `const fn`
+        //~^ ERROR: calls in constant functions
     }
 }
 
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr
index a9e2bcdbdd1..348387ff5f8 100644
--- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr
+++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr
@@ -1,21 +1,15 @@
-error[E0723]: can only call other `const fn` within a `const fn`, but `regular_in_block` is not stable as `const fn`
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
   --> $DIR/const-extern-fn-call-extern-fn.rs:9:9
    |
 LL |         regular_in_block();
    |         ^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
-error[E0723]: can only call other `const fn` within a `const fn`, but `regular` is not stable as `const fn`
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
   --> $DIR/const-extern-fn-call-extern-fn.rs:18:9
    |
 LL |         regular();
    |         ^^^^^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0723`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs
index 2854c086657..e0b9e5f3375 100644
--- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs
+++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs
@@ -6,7 +6,7 @@ const unsafe extern "C" fn closure() -> fn() { || {} }
 const unsafe extern fn use_float() { 1.0 + 1.0; }
 //~^ ERROR only int, `bool` and `char` operations are stable in const fn
 const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
-//~^ ERROR casting pointers to ints is unstable in const fn
+//~^ ERROR casting pointers to integers
 
 
 fn main() {}
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr
index 146d119fc8f..5ca44b3fa7e 100644
--- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr
+++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr
@@ -16,15 +16,16 @@ LL | const unsafe extern fn use_float() { 1.0 + 1.0; }
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
-error[E0723]: casting pointers to ints is unstable in const fn
+error[E0658]: casting pointers to integers in constant functions is unstable
   --> $DIR/const-extern-fn-min-const-fn.rs:8:48
    |
 LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
    |                                                ^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
+   = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0723`.
+Some errors have detailed explanations: E0658, E0723.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/const-fn-not-safe-for-const.rs b/src/test/ui/consts/const-fn-not-safe-for-const.rs
index 085ff5c58e6..0446ece421e 100644
--- a/src/test/ui/consts/const-fn-not-safe-for-const.rs
+++ b/src/test/ui/consts/const-fn-not-safe-for-const.rs
@@ -1,6 +1,6 @@
 // Test that we can't call random fns in a const fn or do other bad things.
 
-#![feature(const_fn, const_transmute)]
+#![feature(const_fn, const_fn_transmute)]
 
 use std::mem::transmute;
 
diff --git a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs
index 2207599815e..f31543af590 100644
--- a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs
+++ b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs
@@ -2,6 +2,7 @@ fn main() {
     foo(&mut 5);
 }
 
-const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references in const fn are unstable
+const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references in const fn
     *x + 1
+
 }
diff --git a/src/test/ui/consts/const_let_assign3.rs b/src/test/ui/consts/const_let_assign3.rs
index f993a427b48..9d5ccb880aa 100644
--- a/src/test/ui/consts/const_let_assign3.rs
+++ b/src/test/ui/consts/const_let_assign3.rs
@@ -6,8 +6,8 @@ struct S {
 
 impl S {
     const fn foo(&mut self, x: u32) {
+        //~^ ERROR mutable references
         self.state = x;
-        //~^ contains unimplemented expression
     }
 }
 
diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr
index dd05a4c0bb0..785d9c8c2a5 100644
--- a/src/test/ui/consts/const_let_assign3.stderr
+++ b/src/test/ui/consts/const_let_assign3.stderr
@@ -1,10 +1,11 @@
-error[E0019]: constant function contains unimplemented expression type
-  --> $DIR/const_let_assign3.rs:9:9
+error[E0723]: mutable references in const fn are unstable
+  --> $DIR/const_let_assign3.rs:8:18
    |
-LL |         self.state = x;
-   |         ^^^^^^^^^^^^^^
+LL |     const fn foo(&mut self, x: u32) {
+   |                  ^^^^^^^^^
    |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0764]: mutable references are not allowed in constants
   --> $DIR/const_let_assign3.rs:16:5
@@ -28,5 +29,5 @@ LL |     *y = 42;
 
 error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0019, E0764.
+Some errors have detailed explanations: E0019, E0723, E0764.
 For more information about an error, try `rustc --explain E0019`.
diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs
index 3e42cb8c1b0..589085871fb 100644
--- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs
+++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs
@@ -1,5 +1,8 @@
 const fn foo(a: i32) -> Vec<i32> {
-    vec![1, 2, 3] //~ ERROR heap allocations are not allowed in const fn
+    vec![1, 2, 3]
+    //~^ ERROR allocations are not allowed
+    //~| ERROR unimplemented expression type
+    //~| ERROR calls in constant functions
 }
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr
index 39b223062e9..0f16890141f 100644
--- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr
+++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr
@@ -1,13 +1,29 @@
-error[E0723]: heap allocations are not allowed in const fn
+error[E0010]: allocations are not allowed in constant functions
+  --> $DIR/bad_const_fn_body_ice.rs:2:5
+   |
+LL |     vec![1, 2, 3]
+   |     ^^^^^^^^^^^^^ allocation not allowed in constant functions
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0019]: constant function contains unimplemented expression type
+  --> $DIR/bad_const_fn_body_ice.rs:2:5
+   |
+LL |     vec![1, 2, 3]
+   |     ^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
   --> $DIR/bad_const_fn_body_ice.rs:2:5
    |
 LL |     vec![1, 2, 3]
    |     ^^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0723`.
+Some errors have detailed explanations: E0010, E0015, E0019.
+For more information about an error, try `rustc --explain E0010`.
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 2ebd9dd10c5..5dd70acb6ff 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
@@ -78,25 +78,25 @@ const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
 const fn foo11_2<T: Send>(t: T) -> T { t }
 //~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
 const fn foo19(f: f32) -> f32 { f * 2.0 }
-//~^ ERROR only int, `bool` and `char` operations are stable in const fn
+//~^ ERROR int, `bool` and `char` operations
 const fn foo19_2(f: f32) -> f32 { 2.0 - f }
-//~^ ERROR only int, `bool` and `char` operations are stable in const fn
+//~^ ERROR int, `bool` and `char` operations
 const fn foo19_3(f: f32) -> f32 { -f }
-//~^ ERROR only int and `bool` operations are stable in const fn
+//~^ ERROR int, `bool` and `char` operations
 const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
-//~^ ERROR only int, `bool` and `char` operations are stable in const fn
+//~^ ERROR int, `bool` and `char` operations
 
 static BAR: u32 = 42;
-const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn
-const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items
+const fn foo25() -> u32 { BAR } //~ ERROR cannot refer to statics
+const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot refer to statics
 const fn foo30(x: *const u32) -> usize { x as usize }
-//~^ ERROR casting pointers to ints is unstable
+//~^ ERROR casting pointers to integers
 const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
-//~^ ERROR casting pointers to ints is unstable
+//~^ ERROR casting pointers to integers
 const fn foo30_2(x: *mut u32) -> usize { x as usize }
-//~^ ERROR casting pointers to ints is unstable
+//~^ ERROR casting pointers to integers
 const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
-//~^ ERROR casting pointers to ints is unstable
+//~^ ERROR casting pointers to integers
 const fn foo30_6() -> bool { let x = true; x }
 const fn inc(x: &mut i32) { *x += 1 }
 //~^ ERROR mutable references in const fn are unstable
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 9b55b6c6f3b..d4498f061c6 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
@@ -94,7 +94,7 @@ LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f }
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
-error[E0723]: only int and `bool` operations are stable in const fn
+error[E0723]: only int, `bool` and `char` operations are stable in const fn
   --> $DIR/min_const_fn.rs:84:35
    |
 LL | const fn foo19_3(f: f32) -> f32 { -f }
@@ -112,59 +112,57 @@ LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
-error[E0723]: cannot access `static` items in const fn
+error[E0013]: constant functions cannot refer to statics
   --> $DIR/min_const_fn.rs:90:27
    |
 LL | const fn foo25() -> u32 { BAR }
    |                           ^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
 
-error[E0723]: cannot access `static` items in const fn
+error[E0013]: constant functions cannot refer to statics
   --> $DIR/min_const_fn.rs:91:37
    |
 LL | const fn foo26() -> &'static u32 { &BAR }
    |                                     ^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
 
-error[E0723]: casting pointers to ints is unstable in const fn
+error[E0658]: casting pointers to integers in constant functions is unstable
   --> $DIR/min_const_fn.rs:92:42
    |
 LL | const fn foo30(x: *const u32) -> usize { x as usize }
    |                                          ^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
+   = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
 
-error[E0723]: casting pointers to ints is unstable in const fn
+error[E0658]: casting pointers to integers in constant functions is unstable
   --> $DIR/min_const_fn.rs:94:63
    |
 LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
    |                                                               ^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
+   = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
 
-error[E0723]: casting pointers to ints is unstable in const fn
+error[E0658]: casting pointers to integers in constant functions is unstable
   --> $DIR/min_const_fn.rs:96:42
    |
 LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
    |                                          ^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
+   = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
 
-error[E0723]: casting pointers to ints is unstable in const fn
+error[E0658]: casting pointers to integers in constant functions is unstable
   --> $DIR/min_const_fn.rs:98:63
    |
 LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
    |                                                               ^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
+   = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
 
 error[E0723]: mutable references in const fn are unstable
   --> $DIR/min_const_fn.rs:101:14
@@ -267,5 +265,5 @@ LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
 
 error: aborting due to 30 previous errors
 
-Some errors have detailed explanations: E0493, E0723.
-For more information about an error, try `rustc --explain E0493`.
+Some errors have detailed explanations: E0013, E0493, E0658, E0723.
+For more information about an error, try `rustc --explain E0013`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
index df10f3496c3..b83fdf7c656 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
@@ -13,7 +13,7 @@ const fn foo() -> u32 { 42 }
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn`
+const fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn
 
 #[unstable(feature = "rust1", issue = "none")]
 const fn foo2() -> u32 { 42 }
@@ -21,12 +21,13 @@ const fn foo2() -> u32 { 42 }
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn`
+const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // conformity is required, even with `const_fn` feature gate
-const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` operations
+const fn bar3() -> u32 { (5f32 + 6f32) as u32 }
+//~^ ERROR const-stable function cannot use `#[feature(const_fn)]`
 
 // check whether this function cannot be called even with the feature gate active
 #[unstable(feature = "foo2", issue = "none")]
@@ -35,6 +36,6 @@ const fn foo2_gated() -> u32 { 42 }
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn`
+const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
index bef4f240eeb..a1f1f6f52ab 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
@@ -1,39 +1,38 @@
-error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn`
+error: `foo` is not yet stable as a const fn
   --> $DIR/min_const_fn_libstd_stability.rs:16:25
    |
 LL | const fn bar() -> u32 { foo() }
    |                         ^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: Const-stable functions can only call other const-stable functions
 
-error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn`
+error: `foo2` is not yet stable as a const fn
   --> $DIR/min_const_fn_libstd_stability.rs:24:26
    |
 LL | const fn bar2() -> u32 { foo2() }
    |                          ^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: Const-stable functions can only call other const-stable functions
 
-error[E0723]: only int, `bool` and `char` operations are stable in const fn
+error: const-stable function cannot use `#[feature(const_fn)]`
   --> $DIR/min_const_fn_libstd_stability.rs:29:26
    |
 LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 }
    |                          ^^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = note: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks
+help: if it is not part of the public API, make this function unstably const
+   |
+LL | #[rustc_const_unstable(feature = "...", issue = "...")]
+   |
 
-error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn`
-  --> $DIR/min_const_fn_libstd_stability.rs:38:32
+error: `foo2_gated` is not yet stable as a const fn
+  --> $DIR/min_const_fn_libstd_stability.rs:39:32
    |
 LL | const fn bar2_gated() -> u32 { foo2_gated() }
    |                                ^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: Const-stable functions can only call other const-stable functions
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0723`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs
index 6462d736ad1..0c8af5a199a 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs
@@ -12,5 +12,5 @@ fn main() {}
 const unsafe fn no_union() {
     union Foo { x: (), y: () }
     Foo { x: () }.y
-    //~^ accessing union fields is unstable
+    //~^ unions in const fn
 }
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr
index 427ecff5c6d..322052c28fa 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr
@@ -25,16 +25,15 @@ LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static u
    = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
    = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
 
-error[E0723]: accessing union fields is unstable
+error[E0658]: unions in const fn are unstable
   --> $DIR/min_const_fn_unsafe_bad.rs:14:5
    |
 LL |     Foo { x: () }.y
    |     ^^^^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = note: see issue #51909 <https://github.com/rust-lang/rust/issues/51909> for more information
+   = help: add `#![feature(const_fn_union)]` to the crate attributes to enable
 
 error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0658, E0723.
-For more information about an error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
index 12b41ee2b0d..902ed435e31 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
@@ -13,7 +13,7 @@ const unsafe fn foo() -> u32 { 42 }
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `const fn`
+const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR not yet stable as a const fn
 
 #[unstable(feature = "rust1", issue = "none")]
 const unsafe fn foo2() -> u32 { 42 }
@@ -21,12 +21,13 @@ const unsafe fn foo2() -> u32 { 42 }
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `const fn`
+const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as a const fn
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // conformity is required, even with `const_fn` feature gate
-const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op
+const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 }
+//~^ ERROR const-stable function cannot use `#[feature(const_fn)]`
 
 // check whether this function cannot be called even with the feature gate active
 #[unstable(feature = "foo2", issue = "none")]
@@ -36,6 +37,6 @@ const unsafe fn foo2_gated() -> u32 { 42 }
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
-//~^ ERROR can only call other `const fn`
+//~^ ERROR not yet stable as a const fn
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
index c5ff340dfc6..2741a864404 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
@@ -1,39 +1,38 @@
-error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn`
+error: `foo` is not yet stable as a const fn
   --> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41
    |
 LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
    |                                         ^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: Const-stable functions can only call other const-stable functions
 
-error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn`
+error: `foo2` is not yet stable as a const fn
   --> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42
    |
 LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
    |                                          ^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: Const-stable functions can only call other const-stable functions
 
-error[E0723]: only int, `bool` and `char` operations are stable in const fn
+error: const-stable function cannot use `#[feature(const_fn)]`
   --> $DIR/min_const_unsafe_fn_libstd_stability.rs:29:33
    |
 LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 }
    |                                 ^^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = note: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks
+help: if it is not part of the public API, make this function unstably const
+   |
+LL | #[rustc_const_unstable(feature = "...", issue = "...")]
+   |
 
-error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn`
-  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:38:48
+error: `foo2_gated` is not yet stable as a const fn
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:39:48
    |
 LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
    |                                                ^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: Const-stable functions can only call other const-stable functions
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0723`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
index 44a62094987..d17dcb28115 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
@@ -13,7 +13,7 @@ const fn foo() -> u32 { 42 }
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn`
+const unsafe fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn
 
 #[unstable(feature = "rust1", issue = "none")]
 const fn foo2() -> u32 { 42 }
@@ -21,7 +21,7 @@ const fn foo2() -> u32 { 42 }
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn`
+const unsafe fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn
 
 // check whether this function cannot be called even with the feature gate active
 #[unstable(feature = "foo2", issue = "none")]
@@ -30,6 +30,6 @@ const fn foo2_gated() -> u32 { 42 }
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
-const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn`
+const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
index 31ad12c9551..891c34a888a 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
@@ -1,30 +1,26 @@
-error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn`
+error: `foo` is not yet stable as a const fn
   --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32
    |
 LL | const unsafe fn bar() -> u32 { foo() }
    |                                ^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: Const-stable functions can only call other const-stable functions
 
-error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn`
+error: `foo2` is not yet stable as a const fn
   --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33
    |
 LL | const unsafe fn bar2() -> u32 { foo2() }
    |                                 ^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: Const-stable functions can only call other const-stable functions
 
-error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn`
+error: `foo2_gated` is not yet stable as a const fn
   --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39
    |
 LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
    |                                       ^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: Const-stable functions can only call other const-stable functions
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0723`.
diff --git a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
index eb250081d6a..93b67fd7b14 100644
--- a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
+++ b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
@@ -12,6 +12,16 @@ LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "
 
 warning: skipping const checks
    |
+help: skipping check for `const_fn` feature
+  --> $DIR/abi-mismatch.rs:9:23
+   |
+LL | const fn call_rust_fn(my_fn: extern "Rust" fn()) {
+   |                       ^^^^^
+help: skipping check for `const_fn` feature
+  --> $DIR/abi-mismatch.rs:10:5
+   |
+LL |     my_fn();
+   |     ^^^^^
 help: skipping check that does not even have a feature gate
   --> $DIR/abi-mismatch.rs:10:5
    |
diff --git a/src/test/ui/consts/unsizing-cast-non-null.rs b/src/test/ui/consts/unsizing-cast-non-null.rs
index 67d9f6baca5..af6bc2d85fd 100644
--- a/src/test/ui/consts/unsizing-cast-non-null.rs
+++ b/src/test/ui/consts/unsizing-cast-non-null.rs
@@ -4,7 +4,7 @@ use std::ptr::NonNull;
 
 pub const fn dangling_slice<T>() -> NonNull<[T]> {
     NonNull::<[T; 0]>::dangling()
-    //~^ ERROR: unsizing casts are only allowed for references right now
+    //~^ ERROR: unsizing casts to types besides slices
 }
 
 fn main() {}
diff --git a/src/test/ui/consts/unsizing-cast-non-null.stderr b/src/test/ui/consts/unsizing-cast-non-null.stderr
index 6575355daad..dc08ccd02b6 100644
--- a/src/test/ui/consts/unsizing-cast-non-null.stderr
+++ b/src/test/ui/consts/unsizing-cast-non-null.stderr
@@ -1,4 +1,4 @@
-error[E0723]: unsizing casts are only allowed for references right now
+error[E0723]: unsizing casts to types besides slices are not allowed in const fn
   --> $DIR/unsizing-cast-non-null.rs:6:5
    |
 LL |     NonNull::<[T; 0]>::dangling()
diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.rs b/src/test/ui/consts/unstable-const-fn-in-libcore.rs
index 29d3dc18fa7..43951c6854b 100644
--- a/src/test/ui/consts/unstable-const-fn-in-libcore.rs
+++ b/src/test/ui/consts/unstable-const-fn-in-libcore.rs
@@ -6,6 +6,7 @@
 #![stable(feature = "core", since = "1.6.0")]
 #![feature(rustc_const_unstable)]
 #![feature(staged_api)]
+#![feature(const_fn)]
 
 enum Opt<T> {
     Some(T),
diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr
index be797cae7ca..928605356a1 100644
--- a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr
+++ b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr
@@ -1,11 +1,11 @@
 error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/unstable-const-fn-in-libcore.rs:23:26
+  --> $DIR/unstable-const-fn-in-libcore.rs:24:26
    |
 LL |             Opt::None => f(),
    |                          ^^^
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/unstable-const-fn-in-libcore.rs:18:53
+  --> $DIR/unstable-const-fn-in-libcore.rs:19:53
    |
 LL |     const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
    |                                                     ^ constant functions cannot evaluate destructors
@@ -14,7 +14,7 @@ LL |     }
    |     - value is dropped here
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/unstable-const-fn-in-libcore.rs:18:47
+  --> $DIR/unstable-const-fn-in-libcore.rs:19:47
    |
 LL |     const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
    |                                               ^^^^ constant functions cannot evaluate destructors
diff --git a/src/test/ui/parser/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs
index c327667f4cd..6d3fc3ce2f1 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.rs
+++ b/src/test/ui/parser/fn-header-semantic-fail.rs
@@ -12,6 +12,7 @@ fn main() {
     extern "C" fn ff4() {} // OK.
     const async unsafe extern "C" fn ff5() {} // OK.
     //~^ ERROR functions cannot be both `const` and `async`
+    //~| ERROR `from_generator` is not yet stable as a const fn
 
     trait X {
         async fn ft1(); //~ ERROR functions in traits cannot be declared `async`
@@ -34,6 +35,7 @@ fn main() {
         const async unsafe extern "C" fn ft5() {}
         //~^ ERROR functions in traits cannot be declared `async`
         //~| ERROR functions in traits cannot be declared const
+        //~| ERROR `from_generator` is not yet stable as a const fn
         //~| ERROR method `ft5` has an incompatible type for trait
         //~| ERROR functions cannot be both `const` and `async`
     }
@@ -45,6 +47,7 @@ fn main() {
         extern "C" fn fi4() {} // OK.
         const async unsafe extern "C" fn fi5() {}
         //~^ ERROR functions cannot be both `const` and `async`
+        //~| ERROR `from_generator` is not yet stable as a const fn
     }
 
     extern {
diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr
index 4193b3ee695..f1e21884040 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.stderr
+++ b/src/test/ui/parser/fn-header-semantic-fail.stderr
@@ -8,7 +8,7 @@ LL |     const async unsafe extern "C" fn ff5() {} // OK.
    |     `const` because of this
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:17:9
+  --> $DIR/fn-header-semantic-fail.rs:18:9
    |
 LL |         async fn ft1();
    |         -----^^^^^^^^^^
@@ -19,19 +19,19 @@ LL |         async fn ft1();
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:19:9
+  --> $DIR/fn-header-semantic-fail.rs:20:9
    |
 LL |         const fn ft3();
    |         ^^^^^ functions in traits cannot be const
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:21:9
+  --> $DIR/fn-header-semantic-fail.rs:22:9
    |
 LL |         const async unsafe extern "C" fn ft5();
    |         ^^^^^ functions in traits cannot be const
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:21:9
+  --> $DIR/fn-header-semantic-fail.rs:22:9
    |
 LL |         const async unsafe extern "C" fn ft5();
    |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -42,7 +42,7 @@ LL |         const async unsafe extern "C" fn ft5();
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:21:9
+  --> $DIR/fn-header-semantic-fail.rs:22:9
    |
 LL |         const async unsafe extern "C" fn ft5();
    |         ^^^^^-^^^^^----------------------------
@@ -51,7 +51,7 @@ LL |         const async unsafe extern "C" fn ft5();
    |         `const` because of this
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:29:9
+  --> $DIR/fn-header-semantic-fail.rs:30:9
    |
 LL |         async fn ft1() {}
    |         -----^^^^^^^^^^^^
@@ -62,19 +62,19 @@ LL |         async fn ft1() {}
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:32:9
+  --> $DIR/fn-header-semantic-fail.rs:33:9
    |
 LL |         const fn ft3() {}
    |         ^^^^^ functions in traits cannot be const
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:34:9
+  --> $DIR/fn-header-semantic-fail.rs:35:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^ functions in traits cannot be const
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:34:9
+  --> $DIR/fn-header-semantic-fail.rs:35:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -85,7 +85,7 @@ LL |         const async unsafe extern "C" fn ft5() {}
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:34:9
+  --> $DIR/fn-header-semantic-fail.rs:35:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^-^^^^^------------------------------
@@ -94,7 +94,7 @@ LL |         const async unsafe extern "C" fn ft5() {}
    |         `const` because of this
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:46:9
+  --> $DIR/fn-header-semantic-fail.rs:48:9
    |
 LL |         const async unsafe extern "C" fn fi5() {}
    |         ^^^^^-^^^^^------------------------------
@@ -103,7 +103,7 @@ LL |         const async unsafe extern "C" fn fi5() {}
    |         `const` because of this
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:51:18
+  --> $DIR/fn-header-semantic-fail.rs:54:18
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -113,7 +113,7 @@ LL |         async fn fe1();
    |         help: remove the qualifiers: `fn`
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:52:19
+  --> $DIR/fn-header-semantic-fail.rs:55:19
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -124,7 +124,7 @@ LL |         unsafe fn fe2();
    |         help: remove the qualifiers: `fn`
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:53:18
+  --> $DIR/fn-header-semantic-fail.rs:56:18
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -135,7 +135,7 @@ LL |         const fn fe3();
    |         help: remove the qualifiers: `fn`
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:54:23
+  --> $DIR/fn-header-semantic-fail.rs:57:23
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -146,7 +146,7 @@ LL |         extern "C" fn fe4();
    |         help: remove the qualifiers: `fn`
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:55:42
+  --> $DIR/fn-header-semantic-fail.rs:58:42
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -157,7 +157,7 @@ LL |         const async unsafe extern "C" fn fe5();
    |         help: remove the qualifiers: `fn`
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:55:9
+  --> $DIR/fn-header-semantic-fail.rs:58:9
    |
 LL |         const async unsafe extern "C" fn fe5();
    |         ^^^^^-^^^^^----------------------------
@@ -165,8 +165,16 @@ LL |         const async unsafe extern "C" fn fe5();
    |         |     `async` because of this
    |         `const` because of this
 
+error: `from_generator` is not yet stable as a const fn
+  --> $DIR/fn-header-semantic-fail.rs:13:44
+   |
+LL |     const async unsafe extern "C" fn ff5() {} // OK.
+   |                                            ^^
+   |
+   = help: add `#![feature(gen_future)]` to the crate attributes to enable
+
 error[E0053]: method `ft1` has an incompatible type for trait
-  --> $DIR/fn-header-semantic-fail.rs:29:24
+  --> $DIR/fn-header-semantic-fail.rs:30:24
    |
 LL |         async fn ft1();
    |                       - type in trait
@@ -181,7 +189,7 @@ LL |         async fn ft1() {}
               found fn pointer `fn() -> impl Future`
 
 error[E0053]: method `ft5` has an incompatible type for trait
-  --> $DIR/fn-header-semantic-fail.rs:34:48
+  --> $DIR/fn-header-semantic-fail.rs:35:48
    |
 LL |         const async unsafe extern "C" fn ft5();
    |                                               - type in trait
@@ -195,7 +203,23 @@ LL |         const async unsafe extern "C" fn ft5() {}
    = note: expected fn pointer `unsafe extern "C" fn()`
               found fn pointer `unsafe extern "C" fn() -> impl Future`
 
-error: aborting due to 20 previous errors
+error: `from_generator` is not yet stable as a const fn
+  --> $DIR/fn-header-semantic-fail.rs:35:48
+   |
+LL |         const async unsafe extern "C" fn ft5() {}
+   |                                                ^^
+   |
+   = help: add `#![feature(gen_future)]` to the crate attributes to enable
+
+error: `from_generator` is not yet stable as a const fn
+  --> $DIR/fn-header-semantic-fail.rs:48:48
+   |
+LL |         const async unsafe extern "C" fn fi5() {}
+   |                                                ^^
+   |
+   = help: add `#![feature(gen_future)]` to the crate attributes to enable
+
+error: aborting due to 23 previous errors
 
 Some errors have detailed explanations: E0053, E0379, E0706.
 For more information about an error, try `rustc --explain E0053`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs
index 3278f35bad2..fc85e98ef53 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs
@@ -10,7 +10,7 @@ fn non_const() {}
 
 impl const T for S {
     fn foo() { non_const() }
-    //~^ ERROR can only call other `const fn`
+    //~^ ERROR calls in constant functions
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr
index b50dd03a861..c6c78c7d1e8 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr
@@ -1,12 +1,9 @@
-error[E0723]: can only call other `const fn` within a `const fn`, but `non_const` is not stable as `const fn`
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
   --> $DIR/const-check-fns-in-const-impl.rs:12:16
    |
 LL |     fn foo() { non_const() }
    |                ^^^^^^^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = 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 E0015`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr
index 3994bd97c30..58041454d59 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr
@@ -1,5 +1,5 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/feature-gate.rs:16:1
+  --> $DIR/feature-gate.rs:17:1
    |
 LL | fn main() {}
    | ^^^^^^^^^
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs
index d600b53e448..3506237d1f1 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs
@@ -4,6 +4,7 @@
 #![cfg_attr(gated, feature(const_trait_bound_opt_out))]
 #![allow(incomplete_features)]
 #![feature(rustc_attrs)]
+#![feature(const_fn)]
 
 trait T {
     const CONST: i32;
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr
index a1e1c3249af..8ae8b8868dd 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr
@@ -1,5 +1,5 @@
 error[E0658]: `?const` on trait bounds is experimental
-  --> $DIR/feature-gate.rs:12:29
+  --> $DIR/feature-gate.rs:13:29
    |
 LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
    |                             ^^^^^^
diff --git a/src/test/ui/rfc-2632-const-trait-impl/stability.rs b/src/test/ui/rfc-2632-const-trait-impl/stability.rs
index 03a6fb51503..454fde34a2c 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/stability.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/stability.rs
@@ -30,7 +30,7 @@ impl const std::ops::Add for Int {
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 pub const fn foo() -> Int {
     Int(1i32) + Int(2i32)
-    //~^ ERROR can only call other `const fn` within a `const fn`
+    //~^ ERROR not yet stable as a const fn
 }
 
 // ok
diff --git a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr
index ddef7a3aafc..54d7cfd5d79 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr
@@ -6,18 +6,14 @@ LL | |
 LL | |         Int(self.0 - rhs.0)
 LL | |     }
    | |_____^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
-error[E0723]: can only call other `const fn` within a `const fn`, but `<Int as Add>::add` is not stable as `const fn`
+error: `<Int as Add>::add` is not yet stable as a const fn
   --> $DIR/stability.rs:32:5
    |
 LL |     Int(1i32) + Int(2i32)
    |     ^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: Const-stable functions can only call other const-stable functions
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/unsafe/ranged_ints2_const.rs b/src/test/ui/unsafe/ranged_ints2_const.rs
index 788f49f743c..65e0d79308c 100644
--- a/src/test/ui/unsafe/ranged_ints2_const.rs
+++ b/src/test/ui/unsafe/ranged_ints2_const.rs
@@ -8,13 +8,13 @@ fn main() {
 
 const fn foo() -> NonZero<u32> {
     let mut x = unsafe { NonZero(1) };
-    let y = &mut x.0; //~ ERROR references in const fn are unstable
+    let y = &mut x.0; //~ ERROR mutable references
     //~^ ERROR mutation of layout constrained field is unsafe
     unsafe { NonZero(1) }
 }
 
 const fn bar() -> NonZero<u32> {
     let mut x = unsafe { NonZero(1) };
-    let y = unsafe { &mut x.0 }; //~ ERROR mutable references in const fn are unstable
+    let y = unsafe { &mut x.0 }; //~ ERROR mutable references
     unsafe { NonZero(1) }
 }