diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 5c67d3b6431fd..3154f12a77964 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -13,8 +13,7 @@ use rustc_ast as ast;
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_hir::lang_items::LangItem;
 use rustc_index::vec::Idx;
-use rustc_middle::mir::AssertKind;
-use rustc_middle::mir::{self, SwitchTargets};
+use rustc_middle::mir::{self, AssertKind, SwitchTargets};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Instance, Ty, TypeVisitable};
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 9ea9fbe0e0e54..6e5c840bdfd6a 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -35,21 +35,7 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
         // All `#[rustc_do_not_const_check]` functions should be hooked here.
         let def_id = instance.def_id();
 
-        if Some(def_id) == self.tcx.lang_items().const_eval_select() {
-            // redirect to const_eval_select_ct
-            if let Some(const_eval_select) = self.tcx.lang_items().const_eval_select_ct() {
-                return Ok(Some(
-                    ty::Instance::resolve(
-                        *self.tcx,
-                        ty::ParamEnv::reveal_all(),
-                        const_eval_select,
-                        instance.substs,
-                    )
-                    .unwrap()
-                    .unwrap(),
-                ));
-            }
-        } else if Some(def_id) == self.tcx.lang_items().panic_display()
+        if Some(def_id) == self.tcx.lang_items().panic_display()
             || Some(def_id) == self.tcx.lang_items().begin_panic_fn()
         {
             // &str or &&str
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index f19d07d98dcb2..bc1ea1c4c736f 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -269,8 +269,6 @@ language_item_table! {
     DropInPlace,             sym::drop_in_place,       drop_in_place_fn,           Target::Fn,             GenericRequirement::Minimum(1);
     Oom,                     sym::oom,                 oom,                        Target::Fn,             GenericRequirement::None;
     AllocLayout,             sym::alloc_layout,        alloc_layout,               Target::Struct,         GenericRequirement::None;
-    ConstEvalSelect,         sym::const_eval_select,   const_eval_select,          Target::Fn,             GenericRequirement::Exact(4);
-    ConstConstEvalSelect,    sym::const_eval_select_ct,const_eval_select_ct,       Target::Fn,             GenericRequirement::Exact(4);
 
     Start,                   sym::start,               start_fn,                   Target::Fn,             GenericRequirement::Exact(1);
 
diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs
index 93707bb18ceec..a803fca0d5b89 100644
--- a/compiler/rustc_middle/src/ty/consts/valtree.rs
+++ b/compiler/rustc_middle/src/ty/consts/valtree.rs
@@ -18,7 +18,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 /// `ValTree` does not have this problem with representation, as it only contains integers or
 /// lists of (nested) `ValTree`.
 pub enum ValTree<'tcx> {
-    /// ZSTs, integers, `bool`, `char` are represented as scalars.
+    /// integers, `bool`, `char` are represented as scalars.
     /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values
     /// of these types have the same representation.
     Leaf(ScalarInt),
@@ -27,8 +27,11 @@ pub enum ValTree<'tcx> {
     // dont use SliceOrStr for now
     /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by
     /// listing their fields' values in order.
+    ///
     /// Enums are represented by storing their discriminant as a field, followed by all
     /// the fields of the variant.
+    ///
+    /// ZST types are represented as an empty slice.
     Branch(&'tcx [ValTree<'tcx>]),
 }
 
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 26b60e4f33988..2c587b76f025f 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -263,6 +263,7 @@ fn layout_of<'tcx>(
     Ok(layout)
 }
 
+#[derive(Clone, Copy)]
 pub struct LayoutCx<'tcx, C> {
     pub tcx: C,
     pub param_env: ty::ParamEnv<'tcx>,
@@ -3063,6 +3064,93 @@ fn fn_abi_of_instance<'tcx>(
     )
 }
 
+// Handle safe Rust thin and fat pointers.
+pub fn adjust_for_rust_scalar<'tcx>(
+    cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
+    attrs: &mut ArgAttributes,
+    scalar: Scalar,
+    layout: TyAndLayout<'tcx>,
+    offset: Size,
+    is_return: bool,
+) {
+    // Booleans are always a noundef i1 that needs to be zero-extended.
+    if scalar.is_bool() {
+        attrs.ext(ArgExtension::Zext);
+        attrs.set(ArgAttribute::NoUndef);
+        return;
+    }
+
+    // Scalars which have invalid values cannot be undef.
+    if !scalar.is_always_valid(&cx) {
+        attrs.set(ArgAttribute::NoUndef);
+    }
+
+    // Only pointer types handled below.
+    let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return };
+
+    if !valid_range.contains(0) {
+        attrs.set(ArgAttribute::NonNull);
+    }
+
+    if let Some(pointee) = layout.pointee_info_at(&cx, offset) {
+        if let Some(kind) = pointee.safe {
+            attrs.pointee_align = Some(pointee.align);
+
+            // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable
+            // for the entire duration of the function as they can be deallocated
+            // at any time. Same for shared mutable references. If LLVM had a
+            // way to say "dereferenceable on entry" we could use it here.
+            attrs.pointee_size = match kind {
+                PointerKind::UniqueBorrowed
+                | PointerKind::UniqueBorrowedPinned
+                | PointerKind::Frozen => pointee.size,
+                PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO,
+            };
+
+            // `Box`, `&T`, and `&mut T` cannot be undef.
+            // Note that this only applies to the value of the pointer itself;
+            // this attribute doesn't make it UB for the pointed-to data to be undef.
+            attrs.set(ArgAttribute::NoUndef);
+
+            // The aliasing rules for `Box<T>` are still not decided, but currently we emit
+            // `noalias` for it. This can be turned off using an unstable flag.
+            // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326
+            let noalias_for_box = cx.tcx.sess.opts.unstable_opts.box_noalias.unwrap_or(true);
+
+            // `&mut` pointer parameters never alias other parameters,
+            // or mutable global data
+            //
+            // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
+            // and can be marked as both `readonly` and `noalias`, as
+            // LLVM's definition of `noalias` is based solely on memory
+            // dependencies rather than pointer equality
+            //
+            // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute
+            // for UniqueBorrowed arguments, so that the codegen backend can decide whether
+            // or not to actually emit the attribute. It can also be controlled with the
+            // `-Zmutable-noalias` debugging option.
+            let no_alias = match kind {
+                PointerKind::SharedMutable
+                | PointerKind::UniqueBorrowed
+                | PointerKind::UniqueBorrowedPinned => false,
+                PointerKind::UniqueOwned => noalias_for_box,
+                PointerKind::Frozen => !is_return,
+            };
+            if no_alias {
+                attrs.set(ArgAttribute::NoAlias);
+            }
+
+            if kind == PointerKind::Frozen && !is_return {
+                attrs.set(ArgAttribute::ReadOnly);
+            }
+
+            if kind == PointerKind::UniqueBorrowed && !is_return {
+                attrs.set(ArgAttribute::NoAliasMutRef);
+            }
+        }
+    }
+}
+
 impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
     // FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
     // arguments of this method, into a separate `struct`.
@@ -3118,91 +3206,6 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
         use SpecAbi::*;
         let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
 
-        // Handle safe Rust thin and fat pointers.
-        let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,
-                                      scalar: Scalar,
-                                      layout: TyAndLayout<'tcx>,
-                                      offset: Size,
-                                      is_return: bool| {
-            // Booleans are always a noundef i1 that needs to be zero-extended.
-            if scalar.is_bool() {
-                attrs.ext(ArgExtension::Zext);
-                attrs.set(ArgAttribute::NoUndef);
-                return;
-            }
-
-            // Scalars which have invalid values cannot be undef.
-            if !scalar.is_always_valid(self) {
-                attrs.set(ArgAttribute::NoUndef);
-            }
-
-            // Only pointer types handled below.
-            let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return };
-
-            if !valid_range.contains(0) {
-                attrs.set(ArgAttribute::NonNull);
-            }
-
-            if let Some(pointee) = layout.pointee_info_at(self, offset) {
-                if let Some(kind) = pointee.safe {
-                    attrs.pointee_align = Some(pointee.align);
-
-                    // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable
-                    // for the entire duration of the function as they can be deallocated
-                    // at any time. Same for shared mutable references. If LLVM had a
-                    // way to say "dereferenceable on entry" we could use it here.
-                    attrs.pointee_size = match kind {
-                        PointerKind::UniqueBorrowed
-                        | PointerKind::UniqueBorrowedPinned
-                        | PointerKind::Frozen => pointee.size,
-                        PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO,
-                    };
-
-                    // `Box`, `&T`, and `&mut T` cannot be undef.
-                    // Note that this only applies to the value of the pointer itself;
-                    // this attribute doesn't make it UB for the pointed-to data to be undef.
-                    attrs.set(ArgAttribute::NoUndef);
-
-                    // The aliasing rules for `Box<T>` are still not decided, but currently we emit
-                    // `noalias` for it. This can be turned off using an unstable flag.
-                    // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326
-                    let noalias_for_box =
-                        self.tcx().sess.opts.unstable_opts.box_noalias.unwrap_or(true);
-
-                    // `&mut` pointer parameters never alias other parameters,
-                    // or mutable global data
-                    //
-                    // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
-                    // and can be marked as both `readonly` and `noalias`, as
-                    // LLVM's definition of `noalias` is based solely on memory
-                    // dependencies rather than pointer equality
-                    //
-                    // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute
-                    // for UniqueBorrowed arguments, so that the codegen backend can decide whether
-                    // or not to actually emit the attribute. It can also be controlled with the
-                    // `-Zmutable-noalias` debugging option.
-                    let no_alias = match kind {
-                        PointerKind::SharedMutable
-                        | PointerKind::UniqueBorrowed
-                        | PointerKind::UniqueBorrowedPinned => false,
-                        PointerKind::UniqueOwned => noalias_for_box,
-                        PointerKind::Frozen => !is_return,
-                    };
-                    if no_alias {
-                        attrs.set(ArgAttribute::NoAlias);
-                    }
-
-                    if kind == PointerKind::Frozen && !is_return {
-                        attrs.set(ArgAttribute::ReadOnly);
-                    }
-
-                    if kind == PointerKind::UniqueBorrowed && !is_return {
-                        attrs.set(ArgAttribute::NoAliasMutRef);
-                    }
-                }
-            }
-        };
-
         let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, FnAbiError<'tcx>> {
             let is_return = arg_idx.is_none();
 
@@ -3218,7 +3221,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
             let mut arg = ArgAbi::new(self, layout, |layout, scalar, offset| {
                 let mut attrs = ArgAttributes::new();
-                adjust_for_rust_scalar(&mut attrs, scalar, *layout, offset, is_return);
+                adjust_for_rust_scalar(*self, &mut attrs, scalar, *layout, offset, is_return);
                 attrs
             });
 
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 0b674b38f3282..162f7d969b181 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -10,6 +10,7 @@
 #![feature(trusted_step)]
 #![feature(try_blocks)]
 #![feature(yeet_expr)]
+#![feature(if_let_guard)]
 #![recursion_limit = "256"]
 
 #[macro_use]
@@ -27,10 +28,13 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::visit::Visitor as _;
 use rustc_middle::mir::{
-    traversal, AnalysisPhase, Body, ConstQualifs, MirPass, MirPhase, Promoted, RuntimePhase,
+    traversal, AnalysisPhase, Body, ConstQualifs, Constant, LocalDecl, MirPass, MirPhase, Operand,
+    Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, Statement, StatementKind,
+    TerminatorKind,
 };
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
+use rustc_span::sym;
 
 #[macro_use]
 mod pass_manager;
@@ -140,6 +144,64 @@ pub fn provide(providers: &mut Providers) {
     };
 }
 
+fn remap_mir_for_const_eval_select<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    mut body: Body<'tcx>,
+    context: hir::Constness,
+) -> Body<'tcx> {
+    for bb in body.basic_blocks.as_mut().iter_mut() {
+        let terminator = bb.terminator.as_mut().expect("invalid terminator");
+        match terminator.kind {
+            TerminatorKind::Call {
+                func: Operand::Constant(box Constant { ref literal, .. }),
+                ref mut args,
+                destination,
+                target,
+                cleanup,
+                fn_span,
+                ..
+            } if let ty::FnDef(def_id, _) = *literal.ty().kind()
+                && tcx.item_name(def_id) == sym::const_eval_select
+                && tcx.is_intrinsic(def_id) =>
+            {
+                let [tupled_args, called_in_const, called_at_rt]: [_; 3] = std::mem::take(args).try_into().unwrap();
+                let ty = tupled_args.ty(&body.local_decls, tcx);
+                let fields = ty.tuple_fields();
+                let num_args = fields.len();
+                let func = if context == hir::Constness::Const { called_in_const } else { called_at_rt };
+                let (method, place): (fn(Place<'tcx>) -> Operand<'tcx>, Place<'tcx>) = match tupled_args {
+                    Operand::Constant(_) => {
+                        // there is no good way of extracting a tuple arg from a constant (const generic stuff)
+                        // so we just create a temporary and deconstruct that.
+                        let local = body.local_decls.push(LocalDecl::new(ty, fn_span));
+                        bb.statements.push(Statement {
+                            source_info: SourceInfo::outermost(fn_span),
+                            kind: StatementKind::Assign(Box::new((local.into(), Rvalue::Use(tupled_args.clone())))),
+                        });
+                        (Operand::Move, local.into())
+                    }
+                    Operand::Move(place) => (Operand::Move, place),
+                    Operand::Copy(place) => (Operand::Copy, place),
+                };
+                let place_elems = place.projection;
+                let arguments = (0..num_args).map(|x| {
+                    let mut place_elems = place_elems.to_vec();
+                    place_elems.push(ProjectionElem::Field(x.into(), fields[x]));
+                    let projection = tcx.intern_place_elems(&place_elems);
+                    let place = Place {
+                        local: place.local,
+                        projection,
+                    };
+                    method(place)
+                }).collect();
+                terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, cleanup, from_hir_call: false, fn_span };
+            }
+            _ => {}
+        }
+    }
+    body
+}
+
 fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     let def_id = def_id.expect_local();
     tcx.mir_keys(()).contains(&def_id)
@@ -325,7 +387,9 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
         .body_const_context(def.did)
         .expect("mir_for_ctfe should not be used for runtime functions");
 
-    let mut body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone();
+    let body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone();
+
+    let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const);
 
     match context {
         // Do not const prop functions, either they get executed at runtime or exported to metadata,
@@ -558,8 +622,9 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
         Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other),
     }
     debug!("about to call mir_drops_elaborated...");
-    let mut body =
+    let body =
         tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal();
+    let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::NotConst);
     debug!("body: {:#?}", body);
     run_optimization_passes(tcx, &mut body);
 
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 4e37da0dedb15..be74a9d11e3c5 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -112,12 +112,6 @@
 //! method in operand position, we treat it as a neighbor of the current
 //! mono item. Calls are just a special case of that.
 //!
-//! #### Closures
-//! In a way, closures are a simple case. Since every closure object needs to be
-//! constructed somewhere, we can reliably discover them by observing
-//! `RValue::Aggregate` expressions with `AggregateKind::Closure`. This is also
-//! true for closures inlined from other crates.
-//!
 //! #### Drop glue
 //! Drop glue mono items are introduced by MIR drop-statements. The
 //! generated mono item will again have drop-glue item neighbors if the
@@ -835,7 +829,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
             mir::TerminatorKind::Call { ref func, .. } => {
                 let callee_ty = func.ty(self.body, tcx);
                 let callee_ty = self.monomorphize(callee_ty);
-                visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output);
+                visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output)
             }
             mir::TerminatorKind::Drop { ref place, .. }
             | mir::TerminatorKind::DropAndReplace { ref place, .. } => {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index c501fba21c60f..f6ce7675c8fae 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -510,7 +510,6 @@ symbols! {
         const_deallocate,
         const_eval_limit,
         const_eval_select,
-        const_eval_select_ct,
         const_evaluatable_checked,
         const_extern_fn,
         const_fn,
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index ce0e59d062266..d1d27db9131fd 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -31,7 +31,7 @@ use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty, TypeSuperVisitable, TypeVisitor};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
-use rustc_span::{self, Span};
+use rustc_span::{self, sym, Span};
 use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
 
 use std::iter;
@@ -224,6 +224,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let minimum_input_count = expected_input_tys.len();
         let provided_arg_count = provided_args.len();
 
+        let is_const_eval_select = matches!(fn_def_id, Some(def_id) if
+            self.tcx.def_kind(def_id) == hir::def::DefKind::Fn
+            && self.tcx.is_intrinsic(def_id)
+            && self.tcx.item_name(def_id) == sym::const_eval_select);
+
         // We introduce a helper function to demand that a given argument satisfy a given input
         // This is more complicated than just checking type equality, as arguments could be coerced
         // This version writes those types back so further type checking uses the narrowed types
@@ -259,6 +264,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return Compatibility::Incompatible(coerce_error);
             }
 
+            // Check that second and third argument of `const_eval_select` must be `FnDef`, and additionally that
+            // the second argument must be `const fn`. The first argument must be a tuple, but this is already expressed
+            // in the function signature (`F: FnOnce<ARG>`), so I did not bother to add another check here.
+            //
+            // This check is here because there is currently no way to express a trait bound for `FnDef` types only.
+            if is_const_eval_select && (1..=2).contains(&idx) {
+                if let ty::FnDef(def_id, _) = checked_ty.kind() {
+                    if idx == 1 && !self.tcx.is_const_fn_raw(*def_id) {
+                        self.tcx
+                            .sess
+                            .struct_span_err(provided_arg.span, "this argument must be a `const fn`")
+                            .help("consult the documentation on `const_eval_select` for more information")
+                            .emit();
+                    }
+                } else {
+                    self.tcx
+                        .sess
+                        .struct_span_err(provided_arg.span, "this argument must be a function item")
+                        .note(format!("expected a function item, found {checked_ty}"))
+                        .help(
+                            "consult the documentation on `const_eval_select` for more information",
+                        )
+                        .emit();
+                }
+            }
+
             // 3. Check if the formal type is a supertype of the checked one
             //    and register any such obligations for future type checks
             let supertype_error = self
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index d610f0a02f403..56f5824efd4ca 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -54,7 +54,9 @@
 )]
 #![allow(missing_docs)]
 
-use crate::marker::{Destruct, DiscriminantKind};
+#[cfg(bootstrap)]
+use crate::marker::Destruct;
+use crate::marker::DiscriminantKind;
 use crate::mem;
 
 // These imports are used for simplifying intra-doc links
@@ -2085,6 +2087,65 @@ extern "rust-intrinsic" {
     /// `ptr` must point to a vtable.
     /// The intrinsic will return the alignment stored in that vtable.
     pub fn vtable_align(ptr: *const ()) -> usize;
+
+    /// Selects which function to call depending on the context.
+    ///
+    /// If this function is evaluated at compile-time, then a call to this
+    /// intrinsic will be replaced with a call to `called_in_const`. It gets
+    /// replaced with a call to `called_at_rt` otherwise.
+    ///
+    /// # Type Requirements
+    ///
+    /// The two functions must be both function items. They cannot be function
+    /// pointers or closures. The first function must be a `const fn`.
+    ///
+    /// `arg` will be the tupled arguments that will be passed to either one of
+    /// the two functions, therefore, both functions must accept the same type of
+    /// arguments. Both functions must return RET.
+    ///
+    /// # Safety
+    ///
+    /// The two functions must behave observably equivalent. Safe code in other
+    /// crates may assume that calling a `const fn` at compile-time and at run-time
+    /// produces the same result. A function that produces a different result when
+    /// evaluated at run-time, or has any other observable side-effects, is
+    /// *unsound*.
+    ///
+    /// Here is an example of how this could cause a problem:
+    /// ```no_run
+    /// #![feature(const_eval_select)]
+    /// #![feature(core_intrinsics)]
+    /// use std::hint::unreachable_unchecked;
+    /// use std::intrinsics::const_eval_select;
+    ///
+    /// // Crate A
+    /// pub const fn inconsistent() -> i32 {
+    ///     fn runtime() -> i32 { 1 }
+    ///     const fn compiletime() -> i32 { 2 }
+    ///
+    ///     unsafe {
+    //          // ⚠ This code violates the required equivalence of `compiletime`
+    ///         // and `runtime`.
+    ///         const_eval_select((), compiletime, runtime)
+    ///     }
+    /// }
+    ///
+    /// // Crate B
+    /// const X: i32 = inconsistent();
+    /// let x = inconsistent();
+    /// if x != X { unsafe { unreachable_unchecked(); }}
+    /// ```
+    ///
+    /// This code causes Undefined Behavior when being run, since the
+    /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
+    /// which violates the principle that a `const fn` must behave the same at
+    /// compile-time and at run-time. The unsafe code in crate B is fine.
+    #[cfg(not(bootstrap))]
+    #[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
+    pub fn const_eval_select<ARG, F, G, RET>(arg: ARG, called_in_const: F, called_at_rt: G) -> RET
+    where
+        G: FnOnce<ARG, Output = RET>,
+        F: FnOnce<ARG, Output = RET>;
 }
 
 // Some functions are defined here because they accidentally got made
@@ -2095,6 +2156,11 @@ extern "rust-intrinsic" {
 /// Check that the preconditions of an unsafe function are followed, if debug_assertions are on,
 /// and only at runtime.
 ///
+/// This macro should be called as `assert_unsafe_precondition!([Generics](name: Type) => Expression)`
+/// where the names specified will be moved into the macro as captured variables, and defines an item
+/// to call `const_eval_select` on. The tokens inside the square brackets are used to denote generics
+/// for the function declaractions and can be omitted if there is no generics.
+///
 /// # Safety
 ///
 /// Invoking this macro is only sound if the following code is already UB when the passed
@@ -2109,18 +2175,21 @@ extern "rust-intrinsic" {
 /// the occasional mistake, and this check should help them figure things out.
 #[allow_internal_unstable(const_eval_select)] // permit this to be called in stably-const fn
 macro_rules! assert_unsafe_precondition {
-    ($e:expr) => {
+    ($([$($tt:tt)*])?($($i:ident:$ty:ty),*$(,)?) => $e:expr) => {
         if cfg!(debug_assertions) {
-            // Use a closure so that we can capture arbitrary expressions from the invocation
-            let runtime = || {
+            // allow non_snake_case to allow capturing const generics
+            #[allow(non_snake_case)]
+            #[inline(always)]
+            fn runtime$(<$($tt)*>)?($($i:$ty),*) {
                 if !$e {
                     // abort instead of panicking to reduce impact on code size
                     ::core::intrinsics::abort();
                 }
-            };
-            const fn comptime() {}
+            }
+            #[allow(non_snake_case)]
+            const fn comptime$(<$($tt)*>)?($(_:$ty),*) {}
 
-            ::core::intrinsics::const_eval_select((), comptime, runtime);
+            ::core::intrinsics::const_eval_select(($($i,)*), comptime, runtime);
         }
     };
 }
@@ -2243,7 +2312,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
     // SAFETY: the safety contract for `copy_nonoverlapping` must be
     // upheld by the caller.
     unsafe {
-        assert_unsafe_precondition!(
+        assert_unsafe_precondition!([T](src: *const T, dst: *mut T, count: usize) =>
             is_aligned_and_not_null(src)
                 && is_aligned_and_not_null(dst)
                 && is_nonoverlapping(src, dst, count)
@@ -2329,7 +2398,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
 
     // SAFETY: the safety contract for `copy` must be upheld by the caller.
     unsafe {
-        assert_unsafe_precondition!(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst));
+        assert_unsafe_precondition!([T](src: *const T, dst: *mut T) =>
+            is_aligned_and_not_null(src) && is_aligned_and_not_null(dst));
         copy(src, dst, count)
     }
 }
@@ -2397,63 +2467,12 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
 
     // SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
     unsafe {
-        assert_unsafe_precondition!(is_aligned_and_not_null(dst));
+        assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst));
         write_bytes(dst, val, count)
     }
 }
 
-/// Selects which function to call depending on the context.
-///
-/// If this function is evaluated at compile-time, then a call to this
-/// intrinsic will be replaced with a call to `called_in_const`. It gets
-/// replaced with a call to `called_at_rt` otherwise.
-///
-/// # Type Requirements
-///
-/// The two functions must be both function items. They cannot be function
-/// pointers or closures.
-///
-/// `arg` will be the arguments that will be passed to either one of the
-/// two functions, therefore, both functions must accept the same type of
-/// arguments. Both functions must return RET.
-///
-/// # Safety
-///
-/// The two functions must behave observably equivalent. Safe code in other
-/// crates may assume that calling a `const fn` at compile-time and at run-time
-/// produces the same result. A function that produces a different result when
-/// evaluated at run-time, or has any other observable side-effects, is
-/// *unsound*.
-///
-/// Here is an example of how this could cause a problem:
-/// ```no_run
-/// #![feature(const_eval_select)]
-/// #![feature(core_intrinsics)]
-/// use std::hint::unreachable_unchecked;
-/// use std::intrinsics::const_eval_select;
-///
-/// // Crate A
-/// pub const fn inconsistent() -> i32 {
-///     fn runtime() -> i32 { 1 }
-///     const fn compiletime() -> i32 { 2 }
-///
-///     unsafe {
-//          // ⚠ This code violates the required equivalence of `compiletime`
-///         // and `runtime`.
-///         const_eval_select((), compiletime, runtime)
-///     }
-/// }
-///
-/// // Crate B
-/// const X: i32 = inconsistent();
-/// let x = inconsistent();
-/// if x != X { unsafe { unreachable_unchecked(); }}
-/// ```
-///
-/// This code causes Undefined Behavior when being run, since the
-/// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
-/// which violates the principle that a `const fn` must behave the same at
-/// compile-time and at run-time. The unsafe code in crate B is fine.
+#[cfg(bootstrap)]
 #[unstable(
     feature = "const_eval_select",
     issue = "none",
@@ -2475,6 +2494,7 @@ where
     called_at_rt.call_once(arg)
 }
 
+#[cfg(bootstrap)]
 #[unstable(
     feature = "const_eval_select",
     issue = "none",
diff --git a/library/core/src/mem/valid_align.rs b/library/core/src/mem/valid_align.rs
index b9ccc0b4c799f..32b2afb72b0dc 100644
--- a/library/core/src/mem/valid_align.rs
+++ b/library/core/src/mem/valid_align.rs
@@ -28,7 +28,7 @@ impl ValidAlign {
     #[inline]
     pub(crate) const unsafe fn new_unchecked(align: usize) -> Self {
         // SAFETY: Precondition passed to the caller.
-        unsafe { assert_unsafe_precondition!(align.is_power_of_two()) };
+        unsafe { assert_unsafe_precondition!((align: usize) => align.is_power_of_two()) };
 
         // SAFETY: By precondition, this must be a power of two, and
         // our variants encompass all possible powers of two.
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index da41ea536357a..c83b928efc18d 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -1033,10 +1033,14 @@ impl f32 {
                 }
             }
         }
-        // SAFETY: `u32` is a plain old datatype so we can always... uh...
-        // ...look, just pretend you forgot what you just read.
-        // Stability concerns.
-        let rt_f32_to_u32 = |rt| unsafe { mem::transmute::<f32, u32>(rt) };
+
+        #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
+        fn rt_f32_to_u32(x: f32) -> u32 {
+            // SAFETY: `u32` is a plain old datatype so we can always... uh...
+            // ...look, just pretend you forgot what you just read.
+            // Stability concerns.
+            unsafe { mem::transmute(x) }
+        }
         // SAFETY: We use internal implementations that either always work or fail at compile time.
         unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
     }
@@ -1121,10 +1125,14 @@ impl f32 {
                 }
             }
         }
-        // SAFETY: `u32` is a plain old datatype so we can always... uh...
-        // ...look, just pretend you forgot what you just read.
-        // Stability concerns.
-        let rt_u32_to_f32 = |rt| unsafe { mem::transmute::<u32, f32>(rt) };
+
+        #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
+        fn rt_u32_to_f32(x: u32) -> f32 {
+            // SAFETY: `u32` is a plain old datatype so we can always... uh...
+            // ...look, just pretend you forgot what you just read.
+            // Stability concerns.
+            unsafe { mem::transmute(x) }
+        }
         // SAFETY: We use internal implementations that either always work or fail at compile time.
         unsafe { intrinsics::const_eval_select((v,), ct_u32_to_f32, rt_u32_to_f32) }
     }
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 631d559df5f70..28d23f733debd 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -1026,10 +1026,14 @@ impl f64 {
                 }
             }
         }
-        // SAFETY: `u64` is a plain old datatype so we can always... uh...
-        // ...look, just pretend you forgot what you just read.
-        // Stability concerns.
-        let rt_f64_to_u64 = |rt| unsafe { mem::transmute::<f64, u64>(rt) };
+
+        #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
+        fn rt_f64_to_u64(rt: f64) -> u64 {
+            // SAFETY: `u64` is a plain old datatype so we can always... uh...
+            // ...look, just pretend you forgot what you just read.
+            // Stability concerns.
+            unsafe { mem::transmute::<f64, u64>(rt) }
+        }
         // SAFETY: We use internal implementations that either always work or fail at compile time.
         unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
     }
@@ -1119,10 +1123,14 @@ impl f64 {
                 }
             }
         }
-        // SAFETY: `u64` is a plain old datatype so we can always... uh...
-        // ...look, just pretend you forgot what you just read.
-        // Stability concerns.
-        let rt_u64_to_f64 = |rt| unsafe { mem::transmute::<u64, f64>(rt) };
+
+        #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
+        fn rt_u64_to_f64(rt: u64) -> f64 {
+            // SAFETY: `u64` is a plain old datatype so we can always... uh...
+            // ...look, just pretend you forgot what you just read.
+            // Stability concerns.
+            unsafe { mem::transmute::<u64, f64>(rt) }
+        }
         // SAFETY: We use internal implementations that either always work or fail at compile time.
         unsafe { intrinsics::const_eval_select((v,), ct_u64_to_f64, rt_u64_to_f64) }
     }
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 1cf306f2103b4..532a09736a7ac 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -56,7 +56,7 @@ macro_rules! nonzero_integers {
                 pub const unsafe fn new_unchecked(n: $Int) -> Self {
                     // SAFETY: this is guaranteed to be safe by the caller.
                     unsafe {
-                        core::intrinsics::assert_unsafe_precondition!(n != 0);
+                        core::intrinsics::assert_unsafe_precondition!((n: $Int) => n != 0);
                         Self(n)
                     }
                 }
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index f5c72d7975534..80bff74f3e9f4 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -755,9 +755,12 @@ impl<T: ?Sized> *const T {
     where
         T: Sized,
     {
+        let this = self;
         // SAFETY: The comparison has no side-effects, and the intrinsic
         // does this check internally in the CTFE implementation.
-        unsafe { assert_unsafe_precondition!(self >= origin) };
+        unsafe {
+            assert_unsafe_precondition!([T](this: *const T, origin: *const T) => this >= origin)
+        };
 
         let pointee_size = mem::size_of::<T>();
         assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 41a2685d361c8..e976abed774b8 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -886,7 +886,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
     // SAFETY: the caller must guarantee that `x` and `y` are
     // valid for writes and properly aligned.
     unsafe {
-        assert_unsafe_precondition!(
+        assert_unsafe_precondition!([T](x: *mut T, y: *mut T, count: usize) =>
             is_aligned_and_not_null(x)
                 && is_aligned_and_not_null(y)
                 && is_nonoverlapping(x, y, count)
@@ -983,7 +983,7 @@ pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
     // and cannot overlap `src` since `dst` must point to a distinct
     // allocated object.
     unsafe {
-        assert_unsafe_precondition!(is_aligned_and_not_null(dst));
+        assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst));
         mem::swap(&mut *dst, &mut src); // cannot overlap
     }
     src
@@ -1470,7 +1470,7 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
 pub unsafe fn read_volatile<T>(src: *const T) -> T {
     // SAFETY: the caller must uphold the safety contract for `volatile_load`.
     unsafe {
-        assert_unsafe_precondition!(is_aligned_and_not_null(src));
+        assert_unsafe_precondition!([T](src: *const T) => is_aligned_and_not_null(src));
         intrinsics::volatile_load(src)
     }
 }
@@ -1541,7 +1541,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
     // SAFETY: the caller must uphold the safety contract for `volatile_store`.
     unsafe {
-        assert_unsafe_precondition!(is_aligned_and_not_null(dst));
+        assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst));
         intrinsics::volatile_store(dst, src);
     }
 }
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index fd7ecf3daf316..3403a5a86f7cb 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -48,10 +48,12 @@ const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
 }
 
 // FIXME const-hack
+#[track_caller]
 fn slice_start_index_len_fail_rt(index: usize, len: usize) -> ! {
     panic!("range start index {index} out of range for slice of length {len}");
 }
 
+#[track_caller]
 const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! {
     panic!("slice start index is out of range for slice");
 }
@@ -69,10 +71,12 @@ const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
 }
 
 // FIXME const-hack
+#[track_caller]
 fn slice_end_index_len_fail_rt(index: usize, len: usize) -> ! {
     panic!("range end index {index} out of range for slice of length {len}");
 }
 
+#[track_caller]
 const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! {
     panic!("slice end index is out of range for slice");
 }
@@ -88,10 +92,12 @@ const fn slice_index_order_fail(index: usize, end: usize) -> ! {
 }
 
 // FIXME const-hack
+#[track_caller]
 fn slice_index_order_fail_rt(index: usize, end: usize) -> ! {
     panic!("slice index starts at {index} but ends at {end}");
 }
 
+#[track_caller]
 const fn slice_index_order_fail_ct(_: usize, _: usize) -> ! {
     panic!("slice index start is larger than end");
 }
@@ -217,21 +223,23 @@ unsafe impl<T> const SliceIndex<[T]> for usize {
 
     #[inline]
     unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
+        let this = self;
         // SAFETY: the caller guarantees that `slice` is not dangling, so it
         // cannot be longer than `isize::MAX`. They also guarantee that
         // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
         // so the call to `add` is safe.
         unsafe {
-            assert_unsafe_precondition!(self < slice.len());
+            assert_unsafe_precondition!([T](this: usize, slice: *const [T]) => this < slice.len());
             slice.as_ptr().add(self)
         }
     }
 
     #[inline]
     unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T {
+        let this = self;
         // SAFETY: see comments for `get_unchecked` above.
         unsafe {
-            assert_unsafe_precondition!(self < slice.len());
+            assert_unsafe_precondition!([T](this: usize, slice: *mut [T]) => this < slice.len());
             slice.as_mut_ptr().add(self)
         }
     }
@@ -276,22 +284,26 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
 
     #[inline]
     unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+        let this = ops::Range { start: self.start, end: self.end };
         // SAFETY: the caller guarantees that `slice` is not dangling, so it
         // cannot be longer than `isize::MAX`. They also guarantee that
         // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
         // so the call to `add` is safe.
 
         unsafe {
-            assert_unsafe_precondition!(self.end >= self.start && self.end <= slice.len());
+            assert_unsafe_precondition!([T](this: ops::Range<usize>, slice: *const [T]) =>
+            this.end >= this.start && this.end <= slice.len());
             ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start)
         }
     }
 
     #[inline]
     unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+        let this = ops::Range { start: self.start, end: self.end };
         // SAFETY: see comments for `get_unchecked` above.
         unsafe {
-            assert_unsafe_precondition!(self.end >= self.start && self.end <= slice.len());
+            assert_unsafe_precondition!([T](this: ops::Range<usize>, slice: *mut [T]) =>
+                this.end >= this.start && this.end <= slice.len());
             ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start)
         }
     }
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 1958745b5868c..6a7150d2986ed 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -656,10 +656,11 @@ impl<T> [T] {
     #[unstable(feature = "slice_swap_unchecked", issue = "88539")]
     #[rustc_const_unstable(feature = "const_swap", issue = "83163")]
     pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) {
-        let ptr = self.as_mut_ptr();
+        let this = self;
+        let ptr = this.as_mut_ptr();
         // SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()`
         unsafe {
-            assert_unsafe_precondition!(a < self.len() && b < self.len());
+            assert_unsafe_precondition!([T](a: usize, b: usize, this: &mut [T]) => a < this.len() && b < this.len());
             ptr::swap(ptr.add(a), ptr.add(b));
         }
     }
@@ -972,9 +973,10 @@ impl<T> [T] {
     #[inline]
     #[must_use]
     pub unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] {
+        let this = self;
         // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
         let new_len = unsafe {
-            assert_unsafe_precondition!(N != 0 && self.len() % N == 0);
+            assert_unsafe_precondition!([T](this: &[T], N: usize) => N != 0 && this.len() % N == 0);
             exact_div(self.len(), N)
         };
         // SAFETY: We cast a slice of `new_len * N` elements into
@@ -1111,10 +1113,11 @@ impl<T> [T] {
     #[inline]
     #[must_use]
     pub unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] {
+        let this = &*self;
         // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
         let new_len = unsafe {
-            assert_unsafe_precondition!(N != 0 && self.len() % N == 0);
-            exact_div(self.len(), N)
+            assert_unsafe_precondition!([T](this: &[T], N: usize) => N != 0 && this.len() % N == 0);
+            exact_div(this.len(), N)
         };
         // SAFETY: We cast a slice of `new_len * N` elements into
         // a slice of `new_len` many `N` elements chunks.
@@ -1687,7 +1690,7 @@ impl<T> [T] {
         // `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference
         // is fine.
         unsafe {
-            assert_unsafe_precondition!(mid <= len);
+            assert_unsafe_precondition!((mid: usize, len: usize) => mid <= len);
             (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid))
         }
     }
diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs
index 107e71ab68b01..f1e8bc79bf4a2 100644
--- a/library/core/src/slice/raw.rs
+++ b/library/core/src/slice/raw.rs
@@ -90,7 +90,7 @@ use crate::ptr;
 pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
     // SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
     unsafe {
-        assert_unsafe_precondition!(
+        assert_unsafe_precondition!([T](data: *const T, len: usize) =>
             is_aligned_and_not_null(data)
                 && crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize
         );
@@ -134,7 +134,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
 pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
     // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
     unsafe {
-        assert_unsafe_precondition!(
+        assert_unsafe_precondition!([T](data: *mut T, len: usize) =>
             is_aligned_and_not_null(data)
                 && crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize
         );
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 2120bf61d759d..f673aa2a44b10 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -91,10 +91,12 @@ const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
     }
 }
 
+#[track_caller]
 const fn slice_error_fail_ct(_: &str, _: usize, _: usize) -> ! {
     panic!("failed to slice string");
 }
 
+#[track_caller]
 fn slice_error_fail_rt(s: &str, begin: usize, end: usize) -> ! {
     const MAX_DISPLAY_LENGTH: usize = 256;
     let trunc_len = s.floor_char_boundary(MAX_DISPLAY_LENGTH);
diff --git a/src/test/ui/consts/const-float-bits-reject-conv.stderr b/src/test/ui/consts/const-float-bits-reject-conv.stderr
index d6e993a10101d..01f2f48956458 100644
--- a/src/test/ui/consts/const-float-bits-reject-conv.stderr
+++ b/src/test/ui/consts/const-float-bits-reject-conv.stderr
@@ -10,16 +10,6 @@ LL |                     panic!("const-eval error: cannot use f32::to_bits on a
 LL |         unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
    |                  -------------------------------------------------------------------- inside `core::f32::<impl f32>::to_bits` at $SRC_DIR/core/src/num/f32.rs:LL:COL
    |
-  ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
-   |
-LL |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
-   |     ------------------------------------------------------------------ inside `<fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32} as FnOnce<(f32,)>>::call_once - shim(fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32})` at $SRC_DIR/core/src/ops/function.rs:LL:COL
-   |
-  ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL
-   |
-LL |     called_in_const.call_once(arg)
-   |     ------------------------------ inside `const_eval_select::<(f32,), fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32}, [closure@core::f32::<impl f32>::to_bits::{closure#0}], u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
-   |
   ::: $DIR/const-float-bits-reject-conv.rs:27:30
    |
 LL |     const MASKED_NAN1: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA;
@@ -39,16 +29,6 @@ LL |                     panic!("const-eval error: cannot use f32::to_bits on a
 LL |         unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
    |                  -------------------------------------------------------------------- inside `core::f32::<impl f32>::to_bits` at $SRC_DIR/core/src/num/f32.rs:LL:COL
    |
-  ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
-   |
-LL |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
-   |     ------------------------------------------------------------------ inside `<fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32} as FnOnce<(f32,)>>::call_once - shim(fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32})` at $SRC_DIR/core/src/ops/function.rs:LL:COL
-   |
-  ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL
-   |
-LL |     called_in_const.call_once(arg)
-   |     ------------------------------ inside `const_eval_select::<(f32,), fn(f32) -> u32 {core::f32::<impl f32>::to_bits::ct_f32_to_u32}, [closure@core::f32::<impl f32>::to_bits::{closure#0}], u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
-   |
   ::: $DIR/const-float-bits-reject-conv.rs:28:30
    |
 LL |     const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555;
@@ -117,16 +97,6 @@ LL |                     panic!("const-eval error: cannot use f64::to_bits on a
 LL |         unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
    |                  -------------------------------------------------------------------- inside `core::f64::<impl f64>::to_bits` at $SRC_DIR/core/src/num/f64.rs:LL:COL
    |
-  ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
-   |
-LL |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
-   |     ------------------------------------------------------------------ inside `<fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64} as FnOnce<(f64,)>>::call_once - shim(fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64})` at $SRC_DIR/core/src/ops/function.rs:LL:COL
-   |
-  ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL
-   |
-LL |     called_in_const.call_once(arg)
-   |     ------------------------------ inside `const_eval_select::<(f64,), fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64}, [closure@core::f64::<impl f64>::to_bits::{closure#0}], u64>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
-   |
   ::: $DIR/const-float-bits-reject-conv.rs:54:30
    |
 LL |     const MASKED_NAN1: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
@@ -146,16 +116,6 @@ LL |                     panic!("const-eval error: cannot use f64::to_bits on a
 LL |         unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
    |                  -------------------------------------------------------------------- inside `core::f64::<impl f64>::to_bits` at $SRC_DIR/core/src/num/f64.rs:LL:COL
    |
-  ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
-   |
-LL |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
-   |     ------------------------------------------------------------------ inside `<fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64} as FnOnce<(f64,)>>::call_once - shim(fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64})` at $SRC_DIR/core/src/ops/function.rs:LL:COL
-   |
-  ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL
-   |
-LL |     called_in_const.call_once(arg)
-   |     ------------------------------ inside `const_eval_select::<(f64,), fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64}, [closure@core::f64::<impl f64>::to_bits::{closure#0}], u64>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
-   |
   ::: $DIR/const-float-bits-reject-conv.rs:55:30
    |
 LL |     const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
diff --git a/src/test/ui/intrinsics/const-eval-select-backtrace-std.rs b/src/test/ui/intrinsics/const-eval-select-backtrace-std.rs
new file mode 100644
index 0000000000000..29aefe07162b3
--- /dev/null
+++ b/src/test/ui/intrinsics/const-eval-select-backtrace-std.rs
@@ -0,0 +1,6 @@
+// See issue #100696.
+// run-fail
+// check-run-results
+fn main() {
+    &""[1..];
+}
diff --git a/src/test/ui/intrinsics/const-eval-select-backtrace-std.run.stderr b/src/test/ui/intrinsics/const-eval-select-backtrace-std.run.stderr
new file mode 100644
index 0000000000000..e53e6034620ca
--- /dev/null
+++ b/src/test/ui/intrinsics/const-eval-select-backtrace-std.run.stderr
@@ -0,0 +1,2 @@
+thread 'main' panicked at 'byte index 1 is out of bounds of ``', $DIR/const-eval-select-backtrace-std.rs:5:6
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/test/ui/intrinsics/const-eval-select-backtrace.rs b/src/test/ui/intrinsics/const-eval-select-backtrace.rs
new file mode 100644
index 0000000000000..99f0725200c1d
--- /dev/null
+++ b/src/test/ui/intrinsics/const-eval-select-backtrace.rs
@@ -0,0 +1,18 @@
+#![feature(core_intrinsics)]
+// See issue #100696.
+// run-fail
+// check-run-results
+
+#[track_caller]
+fn uhoh() {
+    panic!("Aaah!")
+}
+
+const fn c() {}
+
+fn main() {
+    // safety: this is unsound and just used to test
+    unsafe {
+        std::intrinsics::const_eval_select((), c, uhoh);
+    }
+}
diff --git a/src/test/ui/intrinsics/const-eval-select-backtrace.run.stderr b/src/test/ui/intrinsics/const-eval-select-backtrace.run.stderr
new file mode 100644
index 0000000000000..2fd730ac7a68a
--- /dev/null
+++ b/src/test/ui/intrinsics/const-eval-select-backtrace.run.stderr
@@ -0,0 +1,2 @@
+thread 'main' panicked at 'Aaah!', $DIR/const-eval-select-backtrace.rs:16:9
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/test/ui/intrinsics/const-eval-select-bad.rs b/src/test/ui/intrinsics/const-eval-select-bad.rs
index e5640f5ab53b1..fa14efad7b4a4 100644
--- a/src/test/ui/intrinsics/const-eval-select-bad.rs
+++ b/src/test/ui/intrinsics/const-eval-select-bad.rs
@@ -5,10 +5,13 @@ use std::intrinsics::const_eval_select;
 
 const fn not_fn_items() {
     const_eval_select((), || {}, || {});
-    //~^ ERROR the trait bound
+    //~^ ERROR this argument must be a function item
+    //~| ERROR this argument must be a function item
     const_eval_select((), 42, 0xDEADBEEF);
-    //~^ ERROR the trait bound
+    //~^ ERROR expected a `FnOnce<()>` closure
     //~| ERROR expected a `FnOnce<()>` closure
+    //~| ERROR this argument must be a function item
+    //~| ERROR this argument must be a function item
 }
 
 const fn foo(n: i32) -> i32 {
@@ -35,4 +38,9 @@ const fn args_ty_mismatch() {
     //~^ ERROR type mismatch
 }
 
+const fn non_const_fn() {
+    const_eval_select((1,), bar, bar);
+    //~^ ERROR this argument must be a `const fn`
+}
+
 fn main() {}
diff --git a/src/test/ui/intrinsics/const-eval-select-bad.stderr b/src/test/ui/intrinsics/const-eval-select-bad.stderr
index 904e83624b3f2..3720528ad4e40 100644
--- a/src/test/ui/intrinsics/const-eval-select-bad.stderr
+++ b/src/test/ui/intrinsics/const-eval-select-bad.stderr
@@ -1,42 +1,57 @@
-error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]: FnOnce<()>` is not satisfied
+error: this argument must be a function item
   --> $DIR/const-eval-select-bad.rs:7:27
    |
 LL |     const_eval_select((), || {}, || {});
-   |     -----------------     ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]`
-   |     |
-   |     required by a bound introduced by this call
+   |                           ^^^^^
    |
-   = help: the trait `~const FnOnce<()>` is not implemented for closure `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]`
-note: the trait `FnOnce<()>` is implemented for `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]`, but that implementation is not `const`
-  --> $DIR/const-eval-select-bad.rs:7:27
+   = note: expected a function item, found [closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]
+   = help: consult the documentation on `const_eval_select` for more information
+
+error: this argument must be a function item
+  --> $DIR/const-eval-select-bad.rs:7:34
    |
 LL |     const_eval_select((), || {}, || {});
-   |                           ^^^^^
-   = note: wrap the `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]` in a closure with no arguments: `|| { /* code */ }`
-note: required by a bound in `const_eval_select`
-  --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
+   |                                  ^^^^^
    |
-LL |     F: ~const FnOnce<ARG, Output = RET>,
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+   = note: expected a function item, found [closure@$DIR/const-eval-select-bad.rs:7:34: 7:36]
+   = help: consult the documentation on `const_eval_select` for more information
 
-error[E0277]: the trait bound `{integer}: FnOnce<()>` is not satisfied
-  --> $DIR/const-eval-select-bad.rs:9:27
+error: this argument must be a function item
+  --> $DIR/const-eval-select-bad.rs:10:27
+   |
+LL |     const_eval_select((), 42, 0xDEADBEEF);
+   |                           ^^
+   |
+   = note: expected a function item, found {integer}
+   = help: consult the documentation on `const_eval_select` for more information
+
+error[E0277]: expected a `FnOnce<()>` closure, found `{integer}`
+  --> $DIR/const-eval-select-bad.rs:10:27
    |
 LL |     const_eval_select((), 42, 0xDEADBEEF);
    |     -----------------     ^^ expected an `FnOnce<()>` closure, found `{integer}`
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `~const FnOnce<()>` is not implemented for `{integer}`
+   = help: the trait `FnOnce<()>` is not implemented for `{integer}`
    = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`
 note: required by a bound in `const_eval_select`
   --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
    |
-LL |     F: ~const FnOnce<ARG, Output = RET>,
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+LL |         F: FnOnce<ARG, Output = RET>;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+
+error: this argument must be a function item
+  --> $DIR/const-eval-select-bad.rs:10:31
+   |
+LL |     const_eval_select((), 42, 0xDEADBEEF);
+   |                               ^^^^^^^^^^
+   |
+   = note: expected a function item, found {integer}
+   = help: consult the documentation on `const_eval_select` for more information
 
 error[E0277]: expected a `FnOnce<()>` closure, found `{integer}`
-  --> $DIR/const-eval-select-bad.rs:9:31
+  --> $DIR/const-eval-select-bad.rs:10:31
    |
 LL |     const_eval_select((), 42, 0xDEADBEEF);
    |     -----------------         ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `{integer}`
@@ -48,11 +63,11 @@ LL |     const_eval_select((), 42, 0xDEADBEEF);
 note: required by a bound in `const_eval_select`
   --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
    |
-LL |     G: FnOnce<ARG, Output = RET> + ~const Destruct,
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+LL |         G: FnOnce<ARG, Output = RET>,
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
 
 error[E0271]: expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it returns `bool`
-  --> $DIR/const-eval-select-bad.rs:29:34
+  --> $DIR/const-eval-select-bad.rs:32:34
    |
 LL |     const_eval_select((1,), foo, bar);
    |     -----------------            ^^^ expected `i32`, found `bool`
@@ -62,11 +77,11 @@ LL |     const_eval_select((1,), foo, bar);
 note: required by a bound in `const_eval_select`
   --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
    |
-LL |     G: FnOnce<ARG, Output = RET> + ~const Destruct,
-   |                    ^^^^^^^^^^^^ required by this bound in `const_eval_select`
+LL |         G: FnOnce<ARG, Output = RET>,
+   |                        ^^^^^^^^^^^^ required by this bound in `const_eval_select`
 
 error[E0631]: type mismatch in function arguments
-  --> $DIR/const-eval-select-bad.rs:34:32
+  --> $DIR/const-eval-select-bad.rs:37:32
    |
 LL | const fn foo(n: i32) -> i32 {
    | --------------------------- found signature defined here
@@ -81,10 +96,18 @@ LL |     const_eval_select((true,), foo, baz);
 note: required by a bound in `const_eval_select`
   --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
    |
-LL |     F: ~const FnOnce<ARG, Output = RET>,
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+LL |         F: FnOnce<ARG, Output = RET>;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+
+error: this argument must be a `const fn`
+  --> $DIR/const-eval-select-bad.rs:42:29
+   |
+LL |     const_eval_select((1,), bar, bar);
+   |                             ^^^
+   |
+   = help: consult the documentation on `const_eval_select` for more information
 
-error: aborting due to 5 previous errors
+error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0271, E0277, E0631.
 For more information about an error, try `rustc --explain E0271`.