diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 03dbcc450246f..94e2a40e1fe36 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -145,8 +145,6 @@ pub struct ConstStability {
     pub feature: Symbol,
     /// whether the function has a `#[rustc_promotable]` attribute
     pub promotable: bool,
-    /// whether the function has a `#[rustc_allow_const_fn_ptr]` attribute
-    pub allow_const_fn_ptr: bool,
 }
 
 /// The available stability levels.
@@ -190,7 +188,6 @@ where
     let mut stab: Option<Stability> = None;
     let mut const_stab: Option<ConstStability> = None;
     let mut promotable = false;
-    let mut allow_const_fn_ptr = false;
     let diagnostic = &sess.parse_sess.span_diagnostic;
 
     'outer: for attr in attrs_iter {
@@ -200,7 +197,6 @@ where
             sym::unstable,
             sym::stable,
             sym::rustc_promotable,
-            sym::rustc_allow_const_fn_ptr,
         ]
         .iter()
         .any(|&s| attr.has_name(s))
@@ -215,9 +211,6 @@ where
         if attr.has_name(sym::rustc_promotable) {
             promotable = true;
         }
-        if attr.has_name(sym::rustc_allow_const_fn_ptr) {
-            allow_const_fn_ptr = true;
-        }
         // attributes with data
         else if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta {
             let meta = meta.as_ref().unwrap();
@@ -360,12 +353,8 @@ where
                             if sym::unstable == meta_name {
                                 stab = Some(Stability { level, feature });
                             } else {
-                                const_stab = Some(ConstStability {
-                                    level,
-                                    feature,
-                                    promotable: false,
-                                    allow_const_fn_ptr: false,
-                                });
+                                const_stab =
+                                    Some(ConstStability { level, feature, promotable: false });
                             }
                         }
                         (None, _, _) => {
@@ -440,12 +429,8 @@ where
                             if sym::stable == meta_name {
                                 stab = Some(Stability { level, feature });
                             } else {
-                                const_stab = Some(ConstStability {
-                                    level,
-                                    feature,
-                                    promotable: false,
-                                    allow_const_fn_ptr: false,
-                                });
+                                const_stab =
+                                    Some(ConstStability { level, feature, promotable: false });
                             }
                         }
                         (None, _) => {
@@ -464,18 +449,16 @@ where
     }
 
     // Merge the const-unstable info into the stability info
-    if promotable || allow_const_fn_ptr {
+    if promotable {
         if let Some(ref mut stab) = const_stab {
             stab.promotable = promotable;
-            stab.allow_const_fn_ptr = allow_const_fn_ptr;
         } else {
             struct_span_err!(
                 diagnostic,
                 item_sp,
                 E0717,
-                "rustc_promotable and rustc_allow_const_fn_ptr attributes \
-                      must be paired with either a rustc_const_unstable or a rustc_const_stable \
-                      attribute"
+                "`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` \
+                or a `rustc_const_stable` attribute"
             )
             .emit();
         }
diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs
index c4d1c6eee31c4..209158ce39206 100644
--- a/compiler/rustc_builtin_macros/src/concat_idents.rs
+++ b/compiler/rustc_builtin_macros/src/concat_idents.rs
@@ -27,15 +27,15 @@ pub fn expand_concat_idents<'cx>(
                 }
             }
         } else {
-            match e {
-                TokenTree::Token(Token { kind: token::Ident(name, _), .. }) => {
-                    res_str.push_str(&name.as_str())
-                }
-                _ => {
-                    cx.span_err(sp, "concat_idents! requires ident args.");
-                    return DummyResult::any(sp);
+            if let TokenTree::Token(token) = e {
+                if let Some((ident, _)) = token.ident() {
+                    res_str.push_str(&ident.name.as_str());
+                    continue;
                 }
             }
+
+            cx.span_err(sp, "concat_idents! requires ident args.");
+            return DummyResult::any(sp);
         }
     }
 
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 7118437c0c850..544efc124e117 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -141,6 +141,9 @@ pub fn run_compiler(
     callbacks: &mut (dyn Callbacks + Send),
     file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
     emitter: Option<Box<dyn Write + Send>>,
+    make_codegen_backend: Option<
+        Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
+    >,
 ) -> interface::Result<()> {
     let mut args = Vec::new();
     for arg in at_args {
@@ -162,6 +165,11 @@ pub fn run_compiler(
     let sopts = config::build_session_options(&matches);
     let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg"));
 
+    // We wrap `make_codegen_backend` in another `Option` such that `dummy_config` can take
+    // ownership of it when necessary, while also allowing the non-dummy config to take ownership
+    // when `dummy_config` is not used.
+    let mut make_codegen_backend = Some(make_codegen_backend);
+
     let mut dummy_config = |sopts, cfg, diagnostic_output| {
         let mut config = interface::Config {
             opts: sopts,
@@ -177,6 +185,7 @@ pub fn run_compiler(
             lint_caps: Default::default(),
             register_lints: None,
             override_queries: None,
+            make_codegen_backend: make_codegen_backend.take().unwrap(),
             registry: diagnostics_registry(),
         };
         callbacks.config(&mut config);
@@ -253,6 +262,7 @@ pub fn run_compiler(
         lint_caps: Default::default(),
         register_lints: None,
         override_queries: None,
+        make_codegen_backend: make_codegen_backend.unwrap(),
         registry: diagnostics_registry(),
     };
 
@@ -1265,7 +1275,7 @@ pub fn main() -> ! {
                 })
             })
             .collect::<Vec<_>>();
-        run_compiler(&args, &mut callbacks, None, None)
+        run_compiler(&args, &mut callbacks, None, None, None)
     });
     // The extra `\t` is necessary to align this label with the others.
     print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed());
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 926e3dbfc5266..f7651ca0ba6dd 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1,10 +1,9 @@
 use crate::expand::{self, AstFragment, Invocation};
 use crate::module::DirectoryOwnership;
 
-use rustc_ast::mut_visit::{self, MutVisitor};
 use rustc_ast::ptr::P;
 use rustc_ast::token;
-use rustc_ast::tokenstream::{self, TokenStream};
+use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{AssocCtxt, Visitor};
 use rustc_ast::{self as ast, Attribute, NodeId, PatKind};
 use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability};
@@ -313,7 +312,7 @@ where
         ts: TokenStream,
     ) -> Result<TokenStream, ErrorReported> {
         // FIXME setup implicit context in TLS before calling self.
-        Ok((*self)(ts))
+        Ok(self(ts))
     }
 }
 
@@ -339,7 +338,7 @@ where
         annotated: TokenStream,
     ) -> Result<TokenStream, ErrorReported> {
         // FIXME setup implicit context in TLS before calling self.
-        Ok((*self)(annotation, annotated))
+        Ok(self(annotation, annotated))
     }
 }
 
@@ -364,31 +363,9 @@ where
         &self,
         ecx: &'cx mut ExtCtxt<'_>,
         span: Span,
-        mut input: TokenStream,
+        input: TokenStream,
     ) -> Box<dyn MacResult + 'cx> {
-        struct AvoidInterpolatedIdents;
-
-        impl MutVisitor for AvoidInterpolatedIdents {
-            fn visit_tt(&mut self, tt: &mut tokenstream::TokenTree) {
-                if let tokenstream::TokenTree::Token(token) = tt {
-                    if let token::Interpolated(nt) = &token.kind {
-                        if let token::NtIdent(ident, is_raw) = **nt {
-                            *tt = tokenstream::TokenTree::token(
-                                token::Ident(ident.name, is_raw),
-                                ident.span,
-                            );
-                        }
-                    }
-                }
-                mut_visit::noop_visit_tt(tt, self)
-            }
-
-            fn visit_mac(&mut self, mac: &mut ast::MacCall) {
-                mut_visit::noop_visit_mac(mac, self)
-            }
-        }
-        AvoidInterpolatedIdents.visit_tts(&mut input);
-        (*self)(ecx, span, input)
+        self(ecx, span, input)
     }
 }
 
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 17b9e1ee7e8ba..7f5b19134804e 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -587,6 +587,9 @@ declare_features! (
     /// Allows basic arithmetic on floating point types in a `const fn`.
     (active, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None),
 
+    /// Allows using and casting function pointers in a `const fn`.
+    (active, const_fn_fn_ptr_basics, "1.48.0", Some(57563), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 8b7fd59cd874a..22c1ca2f289d3 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -464,7 +464,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // ==========================================================================
 
     rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL),
-    rustc_attr!(rustc_allow_const_fn_ptr, AssumedUsed, template!(Word), IMPL_DETAIL),
     rustc_attr!(rustc_args_required_const, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE),
 
     // ==========================================================================
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 4d84462c42b0b..73a51ad477b22 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -154,6 +154,10 @@ pub struct Config {
     pub override_queries:
         Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::Providers)>,
 
+    /// This is a callback from the driver that is called to create a codegen backend.
+    pub make_codegen_backend:
+        Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
+
     /// Registry of diagnostics codes.
     pub registry: Registry,
 }
@@ -167,6 +171,7 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R
         config.file_loader,
         config.input_path.clone(),
         config.lint_caps,
+        config.make_codegen_backend,
         registry.clone(),
     );
 
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 0eed6938c3169..7ace707cc88e9 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -63,9 +63,17 @@ pub fn create_session(
     file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
     input_path: Option<PathBuf>,
     lint_caps: FxHashMap<lint::LintId, lint::Level>,
+    make_codegen_backend: Option<
+        Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
+    >,
     descriptions: Registry,
 ) -> (Lrc<Session>, Lrc<Box<dyn CodegenBackend>>) {
-    let codegen_backend = get_codegen_backend(&sopts);
+    let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
+        make_codegen_backend(&sopts)
+    } else {
+        get_codegen_backend(&sopts)
+    };
+
     // target_override is documented to be called before init(), so this is okay
     let target_override = codegen_backend.target_override(&sopts);
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 784d6c3b2cee4..d5b99ea4d288d 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -457,10 +457,6 @@ rustc_queries! {
             desc { |tcx| "checking if item is promotable: `{}`", tcx.def_path_str(key) }
         }
 
-        query const_fn_is_allowed_fn_ptr(key: DefId) -> bool {
-            desc { |tcx| "checking if const fn allows `fn()` types: `{}`", tcx.def_path_str(key) }
-        }
-
         /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
         query is_foreign_item(key: DefId) -> bool {
             desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) }
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 342a37cadbac4..67c69d69bda81 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -475,6 +475,18 @@ impl<T> Trait<T> for X {
                                  #traits-as-parameters",
                         );
                     }
+                    (ty::Param(p), ty::Closure(..) | ty::Generator(..)) => {
+                        let generics = self.generics_of(body_owner_def_id);
+                        let p_span = self.def_span(generics.type_param(p, self).def_id);
+                        if !sp.contains(p_span) {
+                            db.span_label(p_span, "this type parameter");
+                        }
+                        db.help(&format!(
+                            "every closure has a distinct type and so could not always match the \
+                             caller-chosen type of parameter `{}`",
+                            p
+                        ));
+                    }
                     (ty::Param(p), _) | (_, ty::Param(p)) => {
                         let generics = self.generics_of(body_owner_def_id);
                         let p_span = self.def_span(generics.type_param(p, self).def_id);
diff --git a/compiler/rustc_mir/src/const_eval/fn_queries.rs b/compiler/rustc_mir/src/const_eval/fn_queries.rs
index 1db1f6ceedac5..aca822a05bde9 100644
--- a/compiler/rustc_mir/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_mir/src/const_eval/fn_queries.rs
@@ -151,17 +151,11 @@ fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
         }
 }
 
-fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    is_const_fn(tcx, def_id)
-        && tcx.lookup_const_stability(def_id).map(|stab| stab.allow_const_fn_ptr).unwrap_or(false)
-}
-
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
         is_const_fn_raw,
         is_const_impl_raw: |tcx, def_id| is_const_impl_raw(tcx, def_id.expect_local()),
         is_promotable_const_fn,
-        const_fn_is_allowed_fn_ptr,
         ..*providers
     };
 }
diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs
index 1d74108585360..3b8d8a5aa99dd 100644
--- a/compiler/rustc_mir/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs
@@ -213,11 +213,21 @@ impl NonConstOp for FnPtrCast {
     const STOPS_CONST_CHECKING: bool = true;
 
     fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
-        mcf_status_in_item(ccx)
+        if ccx.const_kind() != hir::ConstContext::ConstFn {
+            Status::Allowed
+        } else {
+            Status::Unstable(sym::const_fn_fn_ptr_basics)
+        }
     }
 
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        mcf_emit_error(ccx, span, "function pointer casts are not allowed in const fn");
+        feature_err(
+            &ccx.tcx.sess.parse_sess,
+            sym::const_fn_fn_ptr_basics,
+            span,
+            &format!("function pointer casts are not allowed in {}s", ccx.const_kind()),
+        )
+        .emit()
     }
 }
 
@@ -596,17 +606,21 @@ pub mod ty {
         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) {
+            if ccx.const_kind() != hir::ConstContext::ConstFn {
                 Status::Allowed
             } else {
-                mcf_status_in_item(ccx)
+                Status::Unstable(sym::const_fn_fn_ptr_basics)
             }
         }
 
         fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-            mcf_emit_error(ccx, span, "function pointers in const fn are unstable");
+            feature_err(
+                &ccx.tcx.sess.parse_sess,
+                sym::const_fn_fn_ptr_basics,
+                span,
+                &format!("function pointers cannot appear in {}s", ccx.const_kind()),
+            )
+            .emit()
         }
     }
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 12134a85f45c5..4234aef335906 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -353,6 +353,7 @@ symbols! {
         const_extern_fn,
         const_fn,
         const_fn_floating_point_arithmetic,
+        const_fn_fn_ptr_basics,
         const_fn_transmute,
         const_fn_union,
         const_generics,
@@ -884,7 +885,6 @@ symbols! {
         rustc,
         rustc_allocator,
         rustc_allocator_nounwind,
-        rustc_allow_const_fn_ptr,
         rustc_args_required_const,
         rustc_attrs,
         rustc_builtin_macro,
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index 247bbf637ceaf..3e66885448b9a 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -117,11 +117,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ty
     }
 
-    // Checks that the type of `expr` can be coerced to `expected`.
-    //
-    // N.B., this code relies on `self.diverges` to be accurate. In
-    // particular, assignments to `!` will be permitted if the
-    // diverges flag is currently "always".
+    /// Checks that the type of `expr` can be coerced to `expected`.
+    ///
+    /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!`
+    /// will be permitted if the diverges flag is currently "always".
     pub fn demand_coerce_diag(
         &self,
         expr: &hir::Expr<'_>,
diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs
index 851ca17a36548..6a83f5da87cc8 100644
--- a/library/alloc/tests/boxed.rs
+++ b/library/alloc/tests/boxed.rs
@@ -1,3 +1,4 @@
+use std::cell::Cell;
 use std::mem::MaybeUninit;
 use std::ptr::NonNull;
 
@@ -49,3 +50,10 @@ fn box_clone_from_ptr_stability() {
         assert_eq!(copy.as_ptr() as usize, copy_raw);
     }
 }
+
+#[test]
+fn box_deref_lval() {
+    let x = Box::new(Cell::new(5));
+    x.set(1000);
+    assert_eq!(x.get(), 1000);
+}
diff --git a/library/alloc/tests/fmt.rs b/library/alloc/tests/fmt.rs
index 0ad092b4997f4..757fddd241857 100644
--- a/library/alloc/tests/fmt.rs
+++ b/library/alloc/tests/fmt.rs
@@ -1,7 +1,327 @@
-use std::fmt;
+#![deny(warnings)]
+
+use std::cell::RefCell;
+use std::fmt::{self, Write};
 
 #[test]
 fn test_format() {
     let s = fmt::format(format_args!("Hello, {}!", "world"));
     assert_eq!(s, "Hello, world!");
 }
+
+struct A;
+struct B;
+struct C;
+struct D;
+
+impl fmt::LowerHex for A {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("aloha")
+    }
+}
+impl fmt::UpperHex for B {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("adios")
+    }
+}
+impl fmt::Display for C {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.pad_integral(true, "☃", "123")
+    }
+}
+impl fmt::Binary for D {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("aa")?;
+        f.write_char('☃')?;
+        f.write_str("bb")
+    }
+}
+
+macro_rules! t {
+    ($a:expr, $b:expr) => {
+        assert_eq!($a, $b)
+    };
+}
+
+#[test]
+fn test_format_macro_interface() {
+    // Various edge cases without formats
+    t!(format!(""), "");
+    t!(format!("hello"), "hello");
+    t!(format!("hello {{"), "hello {");
+
+    // default formatters should work
+    t!(format!("{}", 1.0f32), "1");
+    t!(format!("{}", 1.0f64), "1");
+    t!(format!("{}", "a"), "a");
+    t!(format!("{}", "a".to_string()), "a");
+    t!(format!("{}", false), "false");
+    t!(format!("{}", 'a'), "a");
+
+    // At least exercise all the formats
+    t!(format!("{}", true), "true");
+    t!(format!("{}", '☃'), "☃");
+    t!(format!("{}", 10), "10");
+    t!(format!("{}", 10_usize), "10");
+    t!(format!("{:?}", '☃'), "'☃'");
+    t!(format!("{:?}", 10), "10");
+    t!(format!("{:?}", 10_usize), "10");
+    t!(format!("{:?}", "true"), "\"true\"");
+    t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\"");
+    t!(
+        format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"),
+        r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#
+    );
+    t!(format!("{:?}", "foo\0bar\x01baz\u{7f}q\u{75}x"), r#""foo\u{0}bar\u{1}baz\u{7f}qux""#);
+    t!(format!("{:o}", 10_usize), "12");
+    t!(format!("{:x}", 10_usize), "a");
+    t!(format!("{:X}", 10_usize), "A");
+    t!(format!("{}", "foo"), "foo");
+    t!(format!("{}", "foo".to_string()), "foo");
+    if cfg!(target_pointer_width = "32") {
+        t!(format!("{:#p}", 0x1234 as *const isize), "0x00001234");
+        t!(format!("{:#p}", 0x1234 as *mut isize), "0x00001234");
+    } else {
+        t!(format!("{:#p}", 0x1234 as *const isize), "0x0000000000001234");
+        t!(format!("{:#p}", 0x1234 as *mut isize), "0x0000000000001234");
+    }
+    t!(format!("{:p}", 0x1234 as *const isize), "0x1234");
+    t!(format!("{:p}", 0x1234 as *mut isize), "0x1234");
+    t!(format!("{:x}", A), "aloha");
+    t!(format!("{:X}", B), "adios");
+    t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
+    t!(format!("{1} {0}", 0, 1), "1 0");
+    t!(format!("{foo} {bar}", foo = 0, bar = 1), "0 1");
+    t!(format!("{foo} {1} {bar} {0}", 0, 1, foo = 2, bar = 3), "2 1 3 0");
+    t!(format!("{} {0}", "a"), "a a");
+    t!(format!("{_foo}", _foo = 6usize), "6");
+    t!(format!("{foo_bar}", foo_bar = 1), "1");
+    t!(format!("{}", 5 + 5), "10");
+    t!(format!("{:#4}", C), "☃123");
+    t!(format!("{:b}", D), "aa☃bb");
+
+    let a: &dyn fmt::Debug = &1;
+    t!(format!("{:?}", a), "1");
+
+    // Formatting strings and their arguments
+    t!(format!("{}", "a"), "a");
+    t!(format!("{:4}", "a"), "a   ");
+    t!(format!("{:4}", "☃"), "☃   ");
+    t!(format!("{:>4}", "a"), "   a");
+    t!(format!("{:<4}", "a"), "a   ");
+    t!(format!("{:^5}", "a"), "  a  ");
+    t!(format!("{:^5}", "aa"), " aa  ");
+    t!(format!("{:^4}", "a"), " a  ");
+    t!(format!("{:^4}", "aa"), " aa ");
+    t!(format!("{:.4}", "a"), "a");
+    t!(format!("{:4.4}", "a"), "a   ");
+    t!(format!("{:4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+    t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+    t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+    t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+    t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), "      aaaa");
+    t!(format!("{:2.4}", "aaaaa"), "aaaa");
+    t!(format!("{:2.4}", "aaaa"), "aaaa");
+    t!(format!("{:2.4}", "aaa"), "aaa");
+    t!(format!("{:2.4}", "aa"), "aa");
+    t!(format!("{:2.4}", "a"), "a ");
+    t!(format!("{:0>2}", "a"), "0a");
+    t!(format!("{:.*}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa");
+    t!(format!("{:.1$}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa");
+    t!(format!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a = 4), "aaaa");
+    t!(format!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a = 4), "aaaa");
+    t!(format!("{:1$}", "a", 4), "a   ");
+    t!(format!("{1:0$}", 4, "a"), "a   ");
+    t!(format!("{:a$}", "a", a = 4), "a   ");
+    t!(format!("{:-#}", "a"), "a");
+    t!(format!("{:+#}", "a"), "a");
+    t!(format!("{:/^10.8}", "1234567890"), "/12345678/");
+
+    // Some float stuff
+    t!(format!("{:}", 1.0f32), "1");
+    t!(format!("{:}", 1.0f64), "1");
+    t!(format!("{:.3}", 1.0f64), "1.000");
+    t!(format!("{:10.3}", 1.0f64), "     1.000");
+    t!(format!("{:+10.3}", 1.0f64), "    +1.000");
+    t!(format!("{:+10.3}", -1.0f64), "    -1.000");
+
+    t!(format!("{:e}", 1.2345e6f32), "1.2345e6");
+    t!(format!("{:e}", 1.2345e6f64), "1.2345e6");
+    t!(format!("{:E}", 1.2345e6f64), "1.2345E6");
+    t!(format!("{:.3e}", 1.2345e6f64), "1.234e6");
+    t!(format!("{:10.3e}", 1.2345e6f64), "   1.234e6");
+    t!(format!("{:+10.3e}", 1.2345e6f64), "  +1.234e6");
+    t!(format!("{:+10.3e}", -1.2345e6f64), "  -1.234e6");
+
+    // Float edge cases
+    t!(format!("{}", -0.0), "0");
+    t!(format!("{:?}", -0.0), "-0.0");
+    t!(format!("{:?}", 0.0), "0.0");
+
+    // sign aware zero padding
+    t!(format!("{:<3}", 1), "1  ");
+    t!(format!("{:>3}", 1), "  1");
+    t!(format!("{:^3}", 1), " 1 ");
+    t!(format!("{:03}", 1), "001");
+    t!(format!("{:<03}", 1), "001");
+    t!(format!("{:>03}", 1), "001");
+    t!(format!("{:^03}", 1), "001");
+    t!(format!("{:+03}", 1), "+01");
+    t!(format!("{:<+03}", 1), "+01");
+    t!(format!("{:>+03}", 1), "+01");
+    t!(format!("{:^+03}", 1), "+01");
+    t!(format!("{:#05x}", 1), "0x001");
+    t!(format!("{:<#05x}", 1), "0x001");
+    t!(format!("{:>#05x}", 1), "0x001");
+    t!(format!("{:^#05x}", 1), "0x001");
+    t!(format!("{:05}", 1.2), "001.2");
+    t!(format!("{:<05}", 1.2), "001.2");
+    t!(format!("{:>05}", 1.2), "001.2");
+    t!(format!("{:^05}", 1.2), "001.2");
+    t!(format!("{:05}", -1.2), "-01.2");
+    t!(format!("{:<05}", -1.2), "-01.2");
+    t!(format!("{:>05}", -1.2), "-01.2");
+    t!(format!("{:^05}", -1.2), "-01.2");
+    t!(format!("{:+05}", 1.2), "+01.2");
+    t!(format!("{:<+05}", 1.2), "+01.2");
+    t!(format!("{:>+05}", 1.2), "+01.2");
+    t!(format!("{:^+05}", 1.2), "+01.2");
+
+    // Ergonomic format_args!
+    t!(format!("{0:x} {0:X}", 15), "f F");
+    t!(format!("{0:x} {0:X} {}", 15), "f F 15");
+    t!(format!("{:x}{0:X}{a:x}{:X}{1:x}{a:X}", 13, 14, a = 15), "dDfEeF");
+    t!(format!("{a:x} {a:X}", a = 15), "f F");
+
+    // And its edge cases
+    t!(
+        format!(
+            "{a:.0$} {b:.0$} {0:.0$}\n{a:.c$} {b:.c$} {c:.c$}",
+            4,
+            a = "abcdefg",
+            b = "hijklmn",
+            c = 3
+        ),
+        "abcd hijk 4\nabc hij 3"
+    );
+    t!(format!("{a:.*} {0} {:.*}", 4, 3, "efgh", a = "abcdef"), "abcd 4 efg");
+    t!(format!("{:.a$} {a} {a:#x}", "aaaaaa", a = 2), "aa 2 0x2");
+
+    // Test that pointers don't get truncated.
+    {
+        let val = usize::MAX;
+        let exp = format!("{:#x}", val);
+        t!(format!("{:p}", val as *const isize), exp);
+    }
+
+    // Escaping
+    t!(format!("{{"), "{");
+    t!(format!("}}"), "}");
+
+    // make sure that format! doesn't move out of local variables
+    let a = Box::new(3);
+    format!("{}", a);
+    format!("{}", a);
+
+    // make sure that format! doesn't cause spurious unused-unsafe warnings when
+    // it's inside of an outer unsafe block
+    unsafe {
+        let a: isize = ::std::mem::transmute(3_usize);
+        format!("{}", a);
+    }
+
+    // test that trailing commas are acceptable
+    format!("{}", "test",);
+    format!("{foo}", foo = "test",);
+}
+
+// Basic test to make sure that we can invoke the `write!` macro with an
+// fmt::Write instance.
+#[test]
+fn test_write() {
+    let mut buf = String::new();
+    let _ = write!(&mut buf, "{}", 3);
+    {
+        let w = &mut buf;
+        let _ = write!(w, "{foo}", foo = 4);
+        let _ = write!(w, "{}", "hello");
+        let _ = writeln!(w, "{}", "line");
+        let _ = writeln!(w, "{foo}", foo = "bar");
+        let _ = w.write_char('☃');
+        let _ = w.write_str("str");
+    }
+
+    t!(buf, "34helloline\nbar\n☃str");
+}
+
+// Just make sure that the macros are defined, there's not really a lot that we
+// can do with them just yet (to test the output)
+#[test]
+fn test_print() {
+    print!("hi");
+    print!("{:?}", vec![0u8]);
+    println!("hello");
+    println!("this is a {}", "test");
+    println!("{foo}", foo = "bar");
+}
+
+// Just make sure that the macros are defined, there's not really a lot that we
+// can do with them just yet (to test the output)
+#[test]
+fn test_format_args() {
+    let mut buf = String::new();
+    {
+        let w = &mut buf;
+        let _ = write!(w, "{}", format_args!("{}", 1));
+        let _ = write!(w, "{}", format_args!("test"));
+        let _ = write!(w, "{}", format_args!("{test}", test = 3));
+    }
+    let s = buf;
+    t!(s, "1test3");
+
+    let s = fmt::format(format_args!("hello {}", "world"));
+    t!(s, "hello world");
+    let s = format!("{}: {}", "args were", format_args!("hello {}", "world"));
+    t!(s, "args were: hello world");
+}
+
+#[test]
+fn test_order() {
+    // Make sure format!() arguments are always evaluated in a left-to-right
+    // ordering
+    fn foo() -> isize {
+        static mut FOO: isize = 0;
+        unsafe {
+            FOO += 1;
+            FOO
+        }
+    }
+    assert_eq!(
+        format!("{} {} {a} {b} {} {c}", foo(), foo(), foo(), a = foo(), b = foo(), c = foo()),
+        "1 2 4 5 3 6".to_string()
+    );
+}
+
+#[test]
+fn test_once() {
+    // Make sure each argument are evaluated only once even though it may be
+    // formatted multiple times
+    fn foo() -> isize {
+        static mut FOO: isize = 0;
+        unsafe {
+            FOO += 1;
+            FOO
+        }
+    }
+    assert_eq!(format!("{0} {0} {0} {a} {a} {a}", foo(), a = foo()), "1 1 1 2 2 2".to_string());
+}
+
+#[test]
+fn test_refcell() {
+    let refcell = RefCell::new(5);
+    assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }");
+    let borrow = refcell.borrow_mut();
+    assert_eq!(format!("{:?}", refcell), "RefCell { value: <borrowed> }");
+    drop(borrow);
+    assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }");
+}
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index a49ca7c256a75..b7c7138db4f52 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -1,4 +1,5 @@
 use std::borrow::Cow;
+use std::cell::Cell;
 use std::collections::TryReserveError::*;
 use std::fmt::Debug;
 use std::iter::InPlaceIterable;
@@ -1831,3 +1832,82 @@ fn partialeq_vec_full() {
     assert_partial_eq_valid!(vec2,vec3; array2,array3);
     assert_partial_eq_valid!(vec2,vec3; arrayref2,arrayref3);
 }
+
+#[test]
+fn test_vec_cycle() {
+    #[derive(Debug)]
+    struct C<'a> {
+        v: Vec<Cell<Option<&'a C<'a>>>>,
+    }
+
+    impl<'a> C<'a> {
+        fn new() -> C<'a> {
+            C { v: Vec::new() }
+        }
+    }
+
+    let mut c1 = C::new();
+    let mut c2 = C::new();
+    let mut c3 = C::new();
+
+    // Push
+    c1.v.push(Cell::new(None));
+    c1.v.push(Cell::new(None));
+
+    c2.v.push(Cell::new(None));
+    c2.v.push(Cell::new(None));
+
+    c3.v.push(Cell::new(None));
+    c3.v.push(Cell::new(None));
+
+    // Set
+    c1.v[0].set(Some(&c2));
+    c1.v[1].set(Some(&c3));
+
+    c2.v[0].set(Some(&c2));
+    c2.v[1].set(Some(&c3));
+
+    c3.v[0].set(Some(&c1));
+    c3.v[1].set(Some(&c2));
+}
+
+#[test]
+fn test_vec_cycle_wrapped() {
+    struct Refs<'a> {
+        v: Vec<Cell<Option<&'a C<'a>>>>,
+    }
+
+    struct C<'a> {
+        refs: Refs<'a>,
+    }
+
+    impl<'a> Refs<'a> {
+        fn new() -> Refs<'a> {
+            Refs { v: Vec::new() }
+        }
+    }
+
+    impl<'a> C<'a> {
+        fn new() -> C<'a> {
+            C { refs: Refs::new() }
+        }
+    }
+
+    let mut c1 = C::new();
+    let mut c2 = C::new();
+    let mut c3 = C::new();
+
+    c1.refs.v.push(Cell::new(None));
+    c1.refs.v.push(Cell::new(None));
+    c2.refs.v.push(Cell::new(None));
+    c2.refs.v.push(Cell::new(None));
+    c3.refs.v.push(Cell::new(None));
+    c3.refs.v.push(Cell::new(None));
+
+    c1.refs.v[0].set(Some(&c2));
+    c1.refs.v[1].set(Some(&c3));
+    c2.refs.v[0].set(Some(&c2));
+    c2.refs.v[1].set(Some(&c3));
+    c3.refs.v[0].set(Some(&c1));
+    c3.refs.v[1].set(Some(&c2));
+}
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 8558cb5a5e8a3..c1038ce4260bc 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -2238,5 +2238,6 @@ impl<T: ?Sized + Debug> Debug for UnsafeCell<T> {
     }
 }
 
-// If you expected tests to be here, look instead at the ui/ifmt.rs test,
+// If you expected tests to be here, look instead at the core/tests/fmt.rs file,
 // it's a lot easier than creating all of the rt::Piece structures here.
+// There are also tests in the alloc crate, for those that need allocations.
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index a75f1d56fb7e6..845df3f5ca551 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -1976,6 +1976,8 @@ pub trait Iterator {
     /// // they're the same
     /// assert_eq!(result, result2);
     /// ```
+    #[doc(alias = "reduce")]
+    #[doc(alias = "inject")]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fold<B, F>(mut self, init: B, mut f: F) -> B
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 30fb87b022645..22bf2b15d6695 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -83,6 +83,7 @@
 #![feature(const_fn_union)]
 #![feature(const_fn)]
 #![cfg_attr(not(bootstrap), feature(const_fn_floating_point_arithmetic))]
+#![cfg_attr(not(bootstrap), feature(const_fn_fn_ptr_basics))]
 #![feature(const_generics)]
 #![feature(const_option)]
 #![feature(const_precise_live_drops)]
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 668a028a3f1ea..ba3fb35caaf9d 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -129,13 +129,9 @@ impl RawWakerVTable {
     /// associated task.
     #[rustc_promotable]
     #[stable(feature = "futures_api", since = "1.36.0")]
-    // `rustc_allow_const_fn_ptr` is a hack that should not be used anywhere else
-    // without first consulting with T-Lang.
-    //
-    // FIXME: remove whenever we have a stable way to accept fn pointers from const fn
-    // (see https://github.com/rust-rfcs/const-eval/issues/19#issuecomment-472799062)
-    #[rustc_allow_const_fn_ptr]
     #[rustc_const_stable(feature = "futures_api", since = "1.36.0")]
+    #[cfg_attr(not(bootstrap), allow_internal_unstable(const_fn_fn_ptr_basics))]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_ptr)]
     pub const fn new(
         clone: unsafe fn(*const ()) -> RawWaker,
         wake: unsafe fn(*const ()),
diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs
index dbcea2747a00d..89c2a969c28bb 100644
--- a/library/core/tests/array.rs
+++ b/library/core/tests/array.rs
@@ -345,3 +345,32 @@ fn array_map_drop_safety() {
     assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create);
     panic!("test succeeded")
 }
+
+#[test]
+fn cell_allows_array_cycle() {
+    use core::cell::Cell;
+
+    #[derive(Debug)]
+    struct B<'a> {
+        a: [Cell<Option<&'a B<'a>>>; 2],
+    }
+
+    impl<'a> B<'a> {
+        fn new() -> B<'a> {
+            B { a: [Cell::new(None), Cell::new(None)] }
+        }
+    }
+
+    let b1 = B::new();
+    let b2 = B::new();
+    let b3 = B::new();
+
+    b1.a[0].set(Some(&b2));
+    b1.a[1].set(Some(&b3));
+
+    b2.a[0].set(Some(&b2));
+    b2.a[1].set(Some(&b3));
+
+    b3.a[0].set(Some(&b1));
+    b3.a[1].set(Some(&b2));
+}
diff --git a/library/core/tests/cell.rs b/library/core/tests/cell.rs
index 801b60be0f093..40be01f443931 100644
--- a/library/core/tests/cell.rs
+++ b/library/core/tests/cell.rs
@@ -303,6 +303,53 @@ fn cell_into_inner() {
     assert_eq!("Hello world".to_owned(), cell.into_inner());
 }
 
+#[test]
+fn cell_exterior() {
+    #[derive(Copy, Clone)]
+    #[allow(dead_code)]
+    struct Point {
+        x: isize,
+        y: isize,
+        z: isize,
+    }
+
+    fn f(p: &Cell<Point>) {
+        assert_eq!(p.get().z, 12);
+        p.set(Point { x: 10, y: 11, z: 13 });
+        assert_eq!(p.get().z, 13);
+    }
+
+    let a = Point { x: 10, y: 11, z: 12 };
+    let b = &Cell::new(a);
+    assert_eq!(b.get().z, 12);
+    f(b);
+    assert_eq!(a.z, 12);
+    assert_eq!(b.get().z, 13);
+}
+
+#[test]
+fn cell_does_not_clone() {
+    #[derive(Copy)]
+    #[allow(dead_code)]
+    struct Foo {
+        x: isize,
+    }
+
+    impl Clone for Foo {
+        fn clone(&self) -> Foo {
+            // Using Cell in any way should never cause clone() to be
+            // invoked -- after all, that would permit evil user code to
+            // abuse `Cell` and trigger crashes.
+
+            panic!();
+        }
+    }
+
+    let x = Cell::new(Foo { x: 22 });
+    let _y = x.get();
+    let _z = x.clone();
+}
+
 #[test]
 fn refcell_default() {
     let cell: RefCell<u64> = Default::default();
@@ -367,3 +414,11 @@ fn refcell_replace_borrows() {
     let _b = x.borrow();
     x.replace(1);
 }
+
+#[test]
+fn refcell_format() {
+    let name = RefCell::new("rust");
+    let what = RefCell::new("rocks");
+    let msg = format!("{name} {}", &*what.borrow(), name = &*name.borrow());
+    assert_eq!(msg, "rust rocks".to_string());
+}
diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs
index 0eb9af3f454e9..ab97352a806ad 100644
--- a/library/core/tests/iter.rs
+++ b/library/core/tests/iter.rs
@@ -376,6 +376,103 @@ fn test_zip_next_back_side_effects_exhausted() {
     assert_eq!(b, vec![200, 300, 400]);
 }
 
+#[derive(Debug)]
+struct CountClone(Cell<i32>);
+
+fn count_clone() -> CountClone {
+    CountClone(Cell::new(0))
+}
+
+impl PartialEq<i32> for CountClone {
+    fn eq(&self, rhs: &i32) -> bool {
+        self.0.get() == *rhs
+    }
+}
+
+impl Clone for CountClone {
+    fn clone(&self) -> Self {
+        let ret = CountClone(self.0.clone());
+        let n = self.0.get();
+        self.0.set(n + 1);
+        ret
+    }
+}
+
+#[test]
+fn test_zip_cloned_sideffectful() {
+    let xs = [count_clone(), count_clone(), count_clone(), count_clone()];
+    let ys = [count_clone(), count_clone()];
+
+    for _ in xs.iter().cloned().zip(ys.iter().cloned()) {}
+
+    assert_eq!(&xs, &[1, 1, 1, 0][..]);
+    assert_eq!(&ys, &[1, 1][..]);
+
+    let xs = [count_clone(), count_clone()];
+    let ys = [count_clone(), count_clone(), count_clone(), count_clone()];
+
+    for _ in xs.iter().cloned().zip(ys.iter().cloned()) {}
+
+    assert_eq!(&xs, &[1, 1][..]);
+    assert_eq!(&ys, &[1, 1, 0, 0][..]);
+}
+
+#[test]
+fn test_zip_map_sideffectful() {
+    let mut xs = [0; 6];
+    let mut ys = [0; 4];
+
+    for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {}
+
+    assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
+    assert_eq!(&ys, &[1, 1, 1, 1]);
+
+    let mut xs = [0; 4];
+    let mut ys = [0; 6];
+
+    for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {}
+
+    assert_eq!(&xs, &[1, 1, 1, 1]);
+    assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]);
+}
+
+#[test]
+fn test_zip_map_rev_sideffectful() {
+    let mut xs = [0; 6];
+    let mut ys = [0; 4];
+
+    {
+        let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
+        it.next_back();
+    }
+    assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]);
+    assert_eq!(&ys, &[0, 0, 0, 1]);
+
+    let mut xs = [0; 6];
+    let mut ys = [0; 4];
+
+    {
+        let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
+        (&mut it).take(5).count();
+        it.next_back();
+    }
+    assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]);
+    assert_eq!(&ys, &[1, 1, 1, 1]);
+}
+
+#[test]
+fn test_zip_nested_sideffectful() {
+    let mut xs = [0; 6];
+    let ys = [0; 4];
+
+    {
+        // test that it has the side effect nested inside enumerate
+        let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys);
+        it.count();
+    }
+    assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
+}
+
 #[test]
 fn test_zip_nth_back_side_effects_exhausted() {
     let mut a = Vec::new();
diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs
index 9e86e07dd91a3..ae814efec2086 100644
--- a/library/core/tests/option.rs
+++ b/library/core/tests/option.rs
@@ -1,3 +1,4 @@
+use core::cell::Cell;
 use core::clone::Clone;
 use core::mem;
 use core::ops::DerefMut;
@@ -372,3 +373,32 @@ fn option_const() {
     const IS_NONE: bool = OPTION.is_none();
     assert!(!IS_NONE);
 }
+
+#[test]
+fn test_unwrap_drop() {
+    struct Dtor<'a> {
+        x: &'a Cell<isize>,
+    }
+
+    impl<'a> std::ops::Drop for Dtor<'a> {
+        fn drop(&mut self) {
+            self.x.set(self.x.get() - 1);
+        }
+    }
+
+    fn unwrap<T>(o: Option<T>) -> T {
+        match o {
+            Some(v) => v,
+            None => panic!(),
+        }
+    }
+
+    let x = &Cell::new(1);
+
+    {
+        let b = Some(Dtor { x });
+        let _c = unwrap(b);
+    }
+
+    assert_eq!(x.get(), 0);
+}
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index 9556d43f9d78b..5ef30b1a8898a 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -1,3 +1,4 @@
+use core::cell::Cell;
 use core::result::Result::{Err, Ok};
 
 #[test]
@@ -1980,3 +1981,30 @@ fn test_is_sorted() {
     assert!(!["c", "bb", "aaa"].is_sorted());
     assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len()));
 }
+
+#[test]
+fn test_slice_run_destructors() {
+    // Make sure that destructors get run on slice literals
+    struct Foo<'a> {
+        x: &'a Cell<isize>,
+    }
+
+    impl<'a> Drop for Foo<'a> {
+        fn drop(&mut self) {
+            self.x.set(self.x.get() + 1);
+        }
+    }
+
+    fn foo(x: &Cell<isize>) -> Foo<'_> {
+        Foo { x }
+    }
+
+    let x = &Cell::new(0);
+
+    {
+        let l = &[foo(x)];
+        assert_eq!(l[0].x.get(), 0);
+    }
+
+    assert_eq!(x.get(), 1);
+}
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index f81ffd2bb9429..93fa1f4e58573 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -21,6 +21,7 @@
 #![feature(nll)]
 #![feature(staged_api)]
 #![feature(const_fn)]
+#![cfg_attr(not(bootstrap), feature(const_fn_fn_ptr_basics))]
 #![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 d03428dd08282..e343eef91126e 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -239,6 +239,7 @@
 #![cfg_attr(not(bootstrap), feature(const_fn_floating_point_arithmetic))]
 #![feature(const_fn_transmute)]
 #![feature(const_fn)]
+#![cfg_attr(not(bootstrap), feature(const_fn_fn_ptr_basics))]
 #![feature(const_ip)]
 #![feature(const_ipv6)]
 #![feature(const_raw_ptr_deref)]
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index 18d9c2f11b544..4281867314cca 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -411,3 +411,6 @@ pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
 pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
     panicking::rust_panic_without_hook(payload)
 }
+
+#[cfg(test)]
+mod tests;
diff --git a/src/test/ui/panics/panic-safe.rs b/library/std/src/panic/tests.rs
similarity index 77%
rename from src/test/ui/panics/panic-safe.rs
rename to library/std/src/panic/tests.rs
index 9867cc56406ef..b37d74011cc67 100644
--- a/src/test/ui/panics/panic-safe.rs
+++ b/library/std/src/panic/tests.rs
@@ -1,16 +1,18 @@
-// run-pass
 #![allow(dead_code)]
 
-use std::panic::{UnwindSafe, AssertUnwindSafe};
-use std::cell::RefCell;
-use std::sync::{Mutex, RwLock, Arc};
-use std::rc::Rc;
+use crate::cell::RefCell;
+use crate::panic::{AssertUnwindSafe, UnwindSafe};
+use crate::rc::Rc;
+use crate::sync::{Arc, Mutex, RwLock};
 
-struct Foo { a: i32 }
+struct Foo {
+    a: i32,
+}
 
 fn assert<T: UnwindSafe + ?Sized>() {}
 
-fn main() {
+#[test]
+fn panic_safety_traits() {
     assert::<i32>();
     assert::<&i32>();
     assert::<*mut i32>();
@@ -32,13 +34,16 @@ fn main() {
     assert::<Arc<i32>>();
     assert::<Box<[u8]>>();
 
-    trait Trait: UnwindSafe {}
-    assert::<Box<dyn Trait>>();
+    {
+        trait Trait: UnwindSafe {}
+        assert::<Box<dyn Trait>>();
+    }
 
     fn bar<T>() {
         assert::<Mutex<T>>();
         assert::<RwLock<T>>();
     }
+
     fn baz<T: UnwindSafe>() {
         assert::<Box<T>>();
         assert::<Vec<T>>();
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index b48d2162eca92..00680fadc18dc 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -93,60 +93,61 @@ pub fn init() {
         reset_sigpipe();
     }
 
-    // In the case when all file descriptors are open, the poll has been
-    // observed to perform better than fcntl (on GNU/Linux).
-    #[cfg(not(any(
-        miri,
-        target_os = "emscripten",
-        target_os = "fuchsia",
-        // The poll on Darwin doesn't set POLLNVAL for closed fds.
-        target_os = "macos",
-        target_os = "ios",
-        target_os = "redox",
-    )))]
-    unsafe fn sanitize_standard_fds() {
-        use crate::sys::os::errno;
-        let pfds: &mut [_] = &mut [
-            libc::pollfd { fd: 0, events: 0, revents: 0 },
-            libc::pollfd { fd: 1, events: 0, revents: 0 },
-            libc::pollfd { fd: 2, events: 0, revents: 0 },
-        ];
-        while libc::poll(pfds.as_mut_ptr(), 3, 0) == -1 {
-            if errno() == libc::EINTR {
-                continue;
-            }
-            libc::abort();
-        }
-        for pfd in pfds {
-            if pfd.revents & libc::POLLNVAL == 0 {
-                continue;
-            }
-            if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
-                // If the stream is closed but we failed to reopen it, abort the
-                // process. Otherwise we wouldn't preserve the safety of
-                // operations on the corresponding Rust object Stdin, Stdout, or
-                // Stderr.
-                libc::abort();
-            }
-        }
-    }
-    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "redox"))]
-    unsafe fn sanitize_standard_fds() {
-        use crate::sys::os::errno;
-        for fd in 0..3 {
-            if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF {
-                if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
+    cfg_if::cfg_if! {
+        if #[cfg(miri)] {
+            // The standard fds are always available in Miri.
+            unsafe fn sanitize_standard_fds() {}
+        } else if #[cfg(not(any(
+            target_os = "emscripten",
+            target_os = "fuchsia",
+            // The poll on Darwin doesn't set POLLNVAL for closed fds.
+            target_os = "macos",
+            target_os = "ios",
+            target_os = "redox",
+        )))] {
+            // In the case when all file descriptors are open, the poll has been
+            // observed to perform better than fcntl (on GNU/Linux).
+            unsafe fn sanitize_standard_fds() {
+                use crate::sys::os::errno;
+                let pfds: &mut [_] = &mut [
+                    libc::pollfd { fd: 0, events: 0, revents: 0 },
+                    libc::pollfd { fd: 1, events: 0, revents: 0 },
+                    libc::pollfd { fd: 2, events: 0, revents: 0 },
+                ];
+                while libc::poll(pfds.as_mut_ptr(), 3, 0) == -1 {
+                    if errno() == libc::EINTR {
+                        continue;
+                    }
                     libc::abort();
                 }
+                for pfd in pfds {
+                    if pfd.revents & libc::POLLNVAL == 0 {
+                        continue;
+                    }
+                    if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
+                        // If the stream is closed but we failed to reopen it, abort the
+                        // process. Otherwise we wouldn't preserve the safety of
+                        // operations on the corresponding Rust object Stdin, Stdout, or
+                        // Stderr.
+                        libc::abort();
+                    }
+                }
+            }
+        } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "redox"))] {
+            unsafe fn sanitize_standard_fds() {
+                use crate::sys::os::errno;
+                for fd in 0..3 {
+                    if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF {
+                        if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
+                            libc::abort();
+                        }
+                    }
+                }
             }
+        } else {
+            unsafe fn sanitize_standard_fds() {}
         }
     }
-    #[cfg(any(
-        // The standard fds are always available in Miri.
-        miri,
-        target_os = "emscripten",
-        target_os = "fuchsia"))]
-    unsafe fn sanitize_standard_fds() {}
 
     #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))]
     unsafe fn reset_sigpipe() {
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 074a43f2a7099..391859050e8a6 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -419,6 +419,7 @@ pub fn run_core(
                 (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id)
             };
         }),
+        make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
     };
 
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 7b7c152d8abbf..7a6c9eabb5f40 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -95,6 +95,7 @@ pub fn run(options: Options) -> Result<(), ErrorReported> {
         lint_caps,
         register_lints: None,
         override_queries: None,
+        make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
     };
 
diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs
index af84faa7511c6..2636423c1a480 100644
--- a/src/test/run-make-fulldeps/issue-19371/foo.rs
+++ b/src/test/run-make-fulldeps/issue-19371/foo.rs
@@ -60,6 +60,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
         lint_caps: Default::default(),
         register_lints: None,
         override_queries: None,
+        make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
     };
 
diff --git a/src/test/ui-fulldeps/compiler-calls.rs b/src/test/ui-fulldeps/compiler-calls.rs
index e97dcab6ae560..0025b47403d19 100644
--- a/src/test/ui-fulldeps/compiler-calls.rs
+++ b/src/test/ui-fulldeps/compiler-calls.rs
@@ -26,7 +26,13 @@ fn main() {
     let mut count = 1;
     let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
     rustc_driver::catch_fatal_errors(|| {
-        rustc_driver::run_compiler(&args, &mut TestCalls { count: &mut count }, None, None).ok();
+        rustc_driver::run_compiler(
+            &args,
+            &mut TestCalls { count: &mut count },
+            None,
+            None,
+            None,
+        ).ok();
     }).ok();
     assert_eq!(count, 2);
 }
diff --git a/src/test/ui/array-slice-vec/arr_cycle.rs b/src/test/ui/array-slice-vec/arr_cycle.rs
deleted file mode 100644
index c262b5a1ff09e..0000000000000
--- a/src/test/ui/array-slice-vec/arr_cycle.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// run-pass
-
-use std::cell::Cell;
-
-#[derive(Debug)]
-struct B<'a> {
-    a: [Cell<Option<&'a B<'a>>>; 2]
-}
-
-impl<'a> B<'a> {
-    fn new() -> B<'a> {
-        B { a: [Cell::new(None), Cell::new(None)] }
-    }
-}
-
-fn f() {
-    let (b1, b2, b3);
-    b1 = B::new();
-    b2 = B::new();
-    b3 = B::new();
-    b1.a[0].set(Some(&b2));
-    b1.a[1].set(Some(&b3));
-    b2.a[0].set(Some(&b2));
-    b2.a[1].set(Some(&b3));
-    b3.a[0].set(Some(&b1));
-    b3.a[1].set(Some(&b2));
-}
-
-fn main() {
-    f();
-}
diff --git a/src/test/ui/array-slice-vec/vec-slice-drop.rs b/src/test/ui/array-slice-vec/vec-slice-drop.rs
deleted file mode 100644
index 3a9ea86af34bb..0000000000000
--- a/src/test/ui/array-slice-vec/vec-slice-drop.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// run-pass
-
-#![allow(non_camel_case_types)]
-
-use std::cell::Cell;
-
-// Make sure that destructors get run on slice literals
-struct foo<'a> {
-    x: &'a Cell<isize>,
-}
-
-impl<'a> Drop for foo<'a> {
-    fn drop(&mut self) {
-        self.x.set(self.x.get() + 1);
-    }
-}
-
-fn foo(x: &Cell<isize>) -> foo {
-    foo {
-        x: x
-    }
-}
-
-pub fn main() {
-    let x = &Cell::new(0);
-    {
-        let l = &[foo(x)];
-        assert_eq!(l[0].x.get(), 0);
-    }
-    assert_eq!(x.get(), 1);
-}
diff --git a/src/test/ui/array-slice-vec/vec_cycle.rs b/src/test/ui/array-slice-vec/vec_cycle.rs
deleted file mode 100644
index 82bce43728262..0000000000000
--- a/src/test/ui/array-slice-vec/vec_cycle.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-// run-pass
-
-use std::cell::Cell;
-
-#[derive(Debug)]
-struct C<'a> {
-    v: Vec<Cell<Option<&'a C<'a>>>>,
-}
-
-impl<'a> C<'a> {
-    fn new() -> C<'a> {
-        C { v: Vec::new() }
-    }
-}
-
-fn f() {
-    let (mut c1, mut c2, mut c3);
-    c1 = C::new();
-    c2 = C::new();
-    c3 = C::new();
-
-    c1.v.push(Cell::new(None));
-    c1.v.push(Cell::new(None));
-    c2.v.push(Cell::new(None));
-    c2.v.push(Cell::new(None));
-    c3.v.push(Cell::new(None));
-    c3.v.push(Cell::new(None));
-
-    c1.v[0].set(Some(&c2));
-    c1.v[1].set(Some(&c3));
-    c2.v[0].set(Some(&c2));
-    c2.v[1].set(Some(&c3));
-    c3.v[0].set(Some(&c1));
-    c3.v[1].set(Some(&c2));
-}
-
-fn main() {
-    f();
-}
diff --git a/src/test/ui/array-slice-vec/vec_cycle_wrapped.rs b/src/test/ui/array-slice-vec/vec_cycle_wrapped.rs
deleted file mode 100644
index 1a3606d5e8d5a..0000000000000
--- a/src/test/ui/array-slice-vec/vec_cycle_wrapped.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-// run-pass
-
-use std::cell::Cell;
-
-#[derive(Debug)]
-struct Refs<'a> {
-    v: Vec<Cell<Option<&'a C<'a>>>>,
-}
-
-#[derive(Debug)]
-struct C<'a> {
-    refs: Refs<'a>,
-}
-
-impl<'a> Refs<'a> {
-    fn new() -> Refs<'a> {
-        Refs { v: Vec::new() }
-    }
-}
-
-impl<'a> C<'a> {
-    fn new() -> C<'a> {
-        C { refs: Refs::new() }
-    }
-}
-
-fn f() {
-    let (mut c1, mut c2, mut c3);
-    c1 = C::new();
-    c2 = C::new();
-    c3 = C::new();
-
-    c1.refs.v.push(Cell::new(None));
-    c1.refs.v.push(Cell::new(None));
-    c2.refs.v.push(Cell::new(None));
-    c2.refs.v.push(Cell::new(None));
-    c3.refs.v.push(Cell::new(None));
-    c3.refs.v.push(Cell::new(None));
-
-    c1.refs.v[0].set(Some(&c2));
-    c1.refs.v[1].set(Some(&c3));
-    c2.refs.v[0].set(Some(&c2));
-    c2.refs.v[1].set(Some(&c3));
-    c3.refs.v[0].set(Some(&c1));
-    c3.refs.v[1].set(Some(&c2));
-}
-
-fn main() {
-    f();
-}
diff --git a/src/test/ui/cell-does-not-clone.rs b/src/test/ui/cell-does-not-clone.rs
deleted file mode 100644
index 587447b54b7fd..0000000000000
--- a/src/test/ui/cell-does-not-clone.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-// run-pass
-
-#![allow(dead_code)]
-
-use std::cell::Cell;
-
-#[derive(Copy)]
-struct Foo {
-    x: isize
-}
-
-impl Clone for Foo {
-    fn clone(&self) -> Foo {
-        // Using Cell in any way should never cause clone() to be
-        // invoked -- after all, that would permit evil user code to
-        // abuse `Cell` and trigger crashes.
-
-        panic!();
-    }
-}
-
-pub fn main() {
-    let x = Cell::new(Foo { x: 22 });
-    let _y = x.get();
-    let _z = x.clone();
-}
diff --git a/src/test/ui/consts/auxiliary/const_fn_lib.rs b/src/test/ui/consts/auxiliary/const_fn_lib.rs
index 85714efdbe99c..bf0b01a2ecfe0 100644
--- a/src/test/ui/consts/auxiliary/const_fn_lib.rs
+++ b/src/test/ui/consts/auxiliary/const_fn_lib.rs
@@ -1,6 +1,6 @@
 // Crate that exports a const fn. Used for testing cross-crate.
 
-#![feature(const_fn)]
+#![feature(const_fn_fn_ptr_basics)]
 #![crate_type="rlib"]
 
 pub const fn foo() -> usize { 22 }
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr.stderr b/src/test/ui/consts/const-eval/const_fn_ptr.stderr
index d0ae94079da2e..ab18020056b0a 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr.stderr
+++ b/src/test/ui/consts/const-eval/const_fn_ptr.stderr
@@ -10,11 +10,23 @@ help: skipping check that does not even have a feature gate
    |
 LL |     X_CONST(x)
    |     ^^^^^^^^^^
+help: skipping check for `const_fn_fn_ptr_basics` feature
+  --> $DIR/const_fn_ptr.rs:19:14
+   |
+LL | const fn foo(x: fn(usize) -> usize, y: usize)  -> usize {
+   |              ^
+help: skipping check for `const_fn_fn_ptr_basics` feature
+  --> $DIR/const_fn_ptr.rs:20:5
+   |
+LL |     x(y)
+   |     ^
 help: skipping check that does not even have a feature gate
   --> $DIR/const_fn_ptr.rs:20:5
    |
 LL |     x(y)
    |     ^^^^
 
-warning: 1 warning emitted
+error: `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
+
+error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
index 90ee2afa315d8..822d4af83064e 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
@@ -20,6 +20,16 @@ LL |     assert_eq!(Z, 4);
 
 warning: skipping const checks
    |
+help: skipping check for `const_fn_fn_ptr_basics` feature
+  --> $DIR/const_fn_ptr_fail2.rs:12:14
+   |
+LL | const fn bar(x: fn(usize) -> usize, y: usize) -> usize {
+   |              ^
+help: skipping check for `const_fn_fn_ptr_basics` feature
+  --> $DIR/const_fn_ptr_fail2.rs:13:5
+   |
+LL |     x(y)
+   |     ^
 help: skipping check that does not even have a feature gate
   --> $DIR/const_fn_ptr_fail2.rs:13:5
    |
diff --git a/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs b/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs
index 59d46ea66c9ca..bf8bae5ea2c73 100644
--- a/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs
+++ b/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs
@@ -1,5 +1,5 @@
 // check-pass
-#![feature(const_fn)]
+#![feature(const_fn_fn_ptr_basics)]
 
 const fn nested(x: (for<'a> fn(&'a ()), String)) -> (fn(&'static ()), String) {
     x
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 094ae7378bce8..8642954a75b45 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
@@ -2,7 +2,7 @@
 
 const extern fn unsize(x: &[u8; 3]) -> &[u8] { x }
 const unsafe extern "C" fn closure() -> fn() { || {} }
-//~^ ERROR function pointers in const fn are unstable
+//~^ ERROR function pointer
 const unsafe extern fn use_float() { 1.0 + 1.0; }
 //~^ ERROR floating point arithmetic
 const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
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 fcc34f358f9f9..455a822e2d085 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
@@ -1,11 +1,11 @@
-error[E0723]: function pointers in const fn are unstable
+error[E0658]: function pointers cannot appear in constant functions
   --> $DIR/const-extern-fn-min-const-fn.rs:4:41
    |
 LL | const unsafe extern "C" fn closure() -> fn() { || {} }
    |                                         ^^^^
    |
    = 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: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
 error[E0658]: floating point arithmetic is not allowed in constant functions
   --> $DIR/const-extern-fn-min-const-fn.rs:6:38
@@ -27,5 +27,4 @@ LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
 
 error: aborting due to 3 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/issue-37550.rs b/src/test/ui/consts/issue-37550.rs
index 04865830df2eb..15877c53747ec 100644
--- a/src/test/ui/consts/issue-37550.rs
+++ b/src/test/ui/consts/issue-37550.rs
@@ -2,7 +2,7 @@
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
-#![feature(const_fn)]
+#![feature(const_fn_fn_ptr_basics)]
 
 const fn x() {
     let t = true;
diff --git a/src/test/ui/consts/issue-56164.rs b/src/test/ui/consts/issue-56164.rs
index 9d1a8b59463e7..90ea217698d65 100644
--- a/src/test/ui/consts/issue-56164.rs
+++ b/src/test/ui/consts/issue-56164.rs
@@ -1,12 +1,11 @@
-#![feature(const_fn)]
+#![feature(const_fn_fn_ptr_basics)]
 
 const fn foo() { (||{})() }
-//~^ ERROR calls in constant functions are limited to constant functions, tuple structs and tuple
-// variants
+//~^ ERROR calls in constant functions
 
 const fn bad(input: fn()) {
     input()
-    //~^ ERROR function pointers are not allowed in const fn
+    //~^ ERROR function pointer
 }
 
 fn main() {
diff --git a/src/test/ui/consts/issue-56164.stderr b/src/test/ui/consts/issue-56164.stderr
index d3e9ce379aed7..500af0a40069a 100644
--- a/src/test/ui/consts/issue-56164.stderr
+++ b/src/test/ui/consts/issue-56164.stderr
@@ -5,7 +5,7 @@ LL | const fn foo() { (||{})() }
    |                  ^^^^^^^^
 
 error: function pointers are not allowed in const fn
-  --> $DIR/issue-56164.rs:8:5
+  --> $DIR/issue-56164.rs:7:5
    |
 LL |     input()
    |     ^^^^^^^
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
index 937aae1a8e399..dc10db177ed69 100644
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
+++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
@@ -1,12 +1,14 @@
-#![feature(rustc_attrs, staged_api)]
+#![feature(rustc_attrs, staged_api, allow_internal_unstable)]
+#![feature(const_fn_fn_ptr_basics)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(since="1.0.0", feature = "mep")]
-const fn error(_: fn()) {} //~ ERROR function pointers in const fn are unstable
+const fn error(_: fn()) {}
+//~^ ERROR const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_allow_const_fn_ptr]
 #[rustc_const_stable(since="1.0.0", feature = "mep")]
+#[allow_internal_unstable(const_fn_fn_ptr_basics)]
 const fn compiles(_: fn()) {}
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
index 9a14bcc2f7335..94f6cda209749 100644
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
+++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
@@ -1,12 +1,14 @@
-error[E0723]: function pointers in const fn are unstable
-  --> $DIR/allow_const_fn_ptr.rs:5:16
+error: const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
+  --> $DIR/allow_const_fn_ptr.rs:6:16
    |
 LL | const fn error(_: fn()) {}
    |                ^
    |
-   = 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: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0723`.
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs
deleted file mode 100644
index 0f9d37292958a..0000000000000
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(staged_api)]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-const fn error(_: fn()) {}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_allow_const_fn_ptr]
-//~^ ERROR internal implementation detail
-const fn compiles(_: fn()) {}
-
-fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr
deleted file mode 100644
index 7794cc7583dfc..0000000000000
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0658]: internal implementation detail
-  --> $DIR/allow_const_fn_ptr_feature_gate.rs:7:1
-   |
-LL | #[rustc_allow_const_fn_ptr]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
index 7aa9bd7e2dcdd..b4e836bbc9540 100644
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
+++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
@@ -1,11 +1,13 @@
 // run-pass
+#![feature(allow_internal_unstable)]
+#![feature(const_fn_fn_ptr_basics)]
 
 #![feature(rustc_attrs, staged_api)]
 #![stable(feature = "rust1", since = "1.0.0")]
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_allow_const_fn_ptr]
 #[rustc_const_stable(since="1.0.0", feature = "mep")]
+#[allow_internal_unstable(const_fn_fn_ptr_basics)]
 const fn takes_fn_ptr(_: fn()) {}
 
 const FN: fn() = || ();
diff --git a/src/test/ui/consts/min_const_fn/cast_errors.rs b/src/test/ui/consts/min_const_fn/cast_errors.rs
index 8d730df16b0d1..43ef8ea12eb1f 100644
--- a/src/test/ui/consts/min_const_fn/cast_errors.rs
+++ b/src/test/ui/consts/min_const_fn/cast_errors.rs
@@ -2,12 +2,12 @@ fn main() {}
 
 const fn unsize(x: &[u8; 3]) -> &[u8] { x }
 const fn closure() -> fn() { || {} }
-//~^ ERROR function pointers in const fn are unstable
+//~^ ERROR function pointer
 const fn closure2() {
     (|| {}) as fn();
-//~^ ERROR function pointers in const fn are unstable
+//~^ ERROR function pointer
 }
 const fn reify(f: fn()) -> unsafe fn() { f }
-//~^ ERROR function pointers in const fn are unstable
+//~^ ERROR function pointer
 const fn reify2() { main as unsafe fn(); }
-//~^ ERROR function pointers in const fn are unstable
+//~^ ERROR function pointer
diff --git a/src/test/ui/consts/min_const_fn/cast_errors.stderr b/src/test/ui/consts/min_const_fn/cast_errors.stderr
index 583cb4e9720cc..ac77c181afda8 100644
--- a/src/test/ui/consts/min_const_fn/cast_errors.stderr
+++ b/src/test/ui/consts/min_const_fn/cast_errors.stderr
@@ -1,39 +1,39 @@
-error[E0723]: function pointers in const fn are unstable
+error[E0658]: function pointers cannot appear in constant functions
   --> $DIR/cast_errors.rs:4:23
    |
 LL | const fn closure() -> fn() { || {} }
    |                       ^^^^
    |
    = 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: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
-error[E0723]: function pointers in const fn are unstable
+error[E0658]: function pointers cannot appear in constant functions
   --> $DIR/cast_errors.rs:7:5
    |
 LL |     (|| {}) as fn();
    |     ^^^^^^^^^^^^^^^
    |
    = 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: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
-error[E0723]: function pointers in const fn are unstable
+error[E0658]: function pointers cannot appear in constant functions
   --> $DIR/cast_errors.rs:10:28
    |
 LL | const fn reify(f: fn()) -> unsafe fn() { 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
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
-error[E0723]: function pointers in const fn are unstable
+error[E0658]: function pointers cannot appear in constant functions
   --> $DIR/cast_errors.rs:12:21
    |
 LL | const fn reify2() { main as unsafe fn(); }
    |                     ^^^^^^^^^^^^^^^^^^^
    |
    = 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: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0723`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs
index c2600f894dc42..4aaf7b86e4560 100644
--- a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs
+++ b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs
@@ -1,4 +1,4 @@
-const fn cmp(x: fn(), y: fn()) -> bool { //~ ERROR function pointers in const fn are unstable
+const fn cmp(x: fn(), y: fn()) -> bool { //~ ERROR function pointer
     unsafe { x == y }
 }
 
diff --git a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr
index 74e5228d0dc62..e913b187feeae 100644
--- a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr
+++ b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr
@@ -1,12 +1,12 @@
-error[E0723]: function pointers in const fn are unstable
+error[E0658]: function pointers cannot appear in constant functions
   --> $DIR/cmp_fn_pointers.rs:1:14
    |
 LL | const fn cmp(x: fn(), y: fn()) -> bool {
    |              ^
    |
    = 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: add `#![feature(const_fn_fn_ptr_basics)]` 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 E0658`.
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 55a999d5cdc04..06a44b271064c 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
@@ -128,6 +128,6 @@ const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
 //~^ ERROR trait bounds other than `Sized`
 
 const fn no_fn_ptrs(_x: fn()) {}
-//~^ ERROR function pointers in const fn are unstable
+//~^ ERROR function pointer
 const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
-//~^ ERROR function pointers in const fn are unstable
+//~^ ERROR function pointer
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 a37e5203eeef4..5e6bf7ef89034 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
@@ -209,23 +209,23 @@ LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1
    = 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]: function pointers in const fn are unstable
+error[E0658]: function pointers cannot appear in constant functions
   --> $DIR/min_const_fn.rs:130:21
    |
 LL | const fn no_fn_ptrs(_x: fn()) {}
    |                     ^^
    |
    = 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: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
-error[E0723]: function pointers in const fn are unstable
+error[E0658]: function pointers cannot appear in constant functions
   --> $DIR/min_const_fn.rs:132:27
    |
 LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} 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: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
 error: aborting due to 26 previous errors
 
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs
index 584ea46b1a6f7..bc6fe89222bbf 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs
@@ -1,3 +1,5 @@
+// gate-test-const_fn_fn_ptr_basics
+
 struct HasPtr {
     field: fn(),
 }
@@ -9,9 +11,9 @@ fn field() {}
 const fn no_inner_dyn_trait(_x: Hide) {}
 const fn no_inner_dyn_trait2(x: Hide) {
     x.0.field;
-//~^ ERROR function pointers in const fn
+//~^ ERROR function pointer
 }
 const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
-//~^ ERROR function pointers in const fn
+//~^ ERROR function pointer
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr
index 58acbb5339aff..8d60436ea39bb 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr
@@ -1,21 +1,21 @@
-error[E0723]: function pointers in const fn are unstable
-  --> $DIR/min_const_fn_fn_ptr.rs:11:5
+error[E0658]: function pointers cannot appear in constant functions
+  --> $DIR/min_const_fn_fn_ptr.rs:13:5
    |
 LL |     x.0.field;
    |     ^^^^^^^^^
    |
    = 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: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
-error[E0723]: function pointers in const fn are unstable
-  --> $DIR/min_const_fn_fn_ptr.rs:14:59
+error[E0658]: function pointers cannot appear in constant functions
+  --> $DIR/min_const_fn_fn_ptr.rs:16:59
    |
 LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
    |                                                           ^^^^^
    |
    = 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: add `#![feature(const_fn_fn_ptr_basics)]` 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 E0658`.
diff --git a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
index 93b67fd7b1428..8fd562c5dae84 100644
--- a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
+++ b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
@@ -12,12 +12,12 @@ 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
+help: skipping check for `const_fn_fn_ptr_basics` 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
+help: skipping check for `const_fn_fn_ptr_basics` feature
   --> $DIR/abi-mismatch.rs:10:5
    |
 LL |     my_fn();
diff --git a/src/test/ui/deref-lval.rs b/src/test/ui/deref-lval.rs
deleted file mode 100644
index f57872f80e025..0000000000000
--- a/src/test/ui/deref-lval.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// run-pass
-
-#![feature(box_syntax)]
-
-use std::cell::Cell;
-
-pub fn main() {
-    let x: Box<_> = box Cell::new(5);
-    x.set(1000);
-    println!("{}", x.get());
-}
diff --git a/src/test/ui/exterior.rs b/src/test/ui/exterior.rs
deleted file mode 100644
index 6f2c37926bea6..0000000000000
--- a/src/test/ui/exterior.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// run-pass
-
-#![allow(dead_code)]
-
-
-use std::cell::Cell;
-
-#[derive(Copy, Clone)]
-struct Point {x: isize, y: isize, z: isize}
-
-fn f(p: &Cell<Point>) {
-    assert_eq!(p.get().z, 12);
-    p.set(Point {x: 10, y: 11, z: 13});
-    assert_eq!(p.get().z, 13);
-}
-
-pub fn main() {
-    let a: Point = Point {x: 10, y: 11, z: 12};
-    let b: &Cell<Point> = &Cell::new(a);
-    assert_eq!(b.get().z, 12);
-    f(b);
-    assert_eq!(a.z, 12);
-    assert_eq!(b.get().z, 13);
-}
diff --git a/src/test/ui/format-ref-cell.rs b/src/test/ui/format-ref-cell.rs
deleted file mode 100644
index afb2f8488b82a..0000000000000
--- a/src/test/ui/format-ref-cell.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// run-pass
-
-use std::cell::RefCell;
-
-pub fn main() {
-    let name = RefCell::new("rust");
-    let what = RefCell::new("rocks");
-    let msg = format!("{name} {}", &*what.borrow(), name=&*name.borrow());
-    assert_eq!(msg, "rust rocks".to_string());
-}
diff --git a/src/test/ui/ifmt.rs b/src/test/ui/ifmt.rs
deleted file mode 100644
index 27ab3d6b7abff..0000000000000
--- a/src/test/ui/ifmt.rs
+++ /dev/null
@@ -1,319 +0,0 @@
-// run-pass
-
-#![deny(warnings)]
-#![allow(unused_must_use)]
-#![allow(unused_features)]
-#![feature(box_syntax)]
-
-use std::cell::RefCell;
-use std::fmt::{self, Write};
-use std::usize;
-
-struct A;
-struct B;
-struct C;
-struct D;
-
-impl fmt::LowerHex for A {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.write_str("aloha")
-    }
-}
-impl fmt::UpperHex for B {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.write_str("adios")
-    }
-}
-impl fmt::Display for C {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.pad_integral(true, "☃", "123")
-    }
-}
-impl fmt::Binary for D {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.write_str("aa")?;
-        f.write_char('☃')?;
-        f.write_str("bb")
-    }
-}
-
-macro_rules! t {
-    ($a:expr, $b:expr) => { assert_eq!($a, $b) }
-}
-
-pub fn main() {
-    // Various edge cases without formats
-    t!(format!(""), "");
-    t!(format!("hello"), "hello");
-    t!(format!("hello {{"), "hello {");
-
-    // default formatters should work
-    t!(format!("{}", 1.0f32), "1");
-    t!(format!("{}", 1.0f64), "1");
-    t!(format!("{}", "a"), "a");
-    t!(format!("{}", "a".to_string()), "a");
-    t!(format!("{}", false), "false");
-    t!(format!("{}", 'a'), "a");
-
-    // At least exercise all the formats
-    t!(format!("{}", true), "true");
-    t!(format!("{}", '☃'), "☃");
-    t!(format!("{}", 10), "10");
-    t!(format!("{}", 10_usize), "10");
-    t!(format!("{:?}", '☃'), "'☃'");
-    t!(format!("{:?}", 10), "10");
-    t!(format!("{:?}", 10_usize), "10");
-    t!(format!("{:?}", "true"), "\"true\"");
-    t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\"");
-    t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"),
-       r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#);
-    t!(format!("{:?}", "foo\0bar\x01baz\u{7f}q\u{75}x"),
-       r#""foo\u{0}bar\u{1}baz\u{7f}qux""#);
-    t!(format!("{:o}", 10_usize), "12");
-    t!(format!("{:x}", 10_usize), "a");
-    t!(format!("{:X}", 10_usize), "A");
-    t!(format!("{}", "foo"), "foo");
-    t!(format!("{}", "foo".to_string()), "foo");
-    if cfg!(target_pointer_width = "32") {
-        t!(format!("{:#p}", 0x1234 as *const isize), "0x00001234");
-        t!(format!("{:#p}", 0x1234 as *mut isize), "0x00001234");
-    } else {
-        t!(format!("{:#p}", 0x1234 as *const isize), "0x0000000000001234");
-        t!(format!("{:#p}", 0x1234 as *mut isize), "0x0000000000001234");
-    }
-    t!(format!("{:p}", 0x1234 as *const isize), "0x1234");
-    t!(format!("{:p}", 0x1234 as *mut isize), "0x1234");
-    t!(format!("{:x}", A), "aloha");
-    t!(format!("{:X}", B), "adios");
-    t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
-    t!(format!("{1} {0}", 0, 1), "1 0");
-    t!(format!("{foo} {bar}", foo=0, bar=1), "0 1");
-    t!(format!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0");
-    t!(format!("{} {0}", "a"), "a a");
-    t!(format!("{_foo}", _foo = 6usize), "6");
-    t!(format!("{foo_bar}", foo_bar=1), "1");
-    t!(format!("{}", 5 + 5), "10");
-    t!(format!("{:#4}", C), "☃123");
-    t!(format!("{:b}", D), "aa☃bb");
-
-    let a: &dyn fmt::Debug = &1;
-    t!(format!("{:?}", a), "1");
-
-    // Formatting strings and their arguments
-    t!(format!("{}", "a"), "a");
-    t!(format!("{:4}", "a"), "a   ");
-    t!(format!("{:4}", "☃"), "☃   ");
-    t!(format!("{:>4}", "a"), "   a");
-    t!(format!("{:<4}", "a"), "a   ");
-    t!(format!("{:^5}", "a"),  "  a  ");
-    t!(format!("{:^5}", "aa"), " aa  ");
-    t!(format!("{:^4}", "a"),  " a  ");
-    t!(format!("{:^4}", "aa"), " aa ");
-    t!(format!("{:.4}", "a"), "a");
-    t!(format!("{:4.4}", "a"), "a   ");
-    t!(format!("{:4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
-    t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
-    t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
-    t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
-    t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), "      aaaa");
-    t!(format!("{:2.4}", "aaaaa"), "aaaa");
-    t!(format!("{:2.4}", "aaaa"), "aaaa");
-    t!(format!("{:2.4}", "aaa"), "aaa");
-    t!(format!("{:2.4}", "aa"), "aa");
-    t!(format!("{:2.4}", "a"), "a ");
-    t!(format!("{:0>2}", "a"), "0a");
-    t!(format!("{:.*}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa");
-    t!(format!("{:.1$}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa");
-    t!(format!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a=4), "aaaa");
-    t!(format!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a=4), "aaaa");
-    t!(format!("{:1$}", "a", 4), "a   ");
-    t!(format!("{1:0$}", 4, "a"), "a   ");
-    t!(format!("{:a$}", "a", a=4), "a   ");
-    t!(format!("{:-#}", "a"), "a");
-    t!(format!("{:+#}", "a"), "a");
-    t!(format!("{:/^10.8}", "1234567890"), "/12345678/");
-
-    // Some float stuff
-    t!(format!("{:}", 1.0f32), "1");
-    t!(format!("{:}", 1.0f64), "1");
-    t!(format!("{:.3}", 1.0f64), "1.000");
-    t!(format!("{:10.3}", 1.0f64),   "     1.000");
-    t!(format!("{:+10.3}", 1.0f64),  "    +1.000");
-    t!(format!("{:+10.3}", -1.0f64), "    -1.000");
-
-    t!(format!("{:e}", 1.2345e6f32), "1.2345e6");
-    t!(format!("{:e}", 1.2345e6f64), "1.2345e6");
-    t!(format!("{:E}", 1.2345e6f64), "1.2345E6");
-    t!(format!("{:.3e}", 1.2345e6f64), "1.234e6");
-    t!(format!("{:10.3e}", 1.2345e6f64),   "   1.234e6");
-    t!(format!("{:+10.3e}", 1.2345e6f64),  "  +1.234e6");
-    t!(format!("{:+10.3e}", -1.2345e6f64), "  -1.234e6");
-
-    // Float edge cases
-    t!(format!("{}", -0.0), "0");
-    t!(format!("{:?}", -0.0), "-0.0");
-    t!(format!("{:?}", 0.0), "0.0");
-
-    // sign aware zero padding
-    t!(format!("{:<3}", 1), "1  ");
-    t!(format!("{:>3}", 1), "  1");
-    t!(format!("{:^3}", 1), " 1 ");
-    t!(format!("{:03}", 1), "001");
-    t!(format!("{:<03}", 1), "001");
-    t!(format!("{:>03}", 1), "001");
-    t!(format!("{:^03}", 1), "001");
-    t!(format!("{:+03}", 1), "+01");
-    t!(format!("{:<+03}", 1), "+01");
-    t!(format!("{:>+03}", 1), "+01");
-    t!(format!("{:^+03}", 1), "+01");
-    t!(format!("{:#05x}", 1), "0x001");
-    t!(format!("{:<#05x}", 1), "0x001");
-    t!(format!("{:>#05x}", 1), "0x001");
-    t!(format!("{:^#05x}", 1), "0x001");
-    t!(format!("{:05}", 1.2), "001.2");
-    t!(format!("{:<05}", 1.2), "001.2");
-    t!(format!("{:>05}", 1.2), "001.2");
-    t!(format!("{:^05}", 1.2), "001.2");
-    t!(format!("{:05}", -1.2), "-01.2");
-    t!(format!("{:<05}", -1.2), "-01.2");
-    t!(format!("{:>05}", -1.2), "-01.2");
-    t!(format!("{:^05}", -1.2), "-01.2");
-    t!(format!("{:+05}", 1.2), "+01.2");
-    t!(format!("{:<+05}", 1.2), "+01.2");
-    t!(format!("{:>+05}", 1.2), "+01.2");
-    t!(format!("{:^+05}", 1.2), "+01.2");
-
-    // Ergonomic format_args!
-    t!(format!("{0:x} {0:X}", 15), "f F");
-    t!(format!("{0:x} {0:X} {}", 15), "f F 15");
-    t!(format!("{:x}{0:X}{a:x}{:X}{1:x}{a:X}", 13, 14, a=15), "dDfEeF");
-    t!(format!("{a:x} {a:X}", a=15), "f F");
-
-    // And its edge cases
-    t!(format!("{a:.0$} {b:.0$} {0:.0$}\n{a:.c$} {b:.c$} {c:.c$}",
-               4, a="abcdefg", b="hijklmn", c=3),
-               "abcd hijk 4\nabc hij 3");
-    t!(format!("{a:.*} {0} {:.*}", 4, 3, "efgh", a="abcdef"), "abcd 4 efg");
-    t!(format!("{:.a$} {a} {a:#x}", "aaaaaa", a=2), "aa 2 0x2");
-
-    // Test that pointers don't get truncated.
-    {
-        let val = usize::MAX;
-        let exp = format!("{:#x}", val);
-        t!(format!("{:p}", val as *const isize), exp);
-    }
-
-    // Escaping
-    t!(format!("{{"), "{");
-    t!(format!("}}"), "}");
-
-    test_write();
-    test_print();
-    test_order();
-    test_once();
-
-    // make sure that format! doesn't move out of local variables
-    let a: Box<_> = box 3;
-    format!("{}", a);
-    format!("{}", a);
-
-    // make sure that format! doesn't cause spurious unused-unsafe warnings when
-    // it's inside of an outer unsafe block
-    unsafe {
-        let a: isize = ::std::mem::transmute(3_usize);
-        format!("{}", a);
-    }
-
-    test_format_args();
-
-    // test that trailing commas are acceptable
-    format!("{}", "test",);
-    format!("{foo}", foo="test",);
-
-    test_refcell();
-}
-
-// Basic test to make sure that we can invoke the `write!` macro with an
-// fmt::Write instance.
-fn test_write() {
-    let mut buf = String::new();
-    write!(&mut buf, "{}", 3);
-    {
-        let w = &mut buf;
-        write!(w, "{foo}", foo=4);
-        write!(w, "{}", "hello");
-        writeln!(w, "{}", "line");
-        writeln!(w, "{foo}", foo="bar");
-        w.write_char('☃');
-        w.write_str("str");
-    }
-
-    t!(buf, "34helloline\nbar\n☃str");
-}
-
-// Just make sure that the macros are defined, there's not really a lot that we
-// can do with them just yet (to test the output)
-fn test_print() {
-    print!("hi");
-    print!("{:?}", vec![0u8]);
-    println!("hello");
-    println!("this is a {}", "test");
-    println!("{foo}", foo="bar");
-}
-
-// Just make sure that the macros are defined, there's not really a lot that we
-// can do with them just yet (to test the output)
-fn test_format_args() {
-    let mut buf = String::new();
-    {
-        let w = &mut buf;
-        write!(w, "{}", format_args!("{}", 1));
-        write!(w, "{}", format_args!("test"));
-        write!(w, "{}", format_args!("{test}", test=3));
-    }
-    let s = buf;
-    t!(s, "1test3");
-
-    let s = fmt::format(format_args!("hello {}", "world"));
-    t!(s, "hello world");
-    let s = format!("{}: {}", "args were", format_args!("hello {}", "world"));
-    t!(s, "args were: hello world");
-}
-
-fn test_order() {
-    // Make sure format!() arguments are always evaluated in a left-to-right
-    // ordering
-    fn foo() -> isize {
-        static mut FOO: isize = 0;
-        unsafe {
-            FOO += 1;
-            FOO
-        }
-    }
-    assert_eq!(format!("{} {} {a} {b} {} {c}",
-                       foo(), foo(), foo(), a=foo(), b=foo(), c=foo()),
-               "1 2 4 5 3 6".to_string());
-}
-
-fn test_once() {
-    // Make sure each argument are evaluated only once even though it may be
-    // formatted multiple times
-    fn foo() -> isize {
-        static mut FOO: isize = 0;
-        unsafe {
-            FOO += 1;
-            FOO
-        }
-    }
-    assert_eq!(format!("{0} {0} {0} {a} {a} {a}", foo(), a=foo()),
-               "1 1 1 2 2 2".to_string());
-}
-
-fn test_refcell() {
-    let refcell = RefCell::new(5);
-    assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }");
-    let borrow = refcell.borrow_mut();
-    assert_eq!(format!("{:?}", refcell), "RefCell { value: <borrowed> }");
-    drop(borrow);
-    assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }");
-}
diff --git a/src/test/ui/issues/issue-37550.rs b/src/test/ui/issues/issue-37550.rs
index 505c030b96712..35b63bddca252 100644
--- a/src/test/ui/issues/issue-37550.rs
+++ b/src/test/ui/issues/issue-37550.rs
@@ -1,6 +1,6 @@
 const fn x() {
     let t = true;
-    let x = || t; //~ ERROR function pointers in const fn are unstable
+    let x = || t; //~ ERROR function pointer
 }
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-37550.stderr b/src/test/ui/issues/issue-37550.stderr
index 35da625801617..54b60df70fd26 100644
--- a/src/test/ui/issues/issue-37550.stderr
+++ b/src/test/ui/issues/issue-37550.stderr
@@ -1,12 +1,12 @@
-error[E0723]: function pointers in const fn are unstable
+error[E0658]: function pointers cannot appear in constant functions
   --> $DIR/issue-37550.rs:3:9
    |
 LL |     let x = || t;
    |         ^
    |
    = 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: add `#![feature(const_fn_fn_ptr_basics)]` 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 E0658`.
diff --git a/src/test/ui/issues/issue-46553.rs b/src/test/ui/issues/issue-46553.rs
index e21a532effd1d..0a1e835672de9 100644
--- a/src/test/ui/issues/issue-46553.rs
+++ b/src/test/ui/issues/issue-46553.rs
@@ -1,5 +1,5 @@
 // run-pass
-#![feature(const_fn)]
+#![feature(const_fn_fn_ptr_basics)]
 #![deny(const_err)]
 
 pub struct Data<T> {
diff --git a/src/test/ui/issues/issue-51154.rs b/src/test/ui/issues/issue-51154.rs
new file mode 100644
index 0000000000000..12903f79010cb
--- /dev/null
+++ b/src/test/ui/issues/issue-51154.rs
@@ -0,0 +1,6 @@
+fn foo<F: FnMut()>() {
+    let _: Box<F> = Box::new(|| ());
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-51154.stderr b/src/test/ui/issues/issue-51154.stderr
new file mode 100644
index 0000000000000..3c3428f3096a8
--- /dev/null
+++ b/src/test/ui/issues/issue-51154.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-51154.rs:2:30
+   |
+LL | fn foo<F: FnMut()>() {
+   |        - this type parameter
+LL |     let _: Box<F> = Box::new(|| ());
+   |                              ^^^^^ expected type parameter `F`, found closure
+   |
+   = note: expected type parameter `F`
+                     found closure `[closure@$DIR/issue-51154.rs:2:30: 2:35]`
+   = help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `F`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/iterators/iter-zip.rs b/src/test/ui/iterators/iter-zip.rs
deleted file mode 100644
index a76fa2408bb8a..0000000000000
--- a/src/test/ui/iterators/iter-zip.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-// run-pass
-// Test that .zip() specialization preserves side effects
-// in sideeffectful iterator adaptors.
-
-use std::cell::Cell;
-
-#[derive(Debug)]
-struct CountClone(Cell<i32>);
-
-fn count_clone() -> CountClone { CountClone(Cell::new(0)) }
-
-impl PartialEq<i32> for CountClone {
-    fn eq(&self, rhs: &i32) -> bool {
-        self.0.get() == *rhs
-    }
-}
-
-impl Clone for CountClone {
-    fn clone(&self) -> Self {
-        let ret = CountClone(self.0.clone());
-        let n = self.0.get();
-        self.0.set(n + 1);
-        ret
-    }
-}
-
-fn test_zip_cloned_sideffectful() {
-    let xs = [count_clone(), count_clone(), count_clone(), count_clone()];
-    let ys = [count_clone(), count_clone()];
-
-    for _ in xs.iter().cloned().zip(ys.iter().cloned()) { }
-
-    assert_eq!(&xs, &[1, 1, 1, 0][..]);
-    assert_eq!(&ys, &[1, 1][..]);
-
-    let xs = [count_clone(), count_clone()];
-    let ys = [count_clone(), count_clone(), count_clone(), count_clone()];
-
-    for _ in xs.iter().cloned().zip(ys.iter().cloned()) { }
-
-    assert_eq!(&xs, &[1, 1][..]);
-    assert_eq!(&ys, &[1, 1, 0, 0][..]);
-}
-
-fn test_zip_map_sideffectful() {
-    let mut xs = [0; 6];
-    let mut ys = [0; 4];
-
-    for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) { }
-
-    assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
-    assert_eq!(&ys, &[1, 1, 1, 1]);
-
-    let mut xs = [0; 4];
-    let mut ys = [0; 6];
-
-    for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) { }
-
-    assert_eq!(&xs, &[1, 1, 1, 1]);
-    assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]);
-}
-
-fn test_zip_map_rev_sideffectful() {
-    let mut xs = [0; 6];
-    let mut ys = [0; 4];
-
-    {
-        let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
-        it.next_back();
-    }
-    assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]);
-    assert_eq!(&ys, &[0, 0, 0, 1]);
-
-    let mut xs = [0; 6];
-    let mut ys = [0; 4];
-
-    {
-        let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
-        (&mut it).take(5).count();
-        it.next_back();
-    }
-    assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]);
-    assert_eq!(&ys, &[1, 1, 1, 1]);
-}
-
-fn test_zip_nested_sideffectful() {
-    let mut xs = [0; 6];
-    let ys = [0; 4];
-
-    {
-        // test that it has the side effect nested inside enumerate
-        let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys);
-        it.count();
-    }
-    assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
-}
-
-fn main() {
-    test_zip_cloned_sideffectful();
-    test_zip_map_sideffectful();
-    test_zip_map_rev_sideffectful();
-    test_zip_nested_sideffectful();
-}
diff --git a/src/test/ui/option-unwrap.rs b/src/test/ui/option-unwrap.rs
deleted file mode 100644
index 173f803ee24d2..0000000000000
--- a/src/test/ui/option-unwrap.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-// run-pass
-
-#![allow(non_camel_case_types)]
-use std::cell::Cell;
-
-struct dtor<'a> {
-    x: &'a Cell<isize>,
-}
-
-impl<'a> Drop for dtor<'a> {
-    fn drop(&mut self) {
-        self.x.set(self.x.get() - 1);
-    }
-}
-
-fn unwrap<T>(o: Option<T>) -> T {
-    match o {
-      Some(v) => v,
-      None => panic!()
-    }
-}
-
-pub fn main() {
-    let x = &Cell::new(1);
-
-    {
-        let b = Some(dtor { x:x });
-        let _c = unwrap(b);
-    }
-
-    assert_eq!(x.get(), 0);
-}
diff --git a/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr b/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr
index cf8ca57714c29..0291a52633358 100644
--- a/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr
+++ b/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr
@@ -1,10 +1,27 @@
 warning: skipping const checks
    |
+help: skipping check for `const_fn_fn_ptr_basics` feature
+  --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:20:9
+   |
+LL |     let ptr: fn() -> L = attributed;
+   |         ^^^
+help: skipping check for `const_fn_fn_ptr_basics` feature
+  --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5
+   |
+LL |     ptr()
+   |     ^^^
+help: skipping check for `const_fn_fn_ptr_basics` feature
+  --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:20:26
+   |
+LL |     let ptr: fn() -> L = attributed;
+   |                          ^^^^^^^^^^
 help: skipping check that does not even have a feature gate
   --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5
    |
 LL |     ptr()
    |     ^^^^^
 
-warning: 1 warning emitted
+error: `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
+
+error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-53096.rs b/src/test/ui/type-alias-impl-trait/issue-53096.rs
index 564c5c3d33f85..bdf426bbd3788 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53096.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-53096.rs
@@ -1,5 +1,5 @@
 // check-pass
-#![feature(const_fn)]
+#![feature(const_fn, const_fn_fn_ptr_basics)]
 #![feature(type_alias_impl_trait)]
 
 type Foo = impl Fn() -> usize;
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 47315fa64cd80..f4f2259cefd51 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -357,7 +357,7 @@ pub fn main() {
                 args.extend(vec!["--sysroot".into(), sys_root]);
             };
 
-            return rustc_driver::run_compiler(&args, &mut DefaultCallbacks, None, None);
+            return rustc_driver::run_compiler(&args, &mut DefaultCallbacks, None, None, None);
         }
 
         if orig_args.iter().any(|a| a == "--version" || a == "-V") {
@@ -420,6 +420,6 @@ pub fn main() {
         let mut default = DefaultCallbacks;
         let callbacks: &mut (dyn rustc_driver::Callbacks + Send) =
             if clippy_enabled { &mut clippy } else { &mut default };
-        rustc_driver::run_compiler(&args, callbacks, None, None)
+        rustc_driver::run_compiler(&args, callbacks, None, None, None)
     }))
 }