about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock2
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs14
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs6
-rw-r--r--compiler/rustc_lint/src/impl_trait_overcaptures.rs5
-rw-r--r--compiler/rustc_log/src/lib.rs33
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs4
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs30
-rw-r--r--compiler/rustc_middle/src/ty/region.rs4
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs8
-rw-r--r--compiler/rustc_next_trait_solver/src/lib.rs1
-rw-r--r--compiler/rustc_next_trait_solver/src/placeholder.rs158
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs49
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs9
-rw-r--r--compiler/rustc_parse/messages.ftl2
-rw-r--r--compiler/rustc_parse/src/errors.rs8
-rw-r--r--compiler/rustc_parse/src/parser/item.rs81
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs65
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs153
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs5
-rw-r--r--compiler/rustc_type_ir/Cargo.toml2
-rw-r--r--compiler/rustc_type_ir/src/binder.rs6
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs15
-rw-r--r--compiler/rustc_type_ir/src/interner.rs16
-rw-r--r--compiler/rustc_type_ir/src/search_graph/global_cache.rs18
-rw-r--r--compiler/rustc_type_ir/src/search_graph/mod.rs114
-rw-r--r--compiler/rustc_type_ir/src/search_graph/stack.rs113
-rw-r--r--compiler/rustc_type_ir/src/ty_kind/closure.rs2
-rw-r--r--compiler/rustc_type_ir/src/visit.rs8
-rw-r--r--library/alloc/src/vec/mod.rs32
-rw-r--r--library/alloc/src/vec/peek_mut.rs55
-rw-r--r--library/alloctests/tests/lib.rs1
-rw-r--r--library/alloctests/tests/vec.rs17
-rw-r--r--library/core/src/intrinsics/mod.rs4
-rw-r--r--library/std/src/fs.rs5
-rw-r--r--src/bootstrap/src/core/sanity.rs14
-rw-r--r--src/bootstrap/src/lib.rs32
-rw-r--r--src/bootstrap/src/utils/helpers.rs19
-rw-r--r--src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile6
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/platform-support.md6
-rw-r--r--src/doc/rustc/src/platform-support/windows-msvc.md69
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs4
-rw-r--r--src/tools/compiletest/src/util.rs1
-rw-r--r--tests/codegen/retpoline.rs8
-rw-r--r--tests/crashes/137188.rs6
-rw-r--r--tests/crashes/138166.rs8
-rw-r--r--tests/crashes/138240.rs9
-rw-r--r--tests/crashes/138266.rs7
-rw-r--r--tests/crashes/138359.rs8
-rw-r--r--tests/ui/borrowck/issue-47646.stderr2
-rw-r--r--tests/ui/borrowck/issue-85581.stderr2
-rw-r--r--tests/ui/const-generics/mgca/missing_generic_params.rs16
-rw-r--r--tests/ui/const-generics/mgca/missing_generic_params.stderr19
-rw-r--r--tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr73
-rw-r--r--tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr (renamed from tests/ui/feature-gates/feature-gate-abi_gpu_kernel.stderr)28
-rw-r--r--tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr73
-rw-r--r--tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs19
-rw-r--r--tests/ui/parser/bad-fn-ptr-qualifier.fixed8
-rw-r--r--tests/ui/parser/bad-fn-ptr-qualifier.rs8
-rw-r--r--tests/ui/parser/bad-fn-ptr-qualifier.stderr139
-rw-r--r--tests/ui/parser/recover/recover-const-async-fn-ptr.rs8
-rw-r--r--tests/ui/parser/recover/recover-const-async-fn-ptr.stderr141
-rw-r--r--tests/ui/target-feature/retpoline-target-feature-flag.rs8
-rw-r--r--tests/ui/traits/object/no-incomplete-inference.current.stderr16
-rw-r--r--tests/ui/traits/object/no-incomplete-inference.next.stderr16
-rw-r--r--tests/ui/traits/object/no-incomplete-inference.rs18
71 files changed, 1268 insertions, 614 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9c0978b92f7..df2842bddb3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4618,7 +4618,7 @@ dependencies = [
  "derive-where",
  "ena",
  "indexmap",
- "rustc-hash 1.1.0",
+ "rustc-hash 2.1.1",
  "rustc_ast_ir",
  "rustc_data_structures",
  "rustc_index",
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 4f0368bcb01..3b99a653417 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -2147,7 +2147,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 ty_id,
                 &None,
                 path,
-                ParamMode::Optional,
+                ParamMode::Explicit,
                 AllowReturnTypeNotation::No,
                 // FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support
                 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
@@ -2219,7 +2219,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 expr.id,
                 qself,
                 path,
-                ParamMode::Optional,
+                ParamMode::Explicit,
                 AllowReturnTypeNotation::No,
                 // FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support
                 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 754b2ba0d76..96c39c7bb32 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -139,13 +139,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
             sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => {
                 let gid = GlobalId { instance, promoted: None };
-                let ty = match intrinsic_name {
-                    sym::variant_count => self.tcx.types.usize,
-                    sym::needs_drop => self.tcx.types.bool,
-                    sym::type_id => self.tcx.types.u128,
-                    sym::type_name => Ty::new_static_str(self.tcx.tcx),
-                    _ => bug!(),
-                };
+                let ty = self
+                    .tcx
+                    .fn_sig(instance.def_id())
+                    .instantiate(self.tcx.tcx, instance.args)
+                    .output()
+                    .no_bound_vars()
+                    .unwrap();
                 let val = self
                     .ctfe_query(|tcx| tcx.const_eval_global_id(self.typing_env, gid, tcx.span))?;
                 let val = self.const_val_to_op(val, ty, Some(dest.layout))?;
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 54a331a4904..0cd9e36a927 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -1500,13 +1500,31 @@ pub fn init_rustc_env_logger(early_dcx: &EarlyDiagCtxt) {
 
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose
-/// the values directly rather than having to set an environment variable.
+/// the logger config directly rather than having to set an environment variable.
 pub fn init_logger(early_dcx: &EarlyDiagCtxt, cfg: rustc_log::LoggerConfig) {
     if let Err(error) = rustc_log::init_logger(cfg) {
         early_dcx.early_fatal(error.to_string());
     }
 }
 
+/// This allows tools to enable rust logging without having to magically match rustc's
+/// tracing crate version. In contrast to `init_rustc_env_logger`, it allows you to
+/// choose the logger config directly rather than having to set an environment variable.
+/// Moreover, in contrast to `init_logger`, it allows you to add a custom tracing layer
+/// via `build_subscriber`, for example `|| Registry::default().with(custom_layer)`.
+pub fn init_logger_with_additional_layer<F, T>(
+    early_dcx: &EarlyDiagCtxt,
+    cfg: rustc_log::LoggerConfig,
+    build_subscriber: F,
+) where
+    F: FnOnce() -> T,
+    T: rustc_log::BuildSubscriberRet,
+{
+    if let Err(error) = rustc_log::init_logger_with_additional_layer(cfg, build_subscriber) {
+        early_dcx.early_fatal(error.to_string());
+    }
+}
+
 /// Install our usual `ctrlc` handler, which sets [`rustc_const_eval::CTRL_C_RECEIVED`].
 /// Making this handler optional lets tools can install a different handler, if they wish.
 pub fn install_ctrlc_handler() {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index bdc42c7a2d9..106420faa4c 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -9,8 +9,8 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::bug;
 use rustc_middle::ty::{
-    self as ty, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt, TypeVisitor, Upcast,
+    self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+    TypeVisitor, Upcast,
 };
 use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
 use rustc_trait_selection::traits;
@@ -927,7 +927,7 @@ struct GenericParamAndBoundVarCollector<'a, 'tcx> {
 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 'tcx> {
     type Result = ControlFlow<ErrorGuaranteed>;
 
-    fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
+    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
         &mut self,
         binder: &ty::Binder<'tcx, T>,
     ) -> Self::Result {
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
index 8124d7f7c86..aa6f36a67f0 100644
--- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -15,8 +15,7 @@ use rustc_middle::ty::relate::{
     Relate, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys,
 };
 use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
-    TypeVisitor,
+    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint::FutureIncompatibilityReason;
@@ -210,7 +209,7 @@ where
     VarFn: FnOnce() -> FxHashMap<DefId, ty::Variance>,
     OutlivesFn: FnOnce() -> OutlivesEnvironment<'tcx>,
 {
-    fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
+    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
         // When we get into a binder, we need to add its own bound vars to the scope.
         let mut added = vec![];
         for arg in t.bound_vars() {
diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs
index 1bb502ca3d0..df648bbd489 100644
--- a/compiler/rustc_log/src/lib.rs
+++ b/compiler/rustc_log/src/lib.rs
@@ -43,6 +43,7 @@ use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
 use tracing_subscriber::fmt::FmtContext;
 use tracing_subscriber::fmt::format::{self, FormatEvent, FormatFields};
 use tracing_subscriber::layer::SubscriberExt;
+use tracing_subscriber::{Layer, Registry};
 
 /// The values of all the environment variables that matter for configuring a logger.
 /// Errors are explicitly preserved so that we can share error handling.
@@ -72,6 +73,36 @@ impl LoggerConfig {
 
 /// Initialize the logger with the given values for the filter, coloring, and other options env variables.
 pub fn init_logger(cfg: LoggerConfig) -> Result<(), Error> {
+    init_logger_with_additional_layer(cfg, || Registry::default())
+}
+
+/// Trait alias for the complex return type of `build_subscriber` in
+/// [init_logger_with_additional_layer]. A [Registry] with any composition of [tracing::Subscriber]s
+/// (e.g. `Registry::default().with(custom_layer)`) should be compatible with this type.
+/// Having an alias is also useful so rustc_driver_impl does not need to explicitly depend on
+/// `tracing_subscriber`.
+pub trait BuildSubscriberRet:
+    tracing::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span> + Send + Sync
+{
+}
+
+impl<
+    T: tracing::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span> + Send + Sync,
+> BuildSubscriberRet for T
+{
+}
+
+/// Initialize the logger with the given values for the filter, coloring, and other options env variables.
+/// Additionally add a custom layer to collect logging and tracing events via `build_subscriber`,
+/// for example: `|| Registry::default().with(custom_layer)`.
+pub fn init_logger_with_additional_layer<F, T>(
+    cfg: LoggerConfig,
+    build_subscriber: F,
+) -> Result<(), Error>
+where
+    F: FnOnce() -> T,
+    T: BuildSubscriberRet,
+{
     let filter = match cfg.filter {
         Ok(env) => EnvFilter::new(env),
         _ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)),
@@ -124,7 +155,7 @@ pub fn init_logger(cfg: LoggerConfig) -> Result<(), Error> {
         Err(_) => {} // no wraptree
     }
 
-    let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
+    let subscriber = build_subscriber().with(layer.with_filter(filter));
     match cfg.backtrace {
         Ok(backtrace_target) => {
             let fmt_layer = tracing_subscriber::fmt::layer()
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 455ac660412..2fbaa2221a1 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -163,6 +163,10 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
         Const::new_bound(tcx, debruijn, var)
     }
 
+    fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Self {
+        Const::new_placeholder(tcx, placeholder)
+    }
+
     fn new_unevaluated(interner: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Self {
         Const::new_unevaluated(interner, uv)
     }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index dc3f2844e5a..0402d098822 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -933,7 +933,9 @@ impl Placeholder<BoundVar> {
 
 pub type PlaceholderRegion = Placeholder<BoundRegion>;
 
-impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderRegion {
+impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> for PlaceholderRegion {
+    type Bound = BoundRegion;
+
     fn universe(self) -> UniverseIndex {
         self.universe
     }
@@ -946,14 +948,20 @@ impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderRegion {
         Placeholder { universe: ui, ..self }
     }
 
-    fn new(ui: UniverseIndex, var: BoundVar) -> Self {
+    fn new(ui: UniverseIndex, bound: BoundRegion) -> Self {
+        Placeholder { universe: ui, bound }
+    }
+
+    fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self {
         Placeholder { universe: ui, bound: BoundRegion { var, kind: BoundRegionKind::Anon } }
     }
 }
 
 pub type PlaceholderType = Placeholder<BoundTy>;
 
-impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderType {
+impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> for PlaceholderType {
+    type Bound = BoundTy;
+
     fn universe(self) -> UniverseIndex {
         self.universe
     }
@@ -966,7 +974,11 @@ impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderType {
         Placeholder { universe: ui, ..self }
     }
 
-    fn new(ui: UniverseIndex, var: BoundVar) -> Self {
+    fn new(ui: UniverseIndex, bound: BoundTy) -> Self {
+        Placeholder { universe: ui, bound }
+    }
+
+    fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self {
         Placeholder { universe: ui, bound: BoundTy { var, kind: BoundTyKind::Anon } }
     }
 }
@@ -980,7 +992,9 @@ pub struct BoundConst<'tcx> {
 
 pub type PlaceholderConst = Placeholder<BoundVar>;
 
-impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderConst {
+impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> for PlaceholderConst {
+    type Bound = BoundVar;
+
     fn universe(self) -> UniverseIndex {
         self.universe
     }
@@ -993,7 +1007,11 @@ impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderConst {
         Placeholder { universe: ui, ..self }
     }
 
-    fn new(ui: UniverseIndex, var: BoundVar) -> Self {
+    fn new(ui: UniverseIndex, bound: BoundVar) -> Self {
+        Placeholder { universe: ui, bound }
+    }
+
+    fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self {
         Placeholder { universe: ui, bound: var }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs
index 3e4f7a79d53..cc25cd16567 100644
--- a/compiler/rustc_middle/src/ty/region.rs
+++ b/compiler/rustc_middle/src/ty/region.rs
@@ -148,6 +148,10 @@ impl<'tcx> rustc_type_ir::inherent::Region<TyCtxt<'tcx>> for Region<'tcx> {
         Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon })
     }
 
+    fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Self {
+        Region::new_placeholder(tcx, placeholder)
+    }
+
     fn new_static(tcx: TyCtxt<'tcx>) -> Self {
         tcx.lifetimes.re_static
     }
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index f8042174599..3853a804a92 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -66,7 +66,7 @@ impl<'tcx> TyCtxt<'tcx> {
         {
             type Result = ControlFlow<()>;
 
-            fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
+            fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
                 &mut self,
                 t: &Binder<'tcx, T>,
             ) -> Self::Result {
@@ -168,7 +168,7 @@ impl LateBoundRegionsCollector {
 }
 
 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
-    fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) {
+    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) {
         self.current_index.shift_in(1);
         t.super_visit_with(self);
         self.current_index.shift_out(1);
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index cea77533178..47ed9e87244 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -435,13 +435,13 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
             },
             ty::Placeholder(placeholder) => match self.canonicalize_mode {
                 CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderTy(
-                    PlaceholderLike::new(placeholder.universe(), self.variables.len().into()),
+                    PlaceholderLike::new_anon(placeholder.universe(), self.variables.len().into()),
                 ),
                 CanonicalizeMode::Response { .. } => CanonicalVarKind::PlaceholderTy(placeholder),
             },
             ty::Param(_) => match self.canonicalize_mode {
                 CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderTy(
-                    PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()),
+                    PlaceholderLike::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()),
                 ),
                 CanonicalizeMode::Response { .. } => panic!("param ty in response: {t:?}"),
             },
@@ -594,7 +594,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
             },
             ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode {
                 CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderConst(
-                    PlaceholderLike::new(placeholder.universe(), self.variables.len().into()),
+                    PlaceholderLike::new_anon(placeholder.universe(), self.variables.len().into()),
                 ),
                 CanonicalizeMode::Response { .. } => {
                     CanonicalVarKind::PlaceholderConst(placeholder)
@@ -602,7 +602,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
             },
             ty::ConstKind::Param(_) => match self.canonicalize_mode {
                 CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderConst(
-                    PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()),
+                    PlaceholderLike::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()),
                 ),
                 CanonicalizeMode::Response { .. } => panic!("param ty in response: {c:?}"),
             },
diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs
index 92cdc28a37b..77f098e6f26 100644
--- a/compiler/rustc_next_trait_solver/src/lib.rs
+++ b/compiler/rustc_next_trait_solver/src/lib.rs
@@ -12,5 +12,6 @@
 pub mod canonicalizer;
 pub mod coherence;
 pub mod delegate;
+pub mod placeholder;
 pub mod resolve;
 pub mod solve;
diff --git a/compiler/rustc_next_trait_solver/src/placeholder.rs b/compiler/rustc_next_trait_solver/src/placeholder.rs
new file mode 100644
index 00000000000..c88fb8defae
--- /dev/null
+++ b/compiler/rustc_next_trait_solver/src/placeholder.rs
@@ -0,0 +1,158 @@
+use core::panic;
+
+use rustc_type_ir::data_structures::IndexMap;
+use rustc_type_ir::inherent::*;
+use rustc_type_ir::{
+    self as ty, InferCtxtLike, Interner, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitableExt,
+};
+
+pub struct BoundVarReplacer<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner>
+where
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner,
+{
+    infcx: &'a Infcx,
+    // These three maps track the bound variable that were replaced by placeholders. It might be
+    // nice to remove these since we already have the `kind` in the placeholder; we really just need
+    // the `var` (but we *could* bring that into scope if we were to track them as we pass them).
+    mapped_regions: IndexMap<I::PlaceholderRegion, I::BoundRegion>,
+    mapped_types: IndexMap<I::PlaceholderTy, I::BoundTy>,
+    mapped_consts: IndexMap<I::PlaceholderConst, I::BoundConst>,
+    // The current depth relative to *this* folding, *not* the entire normalization. In other words,
+    // the depth of binders we've passed here.
+    current_index: ty::DebruijnIndex,
+    // The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy:
+    // we don't actually create a universe until we see a bound var we have to replace.
+    universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
+}
+
+impl<'a, Infcx, I> BoundVarReplacer<'a, Infcx, I>
+where
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner,
+{
+    /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that
+    /// use a binding level above `universe_indices.len()`, we fail.
+    pub fn replace_bound_vars<T: TypeFoldable<I>>(
+        infcx: &'a Infcx,
+        universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
+        value: T,
+    ) -> (
+        T,
+        IndexMap<I::PlaceholderRegion, I::BoundRegion>,
+        IndexMap<I::PlaceholderTy, I::BoundTy>,
+        IndexMap<I::PlaceholderConst, I::BoundConst>,
+    ) {
+        let mut replacer = BoundVarReplacer {
+            infcx,
+            mapped_regions: Default::default(),
+            mapped_types: Default::default(),
+            mapped_consts: Default::default(),
+            current_index: ty::INNERMOST,
+            universe_indices,
+        };
+
+        let value = value.fold_with(&mut replacer);
+
+        (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts)
+    }
+
+    fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex {
+        let infcx = self.infcx;
+        let index =
+            self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1;
+        let universe = self.universe_indices[index].unwrap_or_else(|| {
+            for i in self.universe_indices.iter_mut().take(index + 1) {
+                *i = i.or_else(|| Some(infcx.create_next_universe()))
+            }
+            self.universe_indices[index].unwrap()
+        });
+        universe
+    }
+}
+
+impl<Infcx, I> TypeFolder<I> for BoundVarReplacer<'_, Infcx, I>
+where
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner,
+{
+    fn cx(&self) -> I {
+        self.infcx.cx()
+    }
+
+    fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
+        self.current_index.shift_in(1);
+        let t = t.super_fold_with(self);
+        self.current_index.shift_out(1);
+        t
+    }
+
+    fn fold_region(&mut self, r: I::Region) -> I::Region {
+        match r.kind() {
+            ty::ReBound(debruijn, _)
+                if debruijn.as_usize()
+                    >= self.current_index.as_usize() + self.universe_indices.len() =>
+            {
+                panic!(
+                    "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}",
+                    self.universe_indices
+                );
+            }
+            ty::ReBound(debruijn, br) if debruijn >= self.current_index => {
+                let universe = self.universe_for(debruijn);
+                let p = PlaceholderLike::new(universe, br);
+                self.mapped_regions.insert(p, br);
+                Region::new_placeholder(self.cx(), p)
+            }
+            _ => r,
+        }
+    }
+
+    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
+        match t.kind() {
+            ty::Bound(debruijn, _)
+                if debruijn.as_usize() + 1
+                    > self.current_index.as_usize() + self.universe_indices.len() =>
+            {
+                panic!(
+                    "Bound vars {t:#?} outside of `self.universe_indices`: {:#?}",
+                    self.universe_indices
+                );
+            }
+            ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
+                let universe = self.universe_for(debruijn);
+                let p = PlaceholderLike::new(universe, bound_ty);
+                self.mapped_types.insert(p, bound_ty);
+                Ty::new_placeholder(self.cx(), p)
+            }
+            _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
+            _ => t,
+        }
+    }
+
+    fn fold_const(&mut self, ct: I::Const) -> I::Const {
+        match ct.kind() {
+            ty::ConstKind::Bound(debruijn, _)
+                if debruijn.as_usize() + 1
+                    > self.current_index.as_usize() + self.universe_indices.len() =>
+            {
+                panic!(
+                    "Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}",
+                    self.universe_indices
+                );
+            }
+            ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => {
+                let universe = self.universe_for(debruijn);
+                let p = PlaceholderLike::new(universe, bound_const);
+                self.mapped_consts.insert(p, bound_const);
+                Const::new_placeholder(self.cx(), p)
+            }
+            _ => ct.super_fold_with(self),
+        }
+    }
+
+    fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
+        if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
+    }
+}
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index 542e212e1bf..0c267feefbe 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -1014,7 +1014,11 @@ where
             return Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal));
         }
 
-        match assumption.visit_with(&mut FindParamInClause { ecx: self, param_env }) {
+        match assumption.visit_with(&mut FindParamInClause {
+            ecx: self,
+            param_env,
+            universes: vec![],
+        }) {
             ControlFlow::Break(Err(NoSolution)) => Err(NoSolution),
             ControlFlow::Break(Ok(())) => Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)),
             ControlFlow::Continue(()) => Ok(CandidateSource::ParamEnv(ParamEnvSource::Global)),
@@ -1025,6 +1029,7 @@ where
 struct FindParamInClause<'a, 'b, D: SolverDelegate<Interner = I>, I: Interner> {
     ecx: &'a mut EvalCtxt<'b, D>,
     param_env: I::ParamEnv,
+    universes: Vec<Option<ty::UniverseIndex>>,
 }
 
 impl<D, I> TypeVisitor<I> for FindParamInClause<'_, '_, D, I>
@@ -1034,31 +1039,42 @@ where
 {
     type Result = ControlFlow<Result<(), NoSolution>>;
 
-    fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
-        self.ecx.enter_forall(t.clone(), |ecx, v| {
-            v.visit_with(&mut FindParamInClause { ecx, param_env: self.param_env })
-        })
+    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
+        self.universes.push(None);
+        t.super_visit_with(self)?;
+        self.universes.pop();
+        ControlFlow::Continue(())
     }
 
     fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
+        let ty = self.ecx.replace_bound_vars(ty, &mut self.universes);
         let Ok(ty) = self.ecx.structurally_normalize_ty(self.param_env, ty) else {
             return ControlFlow::Break(Err(NoSolution));
         };
 
-        if let ty::Placeholder(_) = ty.kind() {
-            ControlFlow::Break(Ok(()))
+        if let ty::Placeholder(p) = ty.kind() {
+            if p.universe() == ty::UniverseIndex::ROOT {
+                ControlFlow::Break(Ok(()))
+            } else {
+                ControlFlow::Continue(())
+            }
         } else {
             ty.super_visit_with(self)
         }
     }
 
     fn visit_const(&mut self, ct: I::Const) -> Self::Result {
+        let ct = self.ecx.replace_bound_vars(ct, &mut self.universes);
         let Ok(ct) = self.ecx.structurally_normalize_const(self.param_env, ct) else {
             return ControlFlow::Break(Err(NoSolution));
         };
 
-        if let ty::ConstKind::Placeholder(_) = ct.kind() {
-            ControlFlow::Break(Ok(()))
+        if let ty::ConstKind::Placeholder(p) = ct.kind() {
+            if p.universe() == ty::UniverseIndex::ROOT {
+                ControlFlow::Break(Ok(()))
+            } else {
+                ControlFlow::Continue(())
+            }
         } else {
             ct.super_visit_with(self)
         }
@@ -1066,10 +1082,17 @@ where
 
     fn visit_region(&mut self, r: I::Region) -> Self::Result {
         match self.ecx.eager_resolve_region(r).kind() {
-            ty::ReStatic | ty::ReError(_) => ControlFlow::Continue(()),
-            ty::ReVar(_) | ty::RePlaceholder(_) => ControlFlow::Break(Ok(())),
-            ty::ReErased | ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReBound(..) => {
-                unreachable!()
+            ty::ReStatic | ty::ReError(_) | ty::ReBound(..) => ControlFlow::Continue(()),
+            ty::RePlaceholder(p) => {
+                if p.universe() == ty::UniverseIndex::ROOT {
+                    ControlFlow::Break(Ok(()))
+                } else {
+                    ControlFlow::Continue(())
+                }
+            }
+            ty::ReVar(_) => ControlFlow::Break(Ok(())),
+            ty::ReErased | ty::ReEarlyParam(_) | ty::ReLateParam(_) => {
+                unreachable!("unexpected region in param-env clause")
             }
         }
     }
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index 345ece20b7e..7ead0a6d6b7 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -19,6 +19,7 @@ use tracing::{debug, instrument, trace};
 use super::has_only_region_constraints;
 use crate::coherence;
 use crate::delegate::SolverDelegate;
+use crate::placeholder::BoundVarReplacer;
 use crate::solve::inspect::{self, ProofTreeBuilder};
 use crate::solve::search_graph::SearchGraph;
 use crate::solve::{
@@ -1232,6 +1233,14 @@ where
     ) -> Result<Certainty, NoSolution> {
         self.delegate.is_transmutable(dst, src, assume)
     }
+
+    pub(super) fn replace_bound_vars<T: TypeFoldable<I>>(
+        &self,
+        t: T,
+        universes: &mut Vec<Option<ty::UniverseIndex>>,
+    ) -> T {
+        BoundVarReplacer::replace_bound_vars(&**self.delegate, universes, t).0
+    }
 }
 
 /// Eagerly replace aliases with inference variables, emitting `AliasRelate`
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 1f221b4bf78..f6e0b08b140 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -299,10 +299,12 @@ parse_float_literal_unsupported_base = {$base} float literal is not supported
 parse_fn_pointer_cannot_be_async = an `fn` pointer type cannot be `async`
     .label = `async` because of this
     .suggestion = remove the `async` qualifier
+    .note = allowed qualifiers are: `unsafe` and `extern`
 
 parse_fn_pointer_cannot_be_const = an `fn` pointer type cannot be `const`
     .label = `const` because of this
     .suggestion = remove the `const` qualifier
+    .note = allowed qualifiers are: `unsafe` and `extern`
 
 parse_fn_ptr_with_generics = function pointer types may not have generic parameters
     .suggestion = consider moving the lifetime {$arity ->
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 2dba568a258..0f0c5434800 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2938,22 +2938,22 @@ pub(crate) struct DynAfterMut {
 
 #[derive(Diagnostic)]
 #[diag(parse_fn_pointer_cannot_be_const)]
+#[note]
 pub(crate) struct FnPointerCannotBeConst {
     #[primary_span]
-    pub span: Span,
     #[label]
-    pub qualifier: Span,
+    pub span: Span,
     #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
     pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
 #[diag(parse_fn_pointer_cannot_be_async)]
+#[note]
 pub(crate) struct FnPointerCannotBeAsync {
     #[primary_span]
-    pub span: Span,
     #[label]
-    pub qualifier: Span,
+    pub span: Span,
     #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
     pub suggestion: Span,
 }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index a325c2a57ab..658ed4bd41c 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -23,7 +23,7 @@ use super::{
     AttrWrapper, ExpKeywordPair, ExpTokenPair, FollowedByType, ForceCollect, Parser, PathStyle,
     Recovered, Trailing, UsePreAttrPos,
 };
-use crate::errors::{self, MacroExpandsToAdtField};
+use crate::errors::{self, FnPointerCannotBeAsync, FnPointerCannotBeConst, MacroExpandsToAdtField};
 use crate::{exp, fluent_generated as fluent};
 
 impl<'a> Parser<'a> {
@@ -2402,7 +2402,7 @@ impl<'a> Parser<'a> {
         case: Case,
     ) -> PResult<'a, (Ident, FnSig, Generics, Option<P<FnContract>>, Option<P<Block>>)> {
         let fn_span = self.token.span;
-        let header = self.parse_fn_front_matter(vis, case)?; // `const ... fn`
+        let header = self.parse_fn_front_matter(vis, case, FrontMatterParsingMode::Function)?; // `const ... fn`
         let ident = self.parse_ident()?; // `foo`
         let mut generics = self.parse_generics()?; // `<'a, T, ...>`
         let decl = match self.parse_fn_decl(
@@ -2658,16 +2658,37 @@ impl<'a> Parser<'a> {
     ///
     /// `vis` represents the visibility that was already parsed, if any. Use
     /// `Visibility::Inherited` when no visibility is known.
+    ///
+    /// If `parsing_mode` is `FrontMatterParsingMode::FunctionPtrType`, we error on `const` and `async` qualifiers,
+    /// which are not allowed in function pointer types.
     pub(super) fn parse_fn_front_matter(
         &mut self,
         orig_vis: &Visibility,
         case: Case,
+        parsing_mode: FrontMatterParsingMode,
     ) -> PResult<'a, FnHeader> {
         let sp_start = self.token.span;
         let constness = self.parse_constness(case);
+        if parsing_mode == FrontMatterParsingMode::FunctionPtrType
+            && let Const::Yes(const_span) = constness
+        {
+            self.dcx().emit_err(FnPointerCannotBeConst {
+                span: const_span,
+                suggestion: const_span.until(self.token.span),
+            });
+        }
 
         let async_start_sp = self.token.span;
         let coroutine_kind = self.parse_coroutine_kind(case);
+        if parsing_mode == FrontMatterParsingMode::FunctionPtrType
+            && let Some(ast::CoroutineKind::Async { span: async_span, .. }) = coroutine_kind
+        {
+            self.dcx().emit_err(FnPointerCannotBeAsync {
+                span: async_span,
+                suggestion: async_span.until(self.token.span),
+            });
+        }
+        // FIXME(gen_blocks): emit a similar error for `gen fn()`
 
         let unsafe_start_sp = self.token.span;
         let safety = self.parse_safety(case);
@@ -2703,6 +2724,11 @@ impl<'a> Parser<'a> {
                     enum WrongKw {
                         Duplicated(Span),
                         Misplaced(Span),
+                        /// `MisplacedDisallowedQualifier` is only used instead of `Misplaced`,
+                        /// when the misplaced keyword is disallowed by the current `FrontMatterParsingMode`.
+                        /// In this case, we avoid generating the suggestion to swap around the keywords,
+                        /// as we already generated a suggestion to remove the keyword earlier.
+                        MisplacedDisallowedQualifier,
                     }
 
                     // We may be able to recover
@@ -2716,7 +2742,21 @@ impl<'a> Parser<'a> {
                             Const::Yes(sp) => Some(WrongKw::Duplicated(sp)),
                             Const::No => {
                                 recover_constness = Const::Yes(self.token.span);
-                                Some(WrongKw::Misplaced(async_start_sp))
+                                match parsing_mode {
+                                    FrontMatterParsingMode::Function => {
+                                        Some(WrongKw::Misplaced(async_start_sp))
+                                    }
+                                    FrontMatterParsingMode::FunctionPtrType => {
+                                        self.dcx().emit_err(FnPointerCannotBeConst {
+                                            span: self.token.span,
+                                            suggestion: self
+                                                .token
+                                                .span
+                                                .with_lo(self.prev_token.span.hi()),
+                                        });
+                                        Some(WrongKw::MisplacedDisallowedQualifier)
+                                    }
+                                }
                             }
                         }
                     } else if self.check_keyword(exp!(Async)) {
@@ -2742,7 +2782,21 @@ impl<'a> Parser<'a> {
                                     closure_id: DUMMY_NODE_ID,
                                     return_impl_trait_id: DUMMY_NODE_ID,
                                 });
-                                Some(WrongKw::Misplaced(unsafe_start_sp))
+                                match parsing_mode {
+                                    FrontMatterParsingMode::Function => {
+                                        Some(WrongKw::Misplaced(async_start_sp))
+                                    }
+                                    FrontMatterParsingMode::FunctionPtrType => {
+                                        self.dcx().emit_err(FnPointerCannotBeAsync {
+                                            span: self.token.span,
+                                            suggestion: self
+                                                .token
+                                                .span
+                                                .with_lo(self.prev_token.span.hi()),
+                                        });
+                                        Some(WrongKw::MisplacedDisallowedQualifier)
+                                    }
+                                }
                             }
                         }
                     } else if self.check_keyword(exp!(Unsafe)) {
@@ -2840,14 +2894,20 @@ impl<'a> Parser<'a> {
 
                     // FIXME(gen_blocks): add keyword recovery logic for genness
 
-                    if wrong_kw.is_some()
+                    if let Some(wrong_kw) = wrong_kw
                         && self.may_recover()
                         && self.look_ahead(1, |tok| tok.is_keyword_case(kw::Fn, case))
                     {
                         // Advance past the misplaced keyword and `fn`
                         self.bump();
                         self.bump();
-                        err.emit();
+                        // When we recover from a `MisplacedDisallowedQualifier`, we already emitted an error for the disallowed qualifier
+                        // So we don't emit another error that the qualifier is unexpected.
+                        if matches!(wrong_kw, WrongKw::MisplacedDisallowedQualifier) {
+                            err.cancel();
+                        } else {
+                            err.emit();
+                        }
                         return Ok(FnHeader {
                             constness: recover_constness,
                             safety: recover_safety,
@@ -3194,3 +3254,12 @@ enum IsMacroRulesItem {
     Yes { has_bang: bool },
     No,
 }
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub(super) enum FrontMatterParsingMode {
+    /// Parse the front matter of a function declaration
+    Function,
+    /// Parse the front matter of a function pointet type.
+    /// For function pointer types, the `const` and `async` keywords are not permitted.
+    FunctionPtrType,
+}
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 9ddfc179e9b..620a34044d1 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -15,10 +15,11 @@ use thin_vec::{ThinVec, thin_vec};
 use super::{Parser, PathStyle, SeqSep, TokenType, Trailing};
 use crate::errors::{
     self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
-    FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg,
-    HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
-    NestedCVariadicType, ReturnTypesUseThinArrow,
+    FnPtrWithGenerics, FnPtrWithGenericsSugg, HelpUseLatestEdition, InvalidDynKeyword,
+    LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType,
+    ReturnTypesUseThinArrow,
 };
+use crate::parser::item::FrontMatterParsingMode;
 use crate::{exp, maybe_recover_from_interpolated_ty_qpath};
 
 /// Signals whether parsing a type should allow `+`.
@@ -669,62 +670,16 @@ impl<'a> Parser<'a> {
             tokens: None,
         };
         let span_start = self.token.span;
-        let ast::FnHeader { ext, safety, constness, coroutine_kind } =
-            self.parse_fn_front_matter(&inherited_vis, Case::Sensitive)?;
-        let fn_start_lo = self.prev_token.span.lo();
+        let ast::FnHeader { ext, safety, .. } = self.parse_fn_front_matter(
+            &inherited_vis,
+            Case::Sensitive,
+            FrontMatterParsingMode::FunctionPtrType,
+        )?;
         if self.may_recover() && self.token == TokenKind::Lt {
             self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?;
         }
         let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?;
-        let whole_span = lo.to(self.prev_token.span);
-
-        // Order/parsing of "front matter" follows:
-        // `<constness> <coroutine_kind> <safety> <extern> fn()`
-        //  ^           ^                ^        ^        ^
-        //  |           |                |        |        fn_start_lo
-        //  |           |                |        ext_sp.lo
-        //  |           |                safety_sp.lo
-        //  |           coroutine_sp.lo
-        //  const_sp.lo
-        if let ast::Const::Yes(const_span) = constness {
-            let next_token_lo = if let Some(
-                ast::CoroutineKind::Async { span, .. }
-                | ast::CoroutineKind::Gen { span, .. }
-                | ast::CoroutineKind::AsyncGen { span, .. },
-            ) = coroutine_kind
-            {
-                span.lo()
-            } else if let ast::Safety::Unsafe(span) | ast::Safety::Safe(span) = safety {
-                span.lo()
-            } else if let ast::Extern::Implicit(span) | ast::Extern::Explicit(_, span) = ext {
-                span.lo()
-            } else {
-                fn_start_lo
-            };
-            let sugg_span = const_span.with_hi(next_token_lo);
-            self.dcx().emit_err(FnPointerCannotBeConst {
-                span: whole_span,
-                qualifier: const_span,
-                suggestion: sugg_span,
-            });
-        }
-        if let Some(ast::CoroutineKind::Async { span: async_span, .. }) = coroutine_kind {
-            let next_token_lo = if let ast::Safety::Unsafe(span) | ast::Safety::Safe(span) = safety
-            {
-                span.lo()
-            } else if let ast::Extern::Implicit(span) | ast::Extern::Explicit(_, span) = ext {
-                span.lo()
-            } else {
-                fn_start_lo
-            };
-            let sugg_span = async_span.with_hi(next_token_lo);
-            self.dcx().emit_err(FnPointerCannotBeAsync {
-                span: whole_span,
-                qualifier: async_span,
-                suggestion: sugg_span,
-            });
-        }
-        // FIXME(gen_blocks): emit a similar error for `gen fn()`
+
         let decl_span = span_start.to(self.prev_token.span);
         Ok(TyKind::BareFn(P(BareFnTy { ext, safety, generic_params: params, decl, decl_span })))
     }
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index eb34cb10c68..a54eb80fedc 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -9,7 +9,7 @@ use rustc_macros::extension;
 pub use rustc_middle::traits::query::NormalizationResult;
 use rustc_middle::ty::{
     self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable,
-    TypeVisitableExt, TypeVisitor, TypingMode,
+    TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
 };
 use rustc_span::DUMMY_SP;
 use tracing::{debug, info, instrument};
@@ -127,7 +127,7 @@ struct MaxEscapingBoundVarVisitor {
 }
 
 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxEscapingBoundVarVisitor {
-    fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
+    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
         self.outer_index.shift_in(1);
         t.super_visit_with(self);
         self.outer_index.shift_out(1);
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 3a2f9e8ca17..1b9b68fa980 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1919,12 +1919,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         // impl `impl<T: ?Sized> Any for T { .. }`. This really shouldn't exist but is
         // necessary due to #57893. We again arbitrarily prefer the applicable candidate
         // with the lowest index.
+        //
+        // We do not want to use these impls to guide inference in case a user-written impl
+        // may also apply.
         let object_bound = candidates
             .iter()
             .filter_map(|c| if let ObjectCandidate(i) = c.candidate { Some(i) } else { None })
             .try_reduce(|c1, c2| if has_non_region_infer { None } else { Some(c1.min(c2)) });
         match object_bound {
-            Some(Some(index)) => return Some(ObjectCandidate(index)),
+            Some(Some(index)) => {
+                return if has_non_region_infer
+                    && candidates.iter().any(|c| matches!(c.candidate, ImplCandidate(_)))
+                {
+                    None
+                } else {
+                    Some(ObjectCandidate(index))
+                };
+            }
             Some(None) => {}
             None => return None,
         }
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 035fd38c48a..0723aebd5d2 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -1,4 +1,4 @@
-use std::collections::{BTreeMap, VecDeque};
+use std::collections::VecDeque;
 
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir::LangItem;
@@ -9,6 +9,7 @@ use rustc_middle::bug;
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
 };
+pub use rustc_next_trait_solver::placeholder::BoundVarReplacer;
 use rustc_span::Span;
 use smallvec::{SmallVec, smallvec};
 use tracing::debug;
@@ -212,158 +213,12 @@ pub fn with_replaced_escaping_bound_vars<
     }
 }
 
-pub struct BoundVarReplacer<'a, 'tcx> {
-    infcx: &'a InferCtxt<'tcx>,
-    // These three maps track the bound variable that were replaced by placeholders. It might be
-    // nice to remove these since we already have the `kind` in the placeholder; we really just need
-    // the `var` (but we *could* bring that into scope if we were to track them as we pass them).
-    mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>,
-    mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>,
-    mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
-    // The current depth relative to *this* folding, *not* the entire normalization. In other words,
-    // the depth of binders we've passed here.
-    current_index: ty::DebruijnIndex,
-    // The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy:
-    // we don't actually create a universe until we see a bound var we have to replace.
-    universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
-}
-
-impl<'a, 'tcx> BoundVarReplacer<'a, 'tcx> {
-    /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that
-    /// use a binding level above `universe_indices.len()`, we fail.
-    pub fn replace_bound_vars<T: TypeFoldable<TyCtxt<'tcx>>>(
-        infcx: &'a InferCtxt<'tcx>,
-        universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
-        value: T,
-    ) -> (
-        T,
-        FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>,
-        FxIndexMap<ty::PlaceholderType, ty::BoundTy>,
-        BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
-    ) {
-        let mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion> =
-            FxIndexMap::default();
-        let mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy> = FxIndexMap::default();
-        let mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar> = BTreeMap::new();
-
-        let mut replacer = BoundVarReplacer {
-            infcx,
-            mapped_regions,
-            mapped_types,
-            mapped_consts,
-            current_index: ty::INNERMOST,
-            universe_indices,
-        };
-
-        let value = value.fold_with(&mut replacer);
-
-        (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts)
-    }
-
-    fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex {
-        let infcx = self.infcx;
-        let index =
-            self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1;
-        let universe = self.universe_indices[index].unwrap_or_else(|| {
-            for i in self.universe_indices.iter_mut().take(index + 1) {
-                *i = i.or_else(|| Some(infcx.create_next_universe()))
-            }
-            self.universe_indices[index].unwrap()
-        });
-        universe
-    }
-}
-
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> {
-    fn cx(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
-    }
-
-    fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
-        &mut self,
-        t: ty::Binder<'tcx, T>,
-    ) -> ty::Binder<'tcx, T> {
-        self.current_index.shift_in(1);
-        let t = t.super_fold_with(self);
-        self.current_index.shift_out(1);
-        t
-    }
-
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        match r.kind() {
-            ty::ReBound(debruijn, _)
-                if debruijn.as_usize()
-                    >= self.current_index.as_usize() + self.universe_indices.len() =>
-            {
-                bug!(
-                    "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}",
-                    self.universe_indices
-                );
-            }
-            ty::ReBound(debruijn, br) if debruijn >= self.current_index => {
-                let universe = self.universe_for(debruijn);
-                let p = ty::PlaceholderRegion { universe, bound: br };
-                self.mapped_regions.insert(p, br);
-                ty::Region::new_placeholder(self.infcx.tcx, p)
-            }
-            _ => r,
-        }
-    }
-
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        match *t.kind() {
-            ty::Bound(debruijn, _)
-                if debruijn.as_usize() + 1
-                    > self.current_index.as_usize() + self.universe_indices.len() =>
-            {
-                bug!(
-                    "Bound vars {t:#?} outside of `self.universe_indices`: {:#?}",
-                    self.universe_indices
-                );
-            }
-            ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
-                let universe = self.universe_for(debruijn);
-                let p = ty::PlaceholderType { universe, bound: bound_ty };
-                self.mapped_types.insert(p, bound_ty);
-                Ty::new_placeholder(self.infcx.tcx, p)
-            }
-            _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
-            _ => t,
-        }
-    }
-
-    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        match ct.kind() {
-            ty::ConstKind::Bound(debruijn, _)
-                if debruijn.as_usize() + 1
-                    > self.current_index.as_usize() + self.universe_indices.len() =>
-            {
-                bug!(
-                    "Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}",
-                    self.universe_indices
-                );
-            }
-            ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => {
-                let universe = self.universe_for(debruijn);
-                let p = ty::PlaceholderConst { universe, bound: bound_const };
-                self.mapped_consts.insert(p, bound_const);
-                ty::Const::new_placeholder(self.infcx.tcx, p)
-            }
-            _ => ct.super_fold_with(self),
-        }
-    }
-
-    fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
-        if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
-    }
-}
-
 /// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came.
 pub struct PlaceholderReplacer<'a, 'tcx> {
     infcx: &'a InferCtxt<'tcx>,
     mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>,
     mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>,
-    mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
+    mapped_consts: FxIndexMap<ty::PlaceholderConst, ty::BoundVar>,
     universe_indices: &'a [Option<ty::UniverseIndex>],
     current_index: ty::DebruijnIndex,
 }
@@ -373,7 +228,7 @@ impl<'a, 'tcx> PlaceholderReplacer<'a, 'tcx> {
         infcx: &'a InferCtxt<'tcx>,
         mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>,
         mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>,
-        mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
+        mapped_consts: FxIndexMap<ty::PlaceholderConst, ty::BoundVar>,
         universe_indices: &'a [Option<ty::UniverseIndex>],
         value: T,
     ) -> T {
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 79ac622df32..11becea998c 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -7,8 +7,7 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast,
-    fold_regions,
+    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast, fold_regions,
 };
 use rustc_span::DUMMY_SP;
 use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
@@ -186,7 +185,7 @@ struct ImplTraitInTraitFinder<'a, 'tcx> {
 }
 
 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
-    fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, binder: &ty::Binder<'tcx, T>) {
+    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, binder: &ty::Binder<'tcx, T>) {
         self.depth.shift_in(1);
         binder.super_visit_with(self);
         self.depth.shift_out(1);
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index 83d3d78298e..4bd7bfe79be 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -9,7 +9,7 @@ bitflags = "2.4.1"
 derive-where = "1.2.7"
 ena = "0.14.3"
 indexmap = "2.0.0"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
 rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false }
 rustc_data_structures = { path = "../rustc_data_structures", optional = true }
 rustc_index = { path = "../rustc_index", default-features = false }
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
index 55c0a3bba9f..927a2ce84ea 100644
--- a/compiler/rustc_type_ir/src/binder.rs
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -128,7 +128,7 @@ impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Binder<I, T> {
     }
 }
 
-impl<I: Interner, T: TypeFoldable<I>> TypeVisitable<I> for Binder<I, T> {
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Binder<I, T> {
     fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
         visitor.visit_binder(self)
     }
@@ -147,7 +147,7 @@ impl<I: Interner, T: TypeFoldable<I>> TypeSuperFoldable<I> for Binder<I, T> {
     }
 }
 
-impl<I: Interner, T: TypeFoldable<I>> TypeSuperVisitable<I> for Binder<I, T> {
+impl<I: Interner, T: TypeVisitable<I>> TypeSuperVisitable<I> for Binder<I, T> {
     fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
         self.as_ref().skip_binder().visit_with(visitor)
     }
@@ -292,7 +292,7 @@ impl<I: Interner> ValidateBoundVars<I> {
 impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> {
     type Result = ControlFlow<()>;
 
-    fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &Binder<I, T>) -> Self::Result {
+    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &Binder<I, T>) -> Self::Result {
         self.binder_index.shift_in(1);
         let result = t.super_visit_with(self);
         self.binder_index.shift_out(1);
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index fa88bcb891a..436ab9f80b6 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -228,6 +228,8 @@ pub trait Region<I: Interner<Region = Self>>:
 
     fn new_static(interner: I) -> Self;
 
+    fn new_placeholder(interner: I, var: I::PlaceholderRegion) -> Self;
+
     fn is_bound(self) -> bool {
         matches!(self.kind(), ty::ReBound(..))
     }
@@ -254,6 +256,8 @@ pub trait Const<I: Interner<Const = Self>>:
 
     fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
 
+    fn new_placeholder(interner: I, param: I::PlaceholderConst) -> Self;
+
     fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst<I>) -> Self;
 
     fn new_expr(interner: I, expr: I::ExprConst) -> Self;
@@ -524,13 +528,14 @@ pub trait Clauses<I: Interner<Clauses = Self>>:
 }
 
 /// Common capabilities of placeholder kinds
-pub trait PlaceholderLike: Copy + Debug + Hash + Eq {
+pub trait PlaceholderLike<I: Interner>: Copy + Debug + Hash + Eq {
     fn universe(self) -> ty::UniverseIndex;
     fn var(self) -> ty::BoundVar;
 
+    type Bound: BoundVarLike<I>;
+    fn new(ui: ty::UniverseIndex, bound: Self::Bound) -> Self;
+    fn new_anon(ui: ty::UniverseIndex, var: ty::BoundVar) -> Self;
     fn with_updated_universe(self, ui: ty::UniverseIndex) -> Self;
-
-    fn new(ui: ty::UniverseIndex, var: ty::BoundVar) -> Self;
 }
 
 pub trait IntoKind {
@@ -539,13 +544,13 @@ pub trait IntoKind {
     fn kind(self) -> Self::Kind;
 }
 
-pub trait BoundVarLike<I: Interner> {
+pub trait BoundVarLike<I: Interner>: Copy + Debug + Hash + Eq {
     fn var(self) -> ty::BoundVar;
 
     fn assert_eq(self, var: I::BoundVarKind);
 }
 
-pub trait ParamLike {
+pub trait ParamLike: Copy + Debug + Hash + Eq {
     fn index(self) -> u32;
 }
 
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index cc0925b2c32..033d2579678 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -103,9 +103,9 @@ pub trait Interner:
     type Ty: Ty<Self>;
     type Tys: Tys<Self>;
     type FnInputTys: Copy + Debug + Hash + Eq + SliceLike<Item = Self::Ty> + TypeVisitable<Self>;
-    type ParamTy: Copy + Debug + Hash + Eq + ParamLike;
-    type BoundTy: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
-    type PlaceholderTy: PlaceholderLike;
+    type ParamTy: ParamLike;
+    type BoundTy: BoundVarLike<Self>;
+    type PlaceholderTy: PlaceholderLike<Self, Bound = Self::BoundTy>;
 
     // Things stored inside of tys
     type ErrorGuaranteed: Copy + Debug + Hash + Eq;
@@ -131,19 +131,19 @@ pub trait Interner:
 
     // Kinds of consts
     type Const: Const<Self>;
-    type PlaceholderConst: PlaceholderLike;
     type ParamConst: Copy + Debug + Hash + Eq + ParamLike;
-    type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
+    type BoundConst: BoundVarLike<Self>;
+    type PlaceholderConst: PlaceholderLike<Self, Bound = Self::BoundConst>;
     type ValueConst: ValueConst<Self>;
     type ExprConst: ExprConst<Self>;
     type ValTree: Copy + Debug + Hash + Eq;
 
     // Kinds of regions
     type Region: Region<Self>;
-    type EarlyParamRegion: Copy + Debug + Hash + Eq + ParamLike;
+    type EarlyParamRegion: ParamLike;
     type LateParamRegion: Copy + Debug + Hash + Eq;
-    type BoundRegion: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
-    type PlaceholderRegion: PlaceholderLike;
+    type BoundRegion: BoundVarLike<Self>;
+    type PlaceholderRegion: PlaceholderLike<Self, Bound = Self::BoundRegion>;
 
     // Predicates
     type ParamEnv: ParamEnv<Self>;
diff --git a/compiler/rustc_type_ir/src/search_graph/global_cache.rs b/compiler/rustc_type_ir/src/search_graph/global_cache.rs
index 0ce927b58bb..a2442660259 100644
--- a/compiler/rustc_type_ir/src/search_graph/global_cache.rs
+++ b/compiler/rustc_type_ir/src/search_graph/global_cache.rs
@@ -4,7 +4,7 @@ use super::{AvailableDepth, Cx, NestedGoals};
 use crate::data_structures::HashMap;
 
 struct Success<X: Cx> {
-    additional_depth: usize,
+    required_depth: usize,
     nested_goals: NestedGoals<X>,
     result: X::Tracked<X::Result>,
 }
@@ -28,7 +28,7 @@ struct CacheEntry<X: Cx> {
 #[derive_where(Debug; X: Cx)]
 pub(super) struct CacheData<'a, X: Cx> {
     pub(super) result: X::Result,
-    pub(super) additional_depth: usize,
+    pub(super) required_depth: usize,
     pub(super) encountered_overflow: bool,
     pub(super) nested_goals: &'a NestedGoals<X>,
 }
@@ -47,7 +47,7 @@ impl<X: Cx> GlobalCache<X> {
         origin_result: X::Result,
         dep_node: X::DepNodeIndex,
 
-        additional_depth: usize,
+        required_depth: usize,
         encountered_overflow: bool,
         nested_goals: NestedGoals<X>,
     ) {
@@ -55,13 +55,13 @@ impl<X: Cx> GlobalCache<X> {
         let entry = self.map.entry(input).or_default();
         if encountered_overflow {
             let with_overflow = WithOverflow { nested_goals, result };
-            let prev = entry.with_overflow.insert(additional_depth, with_overflow);
+            let prev = entry.with_overflow.insert(required_depth, with_overflow);
             if let Some(prev) = &prev {
                 assert!(cx.evaluation_is_concurrent());
                 assert_eq!(cx.get_tracked(&prev.result), origin_result);
             }
         } else {
-            let prev = entry.success.replace(Success { additional_depth, nested_goals, result });
+            let prev = entry.success.replace(Success { required_depth, nested_goals, result });
             if let Some(prev) = &prev {
                 assert!(cx.evaluation_is_concurrent());
                 assert_eq!(cx.get_tracked(&prev.result), origin_result);
@@ -81,13 +81,13 @@ impl<X: Cx> GlobalCache<X> {
         mut candidate_is_applicable: impl FnMut(&NestedGoals<X>) -> bool,
     ) -> Option<CacheData<'a, X>> {
         let entry = self.map.get(&input)?;
-        if let Some(Success { additional_depth, ref nested_goals, ref result }) = entry.success {
-            if available_depth.cache_entry_is_applicable(additional_depth)
+        if let Some(Success { required_depth, ref nested_goals, ref result }) = entry.success {
+            if available_depth.cache_entry_is_applicable(required_depth)
                 && candidate_is_applicable(nested_goals)
             {
                 return Some(CacheData {
                     result: cx.get_tracked(&result),
-                    additional_depth,
+                    required_depth,
                     encountered_overflow: false,
                     nested_goals,
                 });
@@ -101,7 +101,7 @@ impl<X: Cx> GlobalCache<X> {
             if candidate_is_applicable(nested_goals) {
                 return Some(CacheData {
                     result: cx.get_tracked(result),
-                    additional_depth,
+                    required_depth: additional_depth,
                     encountered_overflow: true,
                     nested_goals,
                 });
diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs
index 1acd5d5c2af..f0eb96b47b1 100644
--- a/compiler/rustc_type_ir/src/search_graph/mod.rs
+++ b/compiler/rustc_type_ir/src/search_graph/mod.rs
@@ -19,13 +19,14 @@ use std::hash::Hash;
 use std::marker::PhantomData;
 
 use derive_where::derive_where;
-use rustc_index::{Idx, IndexVec};
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
 use tracing::debug;
 
 use crate::data_structures::HashMap;
 
+mod stack;
+use stack::{Stack, StackDepth, StackEntry};
 mod global_cache;
 use global_cache::CacheData;
 pub use global_cache::GlobalCache;
@@ -225,9 +226,9 @@ impl AvailableDepth {
     /// in case there is exponential blowup.
     fn allowed_depth_for_nested<D: Delegate>(
         root_depth: AvailableDepth,
-        stack: &IndexVec<StackDepth, StackEntry<D::Cx>>,
+        stack: &Stack<D::Cx>,
     ) -> Option<AvailableDepth> {
-        if let Some(last) = stack.raw.last() {
+        if let Some(last) = stack.last() {
             if last.available_depth.0 == 0 {
                 return None;
             }
@@ -433,50 +434,6 @@ impl<X: Cx> NestedGoals<X> {
     }
 }
 
-rustc_index::newtype_index! {
-    #[orderable]
-    #[gate_rustc_only]
-    pub struct StackDepth {}
-}
-
-/// Stack entries of the evaluation stack. Its fields tend to be lazily
-/// when popping a child goal or completely immutable.
-#[derive_where(Debug; X: Cx)]
-struct StackEntry<X: Cx> {
-    input: X::Input,
-
-    /// Whether proving this goal is a coinductive step.
-    ///
-    /// This is used when encountering a trait solver cycle to
-    /// decide whether the initial provisional result of the cycle.
-    step_kind_from_parent: PathKind,
-
-    /// The available depth of a given goal, immutable.
-    available_depth: AvailableDepth,
-
-    /// The maximum depth reached by this stack entry, only up-to date
-    /// for the top of the stack and lazily updated for the rest.
-    reached_depth: StackDepth,
-
-    /// All cycle heads this goal depends on. Lazily updated and only
-    /// up-to date for the top of the stack.
-    heads: CycleHeads,
-
-    /// Whether evaluating this goal encountered overflow. Lazily updated.
-    encountered_overflow: bool,
-
-    /// Whether this goal has been used as the root of a cycle. This gets
-    /// eagerly updated when encountering a cycle.
-    has_been_used: Option<UsageKind>,
-
-    /// The nested goals of this goal, see the doc comment of the type.
-    nested_goals: NestedGoals<X>,
-
-    /// Starts out as `None` and gets set when rerunning this
-    /// goal in case we encounter a cycle.
-    provisional_result: Option<X::Result>,
-}
-
 /// A provisional result of an already computed goals which depends on other
 /// goals still on the stack.
 #[derive_where(Debug; X: Cx)]
@@ -498,7 +455,7 @@ pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> {
     /// The stack of goals currently being computed.
     ///
     /// An element is *deeper* in the stack if its index is *lower*.
-    stack: IndexVec<StackDepth, StackEntry<X>>,
+    stack: Stack<X>,
     /// The provisional cache contains entries for already computed goals which
     /// still depend on goals higher-up in the stack. We don't move them to the
     /// global cache and track them locally instead. A provisional cache entry
@@ -537,16 +494,16 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
     /// and using existing global cache entries to make sure they
     /// have the same impact on the remaining evaluation.
     fn update_parent_goal(
-        stack: &mut IndexVec<StackDepth, StackEntry<X>>,
+        stack: &mut Stack<X>,
         step_kind_from_parent: PathKind,
-        reached_depth: StackDepth,
+        required_depth_for_nested: usize,
         heads: &CycleHeads,
         encountered_overflow: bool,
         context: UpdateParentGoalCtxt<'_, X>,
     ) {
         if let Some(parent_index) = stack.last_index() {
             let parent = &mut stack[parent_index];
-            parent.reached_depth = parent.reached_depth.max(reached_depth);
+            parent.required_depth = parent.required_depth.max(required_depth_for_nested + 1);
             parent.encountered_overflow |= encountered_overflow;
 
             parent.heads.extend_from_child(parent_index, step_kind_from_parent, heads);
@@ -588,13 +545,11 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
     /// the stack which completes the cycle. This given an inductive step AB which then cycles
     /// coinductively with A, we need to treat this cycle as coinductive.
     fn cycle_path_kind(
-        stack: &IndexVec<StackDepth, StackEntry<X>>,
+        stack: &Stack<X>,
         step_kind_to_head: PathKind,
         head: StackDepth,
     ) -> PathKind {
-        stack.raw[head.index() + 1..]
-            .iter()
-            .fold(step_kind_to_head, |curr, entry| curr.extend(entry.step_kind_from_parent))
+        stack.cycle_step_kinds(head).fold(step_kind_to_head, |curr, step| curr.extend(step))
     }
 
     /// Probably the most involved method of the whole solver.
@@ -656,20 +611,18 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
             return result;
         }
 
-        // Unfortunate, it looks like we actually have to compute this goalrar.
-        let depth = self.stack.next_index();
-        let entry = StackEntry {
+        // Unfortunate, it looks like we actually have to compute this goal.
+        self.stack.push(StackEntry {
             input,
             step_kind_from_parent,
             available_depth,
-            reached_depth: depth,
+            required_depth: 0,
             heads: Default::default(),
             encountered_overflow: false,
             has_been_used: None,
             nested_goals: Default::default(),
             provisional_result: None,
-        };
-        assert_eq!(self.stack.push(entry), depth);
+        });
 
         // This is for global caching, so we properly track query dependencies.
         // Everything that affects the `result` should be performed within this
@@ -686,7 +639,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         Self::update_parent_goal(
             &mut self.stack,
             final_entry.step_kind_from_parent,
-            final_entry.reached_depth,
+            final_entry.required_depth,
             &final_entry.heads,
             final_entry.encountered_overflow,
             UpdateParentGoalCtxt::Ordinary(&final_entry.nested_goals),
@@ -700,7 +653,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
                 // the global cache.
                 assert_eq!(result, expected, "input={input:?}");
             } else if D::inspect_is_noop(inspect) {
-                self.insert_global_cache(cx, input, final_entry, result, dep_node)
+                self.insert_global_cache(cx, final_entry, result, dep_node)
             }
         } else if D::ENABLE_PROVISIONAL_CACHE {
             debug_assert!(validate_cache.is_none(), "unexpected non-root: {input:?}");
@@ -728,7 +681,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         input: X::Input,
         inspect: &mut D::ProofTreeBuilder,
     ) -> X::Result {
-        if let Some(last) = self.stack.raw.last_mut() {
+        if let Some(last) = self.stack.last_mut() {
             last.encountered_overflow = true;
             // If computing a goal `B` depends on another goal `A` and
             // `A` has a nested goal which overflows, then computing `B`
@@ -859,7 +812,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
                 // apply provisional cache entries which encountered overflow once the
                 // current goal is already part of the same cycle. This check could be
                 // improved but seems to be good enough for now.
-                let last = self.stack.raw.last().unwrap();
+                let last = self.stack.last().unwrap();
                 if last.heads.opt_lowest_cycle_head().is_none_or(|lowest| lowest > head) {
                     continue;
                 }
@@ -868,14 +821,10 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
             // A provisional cache entry is only valid if the current path from its
             // highest cycle head to the goal is the same.
             if path_from_head == Self::cycle_path_kind(&self.stack, step_kind_from_parent, head) {
-                // While we don't have to track the full depth of the provisional cache entry,
-                // we do have to increment the required depth by one as we'd have already failed
-                // with overflow otherwise
-                let next_index = self.stack.next_index();
                 Self::update_parent_goal(
                     &mut self.stack,
                     step_kind_from_parent,
-                    next_index,
+                    0,
                     heads,
                     encountered_overflow,
                     UpdateParentGoalCtxt::ProvisionalCacheHit,
@@ -893,7 +842,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
     /// evaluating this entry would not have ended up depending on either a goal
     /// already on the stack or a provisional cache entry.
     fn candidate_is_applicable(
-        stack: &IndexVec<StackDepth, StackEntry<X>>,
+        stack: &Stack<X>,
         step_kind_from_parent: PathKind,
         provisional_cache: &HashMap<X::Input, Vec<ProvisionalCacheEntry<X>>>,
         nested_goals: &NestedGoals<X>,
@@ -991,7 +940,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         available_depth: AvailableDepth,
     ) -> Option<X::Result> {
         cx.with_global_cache(|cache| {
-            let CacheData { result, additional_depth, encountered_overflow, nested_goals } = cache
+            let CacheData { result, required_depth, encountered_overflow, nested_goals } = cache
                 .get(cx, input, available_depth, |nested_goals| {
                     Self::candidate_is_applicable(
                         &self.stack,
@@ -1001,23 +950,19 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
                     )
                 })?;
 
-            // Update the reached depth of the current goal to make sure
-            // its state is the same regardless of whether we've used the
-            // global cache or not.
-            let reached_depth = self.stack.next_index().plus(additional_depth);
             // We don't move cycle participants to the global cache, so the
             // cycle heads are always empty.
             let heads = Default::default();
             Self::update_parent_goal(
                 &mut self.stack,
                 step_kind_from_parent,
-                reached_depth,
+                required_depth,
                 &heads,
                 encountered_overflow,
                 UpdateParentGoalCtxt::Ordinary(nested_goals),
             );
 
-            debug!(?additional_depth, "global cache hit");
+            debug!(?required_depth, "global cache hit");
             Some(result)
         })
     }
@@ -1028,7 +973,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         input: X::Input,
         step_kind_from_parent: PathKind,
     ) -> Option<X::Result> {
-        let (head, _stack_entry) = self.stack.iter_enumerated().find(|(_, e)| e.input == input)?;
+        let head = self.stack.find(input)?;
         // We have a nested goal which directly relies on a goal deeper in the stack.
         //
         // We start by tagging all cycle participants, as that's necessary for caching.
@@ -1043,10 +988,9 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
 
         // Subtle: when encountering a cyclic goal, we still first checked for overflow,
         // so we have to update the reached depth.
-        let next_index = self.stack.next_index();
         let last_index = self.stack.last_index().unwrap();
         let last = &mut self.stack[last_index];
-        last.reached_depth = last.reached_depth.max(next_index);
+        last.required_depth = last.required_depth.max(1);
 
         last.nested_goals.insert(input, step_kind_from_parent.into());
         last.nested_goals.insert(last.input, PathsToNested::EMPTY);
@@ -1095,7 +1039,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         let mut i = 0;
         loop {
             let result = evaluate_goal(self, inspect);
-            let stack_entry = self.stack.pop().unwrap();
+            let stack_entry = self.stack.pop();
             debug_assert_eq!(stack_entry.input, input);
 
             // If the current goal is not the root of a cycle, we are done.
@@ -1176,20 +1120,18 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
     fn insert_global_cache(
         &mut self,
         cx: X,
-        input: X::Input,
         final_entry: StackEntry<X>,
         result: X::Result,
         dep_node: X::DepNodeIndex,
     ) {
-        let additional_depth = final_entry.reached_depth.as_usize() - self.stack.len();
         debug!(?final_entry, ?result, "insert global cache");
         cx.with_global_cache(|cache| {
             cache.insert(
                 cx,
-                input,
+                final_entry.input,
                 result,
                 dep_node,
-                additional_depth,
+                final_entry.required_depth,
                 final_entry.encountered_overflow,
                 final_entry.nested_goals,
             )
diff --git a/compiler/rustc_type_ir/src/search_graph/stack.rs b/compiler/rustc_type_ir/src/search_graph/stack.rs
new file mode 100644
index 00000000000..8bb247bf055
--- /dev/null
+++ b/compiler/rustc_type_ir/src/search_graph/stack.rs
@@ -0,0 +1,113 @@
+use std::ops::{Index, IndexMut};
+
+use derive_where::derive_where;
+use rustc_index::IndexVec;
+
+use super::{AvailableDepth, Cx, CycleHeads, NestedGoals, PathKind, UsageKind};
+
+rustc_index::newtype_index! {
+    #[orderable]
+    #[gate_rustc_only]
+    pub(super) struct StackDepth {}
+}
+
+/// Stack entries of the evaluation stack. Its fields tend to be lazily
+/// when popping a child goal or completely immutable.
+#[derive_where(Debug; X: Cx)]
+pub(super) struct StackEntry<X: Cx> {
+    pub input: X::Input,
+
+    /// Whether proving this goal is a coinductive step.
+    ///
+    /// This is used when encountering a trait solver cycle to
+    /// decide whether the initial provisional result of the cycle.
+    pub step_kind_from_parent: PathKind,
+
+    /// The available depth of a given goal, immutable.
+    pub available_depth: AvailableDepth,
+
+    /// The maximum depth required while evaluating this goal.
+    pub required_depth: usize,
+
+    /// All cycle heads this goal depends on. Lazily updated and only
+    /// up-to date for the top of the stack.
+    pub heads: CycleHeads,
+
+    /// Whether evaluating this goal encountered overflow. Lazily updated.
+    pub encountered_overflow: bool,
+
+    /// Whether this goal has been used as the root of a cycle. This gets
+    /// eagerly updated when encountering a cycle.
+    pub has_been_used: Option<UsageKind>,
+
+    /// The nested goals of this goal, see the doc comment of the type.
+    pub nested_goals: NestedGoals<X>,
+
+    /// Starts out as `None` and gets set when rerunning this
+    /// goal in case we encounter a cycle.
+    pub provisional_result: Option<X::Result>,
+}
+
+#[derive_where(Default; X: Cx)]
+pub(super) struct Stack<X: Cx> {
+    entries: IndexVec<StackDepth, StackEntry<X>>,
+}
+
+impl<X: Cx> Stack<X> {
+    pub(super) fn is_empty(&self) -> bool {
+        self.entries.is_empty()
+    }
+
+    pub(super) fn len(&self) -> usize {
+        self.entries.len()
+    }
+
+    pub(super) fn last_index(&self) -> Option<StackDepth> {
+        self.entries.last_index()
+    }
+
+    pub(super) fn last(&self) -> Option<&StackEntry<X>> {
+        self.entries.raw.last()
+    }
+
+    pub(super) fn last_mut(&mut self) -> Option<&mut StackEntry<X>> {
+        self.entries.raw.last_mut()
+    }
+
+    pub(super) fn next_index(&self) -> StackDepth {
+        self.entries.next_index()
+    }
+
+    pub(super) fn push(&mut self, entry: StackEntry<X>) -> StackDepth {
+        self.entries.push(entry)
+    }
+
+    pub(super) fn pop(&mut self) -> StackEntry<X> {
+        self.entries.pop().unwrap()
+    }
+
+    pub(super) fn cycle_step_kinds(&self, head: StackDepth) -> impl Iterator<Item = PathKind> {
+        self.entries.raw[head.index() + 1..].iter().map(|entry| entry.step_kind_from_parent)
+    }
+
+    pub(super) fn iter(&self) -> impl Iterator<Item = &StackEntry<X>> {
+        self.entries.iter()
+    }
+
+    pub(super) fn find(&self, input: X::Input) -> Option<StackDepth> {
+        self.entries.iter_enumerated().find(|(_, e)| e.input == input).map(|(idx, _)| idx)
+    }
+}
+
+impl<X: Cx> Index<StackDepth> for Stack<X> {
+    type Output = StackEntry<X>;
+    fn index(&self, index: StackDepth) -> &StackEntry<X> {
+        &self.entries[index]
+    }
+}
+
+impl<X: Cx> IndexMut<StackDepth> for Stack<X> {
+    fn index_mut(&mut self, index: StackDepth) -> &mut Self::Output {
+        &mut self.entries[index]
+    }
+}
diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs
index 8ba985d2d19..d1ca9bdb7fb 100644
--- a/compiler/rustc_type_ir/src/ty_kind/closure.rs
+++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs
@@ -342,7 +342,7 @@ struct HasRegionsBoundAt {
 // FIXME: Could be optimized to not walk into components with no escaping bound vars.
 impl<I: Interner> TypeVisitor<I> for HasRegionsBoundAt {
     type Result = ControlFlow<()>;
-    fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
+    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
         self.binder.shift_in(1);
         t.super_visit_with(self)?;
         self.binder.shift_out(1);
diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs
index fc3864dd5ae..a96ac97f785 100644
--- a/compiler/rustc_type_ir/src/visit.rs
+++ b/compiler/rustc_type_ir/src/visit.rs
@@ -52,7 +52,7 @@ use smallvec::SmallVec;
 use thin_vec::ThinVec;
 
 use crate::inherent::*;
-use crate::{self as ty, Interner, TypeFlags, TypeFoldable};
+use crate::{self as ty, Interner, TypeFlags};
 
 /// This trait is implemented for every type that can be visited,
 /// providing the skeleton of the traversal.
@@ -94,7 +94,7 @@ pub trait TypeVisitor<I: Interner>: Sized {
     #[cfg(not(feature = "nightly"))]
     type Result: VisitorResult;
 
-    fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
+    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
         t.super_visit_with(self)
     }
 
@@ -401,7 +401,7 @@ impl std::fmt::Debug for HasTypeFlagsVisitor {
 impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor {
     type Result = ControlFlow<FoundFlags>;
 
-    fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
+    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
         // If we're looking for the HAS_BINDER_VARS flag, check if the
         // binder has vars. This won't be present in the binder's bound
         // value, so we need to check here too.
@@ -510,7 +510,7 @@ struct HasEscapingVarsVisitor {
 impl<I: Interner> TypeVisitor<I> for HasEscapingVarsVisitor {
     type Result = ControlFlow<FoundEscapingVars>;
 
-    fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
+    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
         self.outer_index.shift_in(1);
         let result = t.super_visit_with(self);
         self.outer_index.shift_out(1);
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index ce7321544b6..5bd82560da7 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -109,6 +109,11 @@ mod in_place_collect;
 
 mod partial_eq;
 
+#[unstable(feature = "vec_peek_mut", issue = "122742")]
+pub use self::peek_mut::PeekMut;
+
+mod peek_mut;
+
 #[cfg(not(no_global_oom_handling))]
 use self::spec_from_elem::SpecFromElem;
 
@@ -729,6 +734,33 @@ impl<T> Vec<T> {
     pub unsafe fn from_parts(ptr: NonNull<T>, length: usize, capacity: usize) -> Self {
         unsafe { Self::from_parts_in(ptr, length, capacity, Global) }
     }
+
+    /// Returns a mutable reference to the last item in the vector, or
+    /// `None` if it is empty.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(vec_peek_mut)]
+    /// let mut vec = Vec::new();
+    /// assert!(vec.peek_mut().is_none());
+    ///
+    /// vec.push(1);
+    /// vec.push(5);
+    /// vec.push(2);
+    /// assert_eq!(vec.last(), Some(&2));
+    /// if let Some(mut val) = vec.peek_mut() {
+    ///     *val = 0;
+    /// }
+    /// assert_eq!(vec.last(), Some(&0));
+    /// ```
+    #[inline]
+    #[unstable(feature = "vec_peek_mut", issue = "122742")]
+    pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
+        PeekMut::new(self)
+    }
 }
 
 impl<T, A: Allocator> Vec<T, A> {
diff --git a/library/alloc/src/vec/peek_mut.rs b/library/alloc/src/vec/peek_mut.rs
new file mode 100644
index 00000000000..c0dd941ed39
--- /dev/null
+++ b/library/alloc/src/vec/peek_mut.rs
@@ -0,0 +1,55 @@
+use core::ops::{Deref, DerefMut};
+
+use super::Vec;
+use crate::fmt;
+
+/// Structure wrapping a mutable reference to the last item in a
+/// `Vec`.
+///
+/// This `struct` is created by the [`peek_mut`] method on [`Vec`]. See
+/// its documentation for more.
+///
+/// [`peek_mut`]: Vec::peek_mut
+#[unstable(feature = "vec_peek_mut", issue = "122742")]
+pub struct PeekMut<'a, T> {
+    vec: &'a mut Vec<T>,
+}
+
+#[unstable(feature = "vec_peek_mut", issue = "122742")]
+impl<T: fmt::Debug> fmt::Debug for PeekMut<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("PeekMut").field(self.deref()).finish()
+    }
+}
+
+impl<'a, T> PeekMut<'a, T> {
+    pub(crate) fn new(vec: &'a mut Vec<T>) -> Option<Self> {
+        if vec.is_empty() { None } else { Some(Self { vec }) }
+    }
+
+    /// Removes the peeked value from the vector and returns it.
+    #[unstable(feature = "vec_peek_mut", issue = "122742")]
+    pub fn pop(self) -> T {
+        // SAFETY: PeekMut is only constructed if the vec is non-empty
+        unsafe { self.vec.pop().unwrap_unchecked() }
+    }
+}
+
+#[unstable(feature = "vec_peek_mut", issue = "122742")]
+impl<'a, T> Deref for PeekMut<'a, T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: PeekMut is only constructed if the vec is non-empty
+        unsafe { self.vec.get_unchecked(self.vec.len() - 1) }
+    }
+}
+
+#[unstable(feature = "vec_peek_mut", issue = "122742")]
+impl<'a, T> DerefMut for PeekMut<'a, T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        let idx = self.vec.len() - 1;
+        // SAFETY: PeekMut is only constructed if the vec is non-empty
+        unsafe { self.vec.get_unchecked_mut(idx) }
+    }
+}
diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs
index 38309585fad..a41162ecd51 100644
--- a/library/alloctests/tests/lib.rs
+++ b/library/alloctests/tests/lib.rs
@@ -40,6 +40,7 @@
 #![feature(vec_deque_truncate_front)]
 #![feature(unique_rc_arc)]
 #![feature(macro_metavar_expr_concat)]
+#![feature(vec_peek_mut)]
 #![allow(internal_features)]
 #![deny(fuzzy_provenance_casts)]
 #![deny(unsafe_op_in_unsafe_fn)]
diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs
index f430d979fa8..51b49b8edb3 100644
--- a/library/alloctests/tests/vec.rs
+++ b/library/alloctests/tests/vec.rs
@@ -2698,6 +2698,23 @@ fn test_pop_if_mutates() {
     assert_eq!(v, [2]);
 }
 
+#[test]
+fn test_peek_mut() {
+    let mut vec = Vec::new();
+    assert!(vec.peek_mut().is_none());
+    vec.push(1);
+    vec.push(2);
+    if let Some(mut p) = vec.peek_mut() {
+        assert_eq!(*p, 2);
+        *p = 0;
+        assert_eq!(*p, 0);
+        p.pop();
+        assert_eq!(vec.len(), 1);
+    } else {
+        unreachable!()
+    }
+}
+
 /// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments
 /// in the stdlib. Draining and extending the allocation are fairly well-tested earlier, but
 /// `vec.insert(usize::MAX, val)` once slipped by!
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index 7ba48cc7268..e0e80fc9b41 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -1,5 +1,9 @@
 //! Compiler intrinsics.
 //!
+//! The functions in this module are implementation details of `core` and should
+//! not be used outside of the standard library. We generally provide access to
+//! intrinsics via stable wrapper functions. Use these instead.
+//!
 //! These are the imports making intrinsics available to Rust code. The actual implementations live in the compiler.
 //! Some of these intrinsics are lowered to MIR in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_mir_transform/src/lower_intrinsics.rs>.
 //! The remaining intrinsics are implemented for the LLVM backend in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs>
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 6cbf8301e01..0cd794fd3ef 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -153,9 +153,8 @@ pub struct Metadata(fs_imp::FileAttr);
 /// dependent.
 ///
 /// # Errors
-///
-/// This [`io::Result`] will be an [`Err`] if there's some sort of intermittent
-/// IO error during iteration.
+/// This [`io::Result`] will be an [`Err`] if an error occurred while fetching
+/// the next entry from the OS.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Debug)]
 pub struct ReadDir(fs_imp::ReadDir);
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index ef776e21943..493f73b21fe 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -200,12 +200,14 @@ than building it.
         .map(|p| cmd_finder.must_have(p))
         .or_else(|| cmd_finder.maybe_have("reuse"));
 
-    let stage0_supported_target_list: HashSet<String> = crate::utils::helpers::output(
-        command(&build.config.initial_rustc).args(["--print", "target-list"]).as_command_mut(),
-    )
-    .lines()
-    .map(|s| s.to_string())
-    .collect();
+    let stage0_supported_target_list: HashSet<String> = command(&build.config.initial_rustc)
+        .args(["--print", "target-list"])
+        .run_always()
+        .run_capture_stdout(&build)
+        .stdout()
+        .lines()
+        .map(|s| s.to_string())
+        .collect();
 
     // Compiler tools like `cc` and `ar` are not configured for cross-targets on certain subcommands
     // because they are not needed.
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 25e59bfe3a8..7254c653a2d 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -21,7 +21,6 @@ use std::cell::{Cell, RefCell};
 use std::collections::{BTreeSet, HashMap, HashSet};
 use std::fmt::Display;
 use std::path::{Path, PathBuf};
-use std::process::Command;
 use std::sync::OnceLock;
 use std::time::SystemTime;
 use std::{env, fs, io, str};
@@ -39,7 +38,7 @@ use crate::core::builder::Kind;
 use crate::core::config::{DryRun, LldMode, LlvmLibunwind, TargetSelection, flags};
 use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode, command};
 use crate::utils::helpers::{
-    self, dir_is_empty, exe, libdir, output, set_file_times, split_debuginfo, symlink_dir,
+    self, dir_is_empty, exe, libdir, set_file_times, split_debuginfo, symlink_dir,
 };
 
 mod core;
@@ -376,10 +375,13 @@ impl Build {
         let in_tree_llvm_info = config.in_tree_llvm_info.clone();
         let in_tree_gcc_info = config.in_tree_gcc_info.clone();
 
-        let initial_target_libdir =
-            output(Command::new(&config.initial_rustc).args(["--print", "target-libdir"]))
-                .trim()
-                .to_owned();
+        let initial_target_libdir = command(&config.initial_rustc)
+            .run_always()
+            .args(["--print", "target-libdir"])
+            .run_capture_stdout(&config)
+            .stdout()
+            .trim()
+            .to_owned();
 
         let initial_target_dir = Path::new(&initial_target_libdir)
             .parent()
@@ -479,8 +481,11 @@ impl Build {
 
         // If local-rust is the same major.minor as the current version, then force a
         // local-rebuild
-        let local_version_verbose =
-            output(Command::new(&build.initial_rustc).arg("--version").arg("--verbose"));
+        let local_version_verbose = command(&build.initial_rustc)
+            .run_always()
+            .args(["--version", "--verbose"])
+            .run_capture_stdout(&build)
+            .stdout();
         let local_release = local_version_verbose
             .lines()
             .filter_map(|x| x.strip_prefix("release:"))
@@ -941,9 +946,14 @@ impl Build {
     fn rustc_snapshot_sysroot(&self) -> &Path {
         static SYSROOT_CACHE: OnceLock<PathBuf> = OnceLock::new();
         SYSROOT_CACHE.get_or_init(|| {
-            let mut rustc = Command::new(&self.initial_rustc);
-            rustc.args(["--print", "sysroot"]);
-            output(&mut rustc).trim().into()
+            command(&self.initial_rustc)
+                .run_always()
+                .args(["--print", "sysroot"])
+                .run_capture_stdout(self)
+                .stdout()
+                .trim()
+                .to_owned()
+                .into()
         })
     }
 
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index f2c3e8c0df4..3e04e046844 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -300,25 +300,6 @@ pub fn make(host: &str) -> PathBuf {
     }
 }
 
-#[track_caller]
-pub fn output(cmd: &mut Command) -> String {
-    #[cfg(feature = "tracing")]
-    let _run_span = crate::trace_cmd!(cmd);
-
-    let output = match cmd.stderr(Stdio::inherit()).output() {
-        Ok(status) => status,
-        Err(e) => fail(&format!("failed to execute command: {cmd:?}\nERROR: {e}")),
-    };
-    if !output.status.success() {
-        panic!(
-            "command did not execute successfully: {:?}\n\
-             expected success, got: {}",
-            cmd, output.status
-        );
-    }
-    String::from_utf8(output.stdout).unwrap()
-}
-
 /// Spawn a process and return a closure that will wait for the process
 /// to finish and then return its output. This allows the spawned process
 /// to do work without immediately blocking bootstrap.
diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
index 006a697af21..8d2c5e004e4 100644
--- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
@@ -41,7 +41,9 @@ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-require
 COPY host-x86_64/mingw-check-1/validate-toolstate.sh /scripts/
 COPY host-x86_64/mingw-check-1/validate-error-codes.sh /scripts/
 
+RUN bash -c 'npm install -g eslint@$(cat /tmp/eslint.version)'
+
 # NOTE: intentionally uses python2 for x.py so we can test it still works.
 # validate-toolstate only runs in our CI, so it's ok for it to only support python3.
-ENV SCRIPT TIDY_PRINT_DIFF=1 npm install eslint@$(head -n 1 /tmp/eslint.version) && \
- python2.7 ../x.py test --stage 0 src/tools/tidy tidyselftest --extra-checks=py,cpp
+ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test --stage 0 \
+    src/tools/tidy tidyselftest --extra-checks=py,cpp
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index a3939e5a5c4..201a5503079 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -113,6 +113,7 @@
     - [\*-unknown-openbsd](platform-support/openbsd.md)
     - [\*-unknown-redox](platform-support/redox.md)
     - [\*-unknown-uefi](platform-support/unknown-uefi.md)
+    - [\*-unknown-windows-msvc](platform-support/windows-msvc.md)
     - [\*-uwp-windows-msvc](platform-support/uwp-windows-msvc.md)
     - [\*-wrs-vxworks](platform-support/vxworks.md)
     - [wasm32-wasip1](platform-support/wasm32-wasip1.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 559e4867bbb..3cab57df75a 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -34,11 +34,11 @@ target | notes
 -------|-------
 [`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+)
 `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1+, glibc 2.17+)
-`i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
+[`i686-pc-windows-msvc`](platform-support/windows-msvc.md) | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
 `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI]
 [`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+)
 [`x86_64-pc-windows-gnu`](platform-support/windows-gnu.md) | 64-bit MinGW (Windows 10+, Windows Server 2016+)
-`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 10+, Windows Server 2016+)
+[`x86_64-pc-windows-msvc`](platform-support/windows-msvc.md) | 64-bit MSVC (Windows 10+, Windows Server 2016+)
 `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+)
 
 [^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. Functions with the default Rust ABI are not affected. See [issue #115567][x86-32-float-return-issue].
@@ -88,7 +88,7 @@ so Rustup may install the documentation for a similar tier 1 target instead.
 
 target | notes
 -------|-------
-`aarch64-pc-windows-msvc` | ARM64 Windows MSVC
+[`aarch64-pc-windows-msvc`](platform-support/windows-msvc.md) | ARM64 Windows MSVC
 `aarch64-unknown-linux-musl` | ARM64 Linux with musl 1.2.3
 [`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ARM64 OpenHarmony
 `arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2+, glibc 2.17)
diff --git a/src/doc/rustc/src/platform-support/windows-msvc.md b/src/doc/rustc/src/platform-support/windows-msvc.md
new file mode 100644
index 00000000000..71dc4ddc2e6
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/windows-msvc.md
@@ -0,0 +1,69 @@
+# `*-pc-windows-msvc`
+
+Windows MSVC targets.
+
+**Tier 1 with host tools:**
+
+- `i686-pc-windows-msvc`: Windows on 32-bit x86.
+- `x86_64-pc-windows-msvc`: Windows on 64-bit x86.
+
+**Tier 2 with host tools:**
+
+- `aarch64-pc-windows-msvc`: Windows on ARM64.
+
+## Target maintainers
+
+[@ChrisDenton](https://github.com/ChrisDenton)
+[@dpaoliello](https://github.com/dpaoliello)
+[@lambdageek](https://github.com/lambdageek)
+[@sivadeilra](https://github.com/sivadeilra)
+[@wesleywiser](https://github.com/wesleywiser)
+
+## Requirements
+
+### OS version
+
+Windows 10 or higher is required for client installs, Windows Server 2016 or higher is required for server installs.
+
+### Host tooling
+
+The minimum supported Visual Studio version is 2017 but this support is not actively tested in CI.
+It is **highly** recommended to use the latest version of VS (currently VS 2022).
+
+### Platform details
+
+These targets fully implement the Rust standard library.
+
+The `extern "C"` calling convention conforms to Microsoft's default calling convention for the given architecture: [`__cdecl`] on `i686`, [`x64`] on `x86_64` and [`ARM64`] on `aarch64`.
+
+The `*-windows-msvc` targets produce PE/COFF binaries with CodeView debuginfo, the native formats used on Windows.
+
+[`__cdecl`]: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170
+[`x64`]: https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170
+[`ARM64`]: https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170
+
+## Building Rust programs
+
+These targets are distributed via `rustup` and can be installed via `rustup component add [--toolchain {name}] {target}`.
+
+For example, adding the 32-bit x86 target to the `nightly` toolchain:
+
+```text
+rustup component add --toolchain nightly i686-pc-windows-msvc
+```
+
+or adding the ARM64 target to the active toolchain:
+
+```text
+rustup component add aarch64-pc-windows-msvc
+```
+
+## Testing
+
+There are no special requirements for testing and running this target.
+
+## Cross-compilation toolchains and C code
+
+Architectural cross-compilation from one Windows host to a different Windows platform is natively supported by the MSVC toolchain provided the appropriate components are selected when using the VS Installer.
+
+Cross-compilation from a non-Windows host to a `*-windows-msvc` target _may_ be possible but is not supported.
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index 1f0a0f2b02a..32a992ccc2d 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -20,7 +20,7 @@ use rustc_middle::traits::EvaluationResult;
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
     self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
-    GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
+    GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
     TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
 };
 use rustc_span::symbol::Ident;
@@ -853,7 +853,7 @@ pub fn for_each_top_level_late_bound_region<B>(
                 ControlFlow::Continue(())
             }
         }
-        fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) -> Self::Result {
+        fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) -> Self::Result {
             self.index += 1;
             let res = t.super_visit_with(self);
             self.index -= 1;
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index 81f5679aead..202582bea8c 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -29,6 +29,7 @@ fn path_div() -> &'static str {
 pub fn logv(config: &Config, s: String) {
     debug!("{}", s);
     if config.verbose {
+        // Note: `./x test ... --verbose --no-capture` is needed to see this print.
         println!("{}", s);
     }
 }
diff --git a/tests/codegen/retpoline.rs b/tests/codegen/retpoline.rs
index 30fdd9c2db2..915c2c3d797 100644
--- a/tests/codegen/retpoline.rs
+++ b/tests/codegen/retpoline.rs
@@ -3,18 +3,16 @@
 // `retpoline-external-thunk`, `retpoline-indirect-branches`, `retpoline-indirect-calls`
 // target features are (not) emitted when the `retpoline/retpoline-external-thunk` flag is (not) set.
 
+//@ add-core-stubs
 //@ revisions: disabled enabled_retpoline enabled_retpoline_external_thunk
 //@ needs-llvm-components: x86
 //@ compile-flags: --target x86_64-unknown-linux-gnu
 //@ [enabled_retpoline] compile-flags: -Zretpoline
 //@ [enabled_retpoline_external_thunk] compile-flags: -Zretpoline-external-thunk
-
 #![crate_type = "lib"]
-#![feature(no_core, lang_items)]
+#![feature(no_core)]
 #![no_core]
-
-#[lang = "sized"]
-trait Sized {}
+extern crate minicore;
 
 #[no_mangle]
 pub fn foo() {
diff --git a/tests/crashes/137188.rs b/tests/crashes/137188.rs
deleted file mode 100644
index fdd098d300f..00000000000
--- a/tests/crashes/137188.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//@ known-bug: #137188
-#![feature(min_generic_const_args)]
-trait Trait {}
-impl Trait for [(); N] {}
-fn N<T>() {}
-pub fn main() {}
diff --git a/tests/crashes/138166.rs b/tests/crashes/138166.rs
deleted file mode 100644
index 98003bd6dae..00000000000
--- a/tests/crashes/138166.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ known-bug: #138166
-#![feature(min_generic_const_args)]
-#![feature(inherent_associated_types)]
-struct a(Box<[u8; Box::b]>);
-impl a {
-  fn c(self) { self.0.d() }
-}
-fn main() {}
diff --git a/tests/crashes/138240.rs b/tests/crashes/138240.rs
deleted file mode 100644
index 6ffb7868bd5..00000000000
--- a/tests/crashes/138240.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ known-bug: #138240
-//@edition:2024
-#![feature(min_generic_const_args)]
-#![feature(inherent_associated_types)]
-async fn _CF() -> Box<[u8; Box::b]> {
-    Box::new(true)
-}
-
-fn main() {}
diff --git a/tests/crashes/138266.rs b/tests/crashes/138266.rs
deleted file mode 100644
index 9a4de9abcff..00000000000
--- a/tests/crashes/138266.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ known-bug: #138266
-//@compile-flags: --crate-type=lib
-#![feature(min_generic_const_args)]
-#![feature(inherent_associated_types)]
-pub fn f(mut x: [u8; Box::b]) {
-    x[72] = 1;
-}
diff --git a/tests/crashes/138359.rs b/tests/crashes/138359.rs
deleted file mode 100644
index d4376d536ee..00000000000
--- a/tests/crashes/138359.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ known-bug: #138359
-#![feature(min_generic_const_args)]
-#![feature(inherent_associated_types)]
-struct a(Box<[u8; Box::b]>);
-impl a {
-  fn c(self) { self.0.da }
-}
-fn main() {}
diff --git a/tests/ui/borrowck/issue-47646.stderr b/tests/ui/borrowck/issue-47646.stderr
index 85adfc03d10..cfe6f3f3993 100644
--- a/tests/ui/borrowck/issue-47646.stderr
+++ b/tests/ui/borrowck/issue-47646.stderr
@@ -11,7 +11,7 @@ LL |             println!("{:?}", heap);
    |                              ^^^^ immutable borrow occurs here
 ...
 LL |     };
-   |      - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(Option<PeekMut<'_, i32>>, ())`
+   |      - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(Option<std::collections::binary_heap::PeekMut<'_, i32>>, ())`
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/borrowck/issue-85581.stderr b/tests/ui/borrowck/issue-85581.stderr
index 80f1f4cb509..5fd457eb8dd 100644
--- a/tests/ui/borrowck/issue-85581.stderr
+++ b/tests/ui/borrowck/issue-85581.stderr
@@ -10,7 +10,7 @@ LL |         Some(_) => { heap.pop(); },
    |                      ^^^^ second mutable borrow occurs here
 ...
 LL | }
-   | - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<PeekMut<'_, i32>>`
+   | - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<std::collections::binary_heap::PeekMut<'_, i32>>`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/mgca/missing_generic_params.rs b/tests/ui/const-generics/mgca/missing_generic_params.rs
new file mode 100644
index 00000000000..ab1db3364ec
--- /dev/null
+++ b/tests/ui/const-generics/mgca/missing_generic_params.rs
@@ -0,0 +1,16 @@
+// This used to ICE: #137188
+// The missing parameter list on `N` was set to
+// "infer from use site" in ast lowering, which
+// caused later code to not emit a missing generic
+// param error. The missing param was then attempted
+// to be inferred, but inference of generic params
+// is only possible within bodies. So a delayed
+// bug was generated with no error ever reported.
+
+#![feature(min_generic_const_args)]
+#![allow(incomplete_features)]
+trait Trait {}
+impl Trait for [(); N] {}
+//~^ ERROR: missing generics for function `N`
+fn N<T>() {}
+pub fn main() {}
diff --git a/tests/ui/const-generics/mgca/missing_generic_params.stderr b/tests/ui/const-generics/mgca/missing_generic_params.stderr
new file mode 100644
index 00000000000..78010c75621
--- /dev/null
+++ b/tests/ui/const-generics/mgca/missing_generic_params.stderr
@@ -0,0 +1,19 @@
+error[E0107]: missing generics for function `N`
+  --> $DIR/missing_generic_params.rs:13:21
+   |
+LL | impl Trait for [(); N] {}
+   |                     ^ expected 1 generic argument
+   |
+note: function defined here, with 1 generic parameter: `T`
+  --> $DIR/missing_generic_params.rs:15:4
+   |
+LL | fn N<T>() {}
+   |    ^ -
+help: add missing generic argument
+   |
+LL | impl Trait for [(); N<T>] {}
+   |                      +++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr
new file mode 100644
index 00000000000..fca32c5c1e6
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr
@@ -0,0 +1,73 @@
+error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:16:8
+   |
+LL | extern "gpu-kernel" fn f1(_: ()) {}
+   |        ^^^^^^^^^^^^
+   |
+   = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information
+   = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:21:12
+   |
+LL |     extern "gpu-kernel" fn m1(_: ());
+   |            ^^^^^^^^^^^^
+   |
+   = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information
+   = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:23:12
+   |
+LL |     extern "gpu-kernel" fn dm1(_: ()) {}
+   |            ^^^^^^^^^^^^
+   |
+   = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information
+   = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:31:12
+   |
+LL |     extern "gpu-kernel" fn m1(_: ()) {}
+   |            ^^^^^^^^^^^^
+   |
+   = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information
+   = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:37:12
+   |
+LL |     extern "gpu-kernel" fn im1(_: ()) {}
+   |            ^^^^^^^^^^^^
+   |
+   = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information
+   = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:42:18
+   |
+LL | type A1 = extern "gpu-kernel" fn(_: ());
+   |                  ^^^^^^^^^^^^
+   |
+   = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information
+   = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:47:8
+   |
+LL | extern "gpu-kernel" {}
+   |        ^^^^^^^^^^^^
+   |
+   = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information
+   = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.stderr b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr
index aa9c67f0151..cc81289f6b7 100644
--- a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.stderr
+++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:11:8
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:16:8
    |
 LL | extern "gpu-kernel" fn f1(_: ()) {}
    |        ^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL | extern "gpu-kernel" fn f1(_: ()) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:16:12
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:21:12
    |
 LL |     extern "gpu-kernel" fn m1(_: ());
    |            ^^^^^^^^^^^^
@@ -19,7 +19,7 @@ LL |     extern "gpu-kernel" fn m1(_: ());
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:18:12
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:23:12
    |
 LL |     extern "gpu-kernel" fn dm1(_: ()) {}
    |            ^^^^^^^^^^^^
@@ -29,7 +29,7 @@ LL |     extern "gpu-kernel" fn dm1(_: ()) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:26:12
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:31:12
    |
 LL |     extern "gpu-kernel" fn m1(_: ()) {}
    |            ^^^^^^^^^^^^
@@ -39,7 +39,7 @@ LL |     extern "gpu-kernel" fn m1(_: ()) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:32:12
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:37:12
    |
 LL |     extern "gpu-kernel" fn im1(_: ()) {}
    |            ^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL |     extern "gpu-kernel" fn im1(_: ()) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:37:18
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:42:18
    |
 LL | type A1 = extern "gpu-kernel" fn(_: ());
    |                  ^^^^^^^^^^^^
@@ -59,7 +59,7 @@ LL | type A1 = extern "gpu-kernel" fn(_: ());
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:42:8
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:47:8
    |
 LL | extern "gpu-kernel" {}
    |        ^^^^^^^^^^^^
@@ -69,7 +69,7 @@ LL | extern "gpu-kernel" {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 warning: the calling convention "gpu-kernel" is not supported on this target
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:37:11
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:42:11
    |
 LL | type A1 = extern "gpu-kernel" fn(_: ());
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -79,31 +79,31 @@ LL | type A1 = extern "gpu-kernel" fn(_: ());
    = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
 
 error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:42:1
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:47:1
    |
 LL | extern "gpu-kernel" {}
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:11:1
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:16:1
    |
 LL | extern "gpu-kernel" fn f1(_: ()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:18:5
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:23:5
    |
 LL |     extern "gpu-kernel" fn dm1(_: ()) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:26:5
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:31:5
    |
 LL |     extern "gpu-kernel" fn m1(_: ()) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:32:5
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:37:5
    |
 LL |     extern "gpu-kernel" fn im1(_: ()) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -114,7 +114,7 @@ Some errors have detailed explanations: E0570, E0658.
 For more information about an error, try `rustc --explain E0570`.
 Future incompatibility report: Future breakage diagnostic:
 warning: the calling convention "gpu-kernel" is not supported on this target
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:37:11
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:42:11
    |
 LL | type A1 = extern "gpu-kernel" fn(_: ());
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr
new file mode 100644
index 00000000000..fca32c5c1e6
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr
@@ -0,0 +1,73 @@
+error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:16:8
+   |
+LL | extern "gpu-kernel" fn f1(_: ()) {}
+   |        ^^^^^^^^^^^^
+   |
+   = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information
+   = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:21:12
+   |
+LL |     extern "gpu-kernel" fn m1(_: ());
+   |            ^^^^^^^^^^^^
+   |
+   = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information
+   = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:23:12
+   |
+LL |     extern "gpu-kernel" fn dm1(_: ()) {}
+   |            ^^^^^^^^^^^^
+   |
+   = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information
+   = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:31:12
+   |
+LL |     extern "gpu-kernel" fn m1(_: ()) {}
+   |            ^^^^^^^^^^^^
+   |
+   = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information
+   = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:37:12
+   |
+LL |     extern "gpu-kernel" fn im1(_: ()) {}
+   |            ^^^^^^^^^^^^
+   |
+   = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information
+   = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:42:18
+   |
+LL | type A1 = extern "gpu-kernel" fn(_: ());
+   |                  ^^^^^^^^^^^^
+   |
+   = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information
+   = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:47:8
+   |
+LL | extern "gpu-kernel" {}
+   |        ^^^^^^^^^^^^
+   |
+   = note: see issue #135467 <https://github.com/rust-lang/rust/issues/135467> for more information
+   = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs
index d9027b417b4..7b1ee681dd7 100644
--- a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs
+++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs
@@ -1,5 +1,10 @@
+//@ revisions: HOST AMDGPU NVPTX
 //@ add-core-stubs
 //@ compile-flags: --crate-type=rlib
+//@[AMDGPU] compile-flags: --target amdgcn-amd-amdhsa -Ctarget-cpu=gfx1100
+//@[AMDGPU] needs-llvm-components: amdgpu
+//@[NVPTX]  compile-flags: --target nvptx64-nvidia-cuda
+//@[NVPTX] needs-llvm-components: nvptx
 
 #![feature(no_core, lang_items)]
 #![no_core]
@@ -9,14 +14,14 @@ use minicore::*;
 
 // Functions
 extern "gpu-kernel" fn f1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change
-//~^ ERROR is not a supported ABI
+//[HOST]~^ ERROR is not a supported ABI
 
 // Methods in trait definition
 trait Tr {
     extern "gpu-kernel" fn m1(_: ()); //~ ERROR "gpu-kernel" ABI is experimental and subject to change
 
     extern "gpu-kernel" fn dm1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change
-    //~^ ERROR is not a supported ABI
+    //[HOST]~^ ERROR is not a supported ABI
 }
 
 struct S;
@@ -24,20 +29,20 @@ struct S;
 // Methods in trait impl
 impl Tr for S {
     extern "gpu-kernel" fn m1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change
-    //~^ ERROR is not a supported ABI
+    //[HOST]~^ ERROR is not a supported ABI
 }
 
 // Methods in inherent impl
 impl S {
     extern "gpu-kernel" fn im1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change
-    //~^ ERROR is not a supported ABI
+    //[HOST]~^ ERROR is not a supported ABI
 }
 
 // Function pointer types
 type A1 = extern "gpu-kernel" fn(_: ()); //~ ERROR "gpu-kernel" ABI is experimental and subject to change
-//~^ WARN the calling convention "gpu-kernel" is not supported on this target
-//~^^ WARN this was previously accepted by the compiler but is being phased out
+//[HOST]~^ WARNING the calling convention "gpu-kernel" is not supported on this target [unsupported_fn_ptr_calling_conventions]
+//[HOST]~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 // Foreign modules
 extern "gpu-kernel" {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change
-//~^ ERROR is not a supported ABI
+//[HOST]~^ ERROR is not a supported ABI
diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.fixed b/tests/ui/parser/bad-fn-ptr-qualifier.fixed
index 8a97a2f09cc..e9b87a72aab 100644
--- a/tests/ui/parser/bad-fn-ptr-qualifier.fixed
+++ b/tests/ui/parser/bad-fn-ptr-qualifier.fixed
@@ -23,4 +23,12 @@ pub type FTT6 = for<'a> unsafe extern "C" fn();
 //~^ ERROR an `fn` pointer type cannot be `const`
 //~| ERROR an `fn` pointer type cannot be `async`
 
+// Tests with qualifiers in the wrong order
+pub type W1 = unsafe fn();
+//~^ ERROR an `fn` pointer type cannot be `const`
+pub type W2 = unsafe fn();
+//~^ ERROR an `fn` pointer type cannot be `async`
+pub type W3 = for<'a> unsafe fn();
+//~^ ERROR an `fn` pointer type cannot be `const`
+
 fn main() {}
diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.rs b/tests/ui/parser/bad-fn-ptr-qualifier.rs
index f2611c93b17..f110375509c 100644
--- a/tests/ui/parser/bad-fn-ptr-qualifier.rs
+++ b/tests/ui/parser/bad-fn-ptr-qualifier.rs
@@ -23,4 +23,12 @@ pub type FTT6 = for<'a> const async unsafe extern "C" fn();
 //~^ ERROR an `fn` pointer type cannot be `const`
 //~| ERROR an `fn` pointer type cannot be `async`
 
+// Tests with qualifiers in the wrong order
+pub type W1 = unsafe const fn();
+//~^ ERROR an `fn` pointer type cannot be `const`
+pub type W2 = unsafe async fn();
+//~^ ERROR an `fn` pointer type cannot be `async`
+pub type W3 = for<'a> unsafe const fn();
+//~^ ERROR an `fn` pointer type cannot be `const`
+
 fn main() {}
diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.stderr b/tests/ui/parser/bad-fn-ptr-qualifier.stderr
index b9d2625d9f4..f3fbbf67159 100644
--- a/tests/ui/parser/bad-fn-ptr-qualifier.stderr
+++ b/tests/ui/parser/bad-fn-ptr-qualifier.stderr
@@ -2,10 +2,9 @@ error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:5:15
    |
 LL | pub type T0 = const fn();
-   |               -----^^^^^
-   |               |
-   |               `const` because of this
+   |               ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type T0 = const fn();
@@ -16,10 +15,9 @@ error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:6:15
    |
 LL | pub type T1 = const extern "C" fn();
-   |               -----^^^^^^^^^^^^^^^^
-   |               |
-   |               `const` because of this
+   |               ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type T1 = const extern "C" fn();
@@ -30,10 +28,9 @@ error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:7:15
    |
 LL | pub type T2 = const unsafe extern "C" fn();
-   |               -----^^^^^^^^^^^^^^^^^^^^^^^
-   |               |
-   |               `const` because of this
+   |               ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type T2 = const unsafe extern "C" fn();
@@ -44,10 +41,9 @@ error: an `fn` pointer type cannot be `async`
   --> $DIR/bad-fn-ptr-qualifier.rs:8:15
    |
 LL | pub type T3 = async fn();
-   |               -----^^^^^
-   |               |
-   |               `async` because of this
+   |               ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type T3 = async fn();
@@ -58,10 +54,9 @@ error: an `fn` pointer type cannot be `async`
   --> $DIR/bad-fn-ptr-qualifier.rs:9:15
    |
 LL | pub type T4 = async extern "C" fn();
-   |               -----^^^^^^^^^^^^^^^^
-   |               |
-   |               `async` because of this
+   |               ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type T4 = async extern "C" fn();
@@ -72,10 +67,9 @@ error: an `fn` pointer type cannot be `async`
   --> $DIR/bad-fn-ptr-qualifier.rs:10:15
    |
 LL | pub type T5 = async unsafe extern "C" fn();
-   |               -----^^^^^^^^^^^^^^^^^^^^^^^
-   |               |
-   |               `async` because of this
+   |               ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type T5 = async unsafe extern "C" fn();
@@ -86,10 +80,9 @@ error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:11:15
    |
 LL | pub type T6 = const async unsafe extern "C" fn();
-   |               -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |               |
-   |               `const` because of this
+   |               ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type T6 = const async unsafe extern "C" fn();
@@ -97,13 +90,12 @@ LL + pub type T6 = async unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/bad-fn-ptr-qualifier.rs:11:15
+  --> $DIR/bad-fn-ptr-qualifier.rs:11:21
    |
 LL | pub type T6 = const async unsafe extern "C" fn();
-   |               ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
-   |                     |
-   |                     `async` because of this
+   |                     ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type T6 = const async unsafe extern "C" fn();
@@ -111,13 +103,12 @@ LL + pub type T6 = const unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/bad-fn-ptr-qualifier.rs:15:17
+  --> $DIR/bad-fn-ptr-qualifier.rs:15:25
    |
 LL | pub type FTT0 = for<'a> const fn();
-   |                 ^^^^^^^^-----^^^^^
-   |                         |
-   |                         `const` because of this
+   |                         ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type FTT0 = for<'a> const fn();
@@ -125,13 +116,12 @@ LL + pub type FTT0 = for<'a> fn();
    |
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/bad-fn-ptr-qualifier.rs:16:17
+  --> $DIR/bad-fn-ptr-qualifier.rs:16:25
    |
 LL | pub type FTT1 = for<'a> const extern "C" fn();
-   |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^
-   |                         |
-   |                         `const` because of this
+   |                         ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type FTT1 = for<'a> const extern "C" fn();
@@ -139,13 +129,12 @@ LL + pub type FTT1 = for<'a> extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/bad-fn-ptr-qualifier.rs:17:17
+  --> $DIR/bad-fn-ptr-qualifier.rs:17:25
    |
 LL | pub type FTT2 = for<'a> const unsafe extern "C" fn();
-   |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
-   |                         |
-   |                         `const` because of this
+   |                         ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type FTT2 = for<'a> const unsafe extern "C" fn();
@@ -153,13 +142,12 @@ LL + pub type FTT2 = for<'a> unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/bad-fn-ptr-qualifier.rs:18:17
+  --> $DIR/bad-fn-ptr-qualifier.rs:18:25
    |
 LL | pub type FTT3 = for<'a> async fn();
-   |                 ^^^^^^^^-----^^^^^
-   |                         |
-   |                         `async` because of this
+   |                         ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type FTT3 = for<'a> async fn();
@@ -167,13 +155,12 @@ LL + pub type FTT3 = for<'a> fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/bad-fn-ptr-qualifier.rs:19:17
+  --> $DIR/bad-fn-ptr-qualifier.rs:19:25
    |
 LL | pub type FTT4 = for<'a> async extern "C" fn();
-   |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^
-   |                         |
-   |                         `async` because of this
+   |                         ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type FTT4 = for<'a> async extern "C" fn();
@@ -181,13 +168,12 @@ LL + pub type FTT4 = for<'a> extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/bad-fn-ptr-qualifier.rs:20:17
+  --> $DIR/bad-fn-ptr-qualifier.rs:20:25
    |
 LL | pub type FTT5 = for<'a> async unsafe extern "C" fn();
-   |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
-   |                         |
-   |                         `async` because of this
+   |                         ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type FTT5 = for<'a> async unsafe extern "C" fn();
@@ -195,13 +181,12 @@ LL + pub type FTT5 = for<'a> unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/bad-fn-ptr-qualifier.rs:22:17
+  --> $DIR/bad-fn-ptr-qualifier.rs:22:25
    |
 LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn();
-   |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                         |
-   |                         `const` because of this
+   |                         ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn();
@@ -209,18 +194,56 @@ LL + pub type FTT6 = for<'a> async unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/bad-fn-ptr-qualifier.rs:22:17
+  --> $DIR/bad-fn-ptr-qualifier.rs:22:31
    |
 LL | pub type FTT6 = for<'a> const async unsafe extern "C" fn();
-   |                 ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
-   |                               |
-   |                               `async` because of this
+   |                               ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - pub type FTT6 = for<'a> const async unsafe extern "C" fn();
 LL + pub type FTT6 = for<'a> const unsafe extern "C" fn();
    |
 
-error: aborting due to 16 previous errors
+error: an `fn` pointer type cannot be `const`
+  --> $DIR/bad-fn-ptr-qualifier.rs:27:22
+   |
+LL | pub type W1 = unsafe const fn();
+   |                      ^^^^^ `const` because of this
+   |
+   = note: allowed qualifiers are: `unsafe` and `extern`
+help: remove the `const` qualifier
+   |
+LL - pub type W1 = unsafe const fn();
+LL + pub type W1 = unsafe fn();
+   |
+
+error: an `fn` pointer type cannot be `async`
+  --> $DIR/bad-fn-ptr-qualifier.rs:29:22
+   |
+LL | pub type W2 = unsafe async fn();
+   |                      ^^^^^ `async` because of this
+   |
+   = note: allowed qualifiers are: `unsafe` and `extern`
+help: remove the `async` qualifier
+   |
+LL - pub type W2 = unsafe async fn();
+LL + pub type W2 = unsafe fn();
+   |
+
+error: an `fn` pointer type cannot be `const`
+  --> $DIR/bad-fn-ptr-qualifier.rs:31:30
+   |
+LL | pub type W3 = for<'a> unsafe const fn();
+   |                              ^^^^^ `const` because of this
+   |
+   = note: allowed qualifiers are: `unsafe` and `extern`
+help: remove the `const` qualifier
+   |
+LL - pub type W3 = for<'a> unsafe const fn();
+LL + pub type W3 = for<'a> unsafe fn();
+   |
+
+error: aborting due to 19 previous errors
 
diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.rs b/tests/ui/parser/recover/recover-const-async-fn-ptr.rs
index 45d75349599..a74b618c282 100644
--- a/tests/ui/parser/recover/recover-const-async-fn-ptr.rs
+++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.rs
@@ -20,6 +20,14 @@ type FT6 = for<'a> const async unsafe extern "C" fn();
 //~^ ERROR an `fn` pointer type cannot be `const`
 //~| ERROR an `fn` pointer type cannot be `async`
 
+// Tests with qualifiers in the wrong order
+type W1 = unsafe const fn();
+//~^ ERROR an `fn` pointer type cannot be `const`
+type W2 = unsafe async fn();
+//~^ ERROR an `fn` pointer type cannot be `async`
+type W3 = for<'a> unsafe const fn();
+//~^ ERROR an `fn` pointer type cannot be `const`
+
 fn main() {
     let _recovery_witness: () = 0; //~ ERROR mismatched types
 }
diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
index 4e5927914cc..3700bee6e15 100644
--- a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
+++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
@@ -2,10 +2,9 @@ error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:3:11
    |
 LL | type T0 = const fn();
-   |           -----^^^^^
-   |           |
-   |           `const` because of this
+   |           ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type T0 = const fn();
@@ -16,10 +15,9 @@ error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:4:11
    |
 LL | type T1 = const extern "C" fn();
-   |           -----^^^^^^^^^^^^^^^^
-   |           |
-   |           `const` because of this
+   |           ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type T1 = const extern "C" fn();
@@ -30,10 +28,9 @@ error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:5:11
    |
 LL | type T2 = const unsafe extern "C" fn();
-   |           -----^^^^^^^^^^^^^^^^^^^^^^^
-   |           |
-   |           `const` because of this
+   |           ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type T2 = const unsafe extern "C" fn();
@@ -44,10 +41,9 @@ error: an `fn` pointer type cannot be `async`
   --> $DIR/recover-const-async-fn-ptr.rs:6:11
    |
 LL | type T3 = async fn();
-   |           -----^^^^^
-   |           |
-   |           `async` because of this
+   |           ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type T3 = async fn();
@@ -58,10 +54,9 @@ error: an `fn` pointer type cannot be `async`
   --> $DIR/recover-const-async-fn-ptr.rs:7:11
    |
 LL | type T4 = async extern "C" fn();
-   |           -----^^^^^^^^^^^^^^^^
-   |           |
-   |           `async` because of this
+   |           ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type T4 = async extern "C" fn();
@@ -72,10 +67,9 @@ error: an `fn` pointer type cannot be `async`
   --> $DIR/recover-const-async-fn-ptr.rs:8:11
    |
 LL | type T5 = async unsafe extern "C" fn();
-   |           -----^^^^^^^^^^^^^^^^^^^^^^^
-   |           |
-   |           `async` because of this
+   |           ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type T5 = async unsafe extern "C" fn();
@@ -86,10 +80,9 @@ error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:9:11
    |
 LL | type T6 = const async unsafe extern "C" fn();
-   |           -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |           |
-   |           `const` because of this
+   |           ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type T6 = const async unsafe extern "C" fn();
@@ -97,13 +90,12 @@ LL + type T6 = async unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/recover-const-async-fn-ptr.rs:9:11
+  --> $DIR/recover-const-async-fn-ptr.rs:9:17
    |
 LL | type T6 = const async unsafe extern "C" fn();
-   |           ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
-   |                 |
-   |                 `async` because of this
+   |                 ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type T6 = const async unsafe extern "C" fn();
@@ -111,13 +103,12 @@ LL + type T6 = const unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/recover-const-async-fn-ptr.rs:13:12
+  --> $DIR/recover-const-async-fn-ptr.rs:13:20
    |
 LL | type FT0 = for<'a> const fn();
-   |            ^^^^^^^^-----^^^^^
-   |                    |
-   |                    `const` because of this
+   |                    ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type FT0 = for<'a> const fn();
@@ -125,13 +116,12 @@ LL + type FT0 = for<'a> fn();
    |
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/recover-const-async-fn-ptr.rs:14:12
+  --> $DIR/recover-const-async-fn-ptr.rs:14:20
    |
 LL | type FT1 = for<'a> const extern "C" fn();
-   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^
-   |                    |
-   |                    `const` because of this
+   |                    ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type FT1 = for<'a> const extern "C" fn();
@@ -139,13 +129,12 @@ LL + type FT1 = for<'a> extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/recover-const-async-fn-ptr.rs:15:12
+  --> $DIR/recover-const-async-fn-ptr.rs:15:20
    |
 LL | type FT2 = for<'a> const unsafe extern "C" fn();
-   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
-   |                    |
-   |                    `const` because of this
+   |                    ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type FT2 = for<'a> const unsafe extern "C" fn();
@@ -153,13 +142,12 @@ LL + type FT2 = for<'a> unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/recover-const-async-fn-ptr.rs:16:12
+  --> $DIR/recover-const-async-fn-ptr.rs:16:20
    |
 LL | type FT3 = for<'a> async fn();
-   |            ^^^^^^^^-----^^^^^
-   |                    |
-   |                    `async` because of this
+   |                    ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type FT3 = for<'a> async fn();
@@ -167,13 +155,12 @@ LL + type FT3 = for<'a> fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/recover-const-async-fn-ptr.rs:17:12
+  --> $DIR/recover-const-async-fn-ptr.rs:17:20
    |
 LL | type FT4 = for<'a> async extern "C" fn();
-   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^
-   |                    |
-   |                    `async` because of this
+   |                    ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type FT4 = for<'a> async extern "C" fn();
@@ -181,13 +168,12 @@ LL + type FT4 = for<'a> extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/recover-const-async-fn-ptr.rs:18:12
+  --> $DIR/recover-const-async-fn-ptr.rs:18:20
    |
 LL | type FT5 = for<'a> async unsafe extern "C" fn();
-   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
-   |                    |
-   |                    `async` because of this
+   |                    ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type FT5 = for<'a> async unsafe extern "C" fn();
@@ -195,13 +181,12 @@ LL + type FT5 = for<'a> unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `const`
-  --> $DIR/recover-const-async-fn-ptr.rs:19:12
+  --> $DIR/recover-const-async-fn-ptr.rs:19:20
    |
 LL | type FT6 = for<'a> const async unsafe extern "C" fn();
-   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                    |
-   |                    `const` because of this
+   |                    ^^^^^ `const` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `const` qualifier
    |
 LL - type FT6 = for<'a> const async unsafe extern "C" fn();
@@ -209,27 +194,65 @@ LL + type FT6 = for<'a> async unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
-  --> $DIR/recover-const-async-fn-ptr.rs:19:12
+  --> $DIR/recover-const-async-fn-ptr.rs:19:26
    |
 LL | type FT6 = for<'a> const async unsafe extern "C" fn();
-   |            ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
-   |                          |
-   |                          `async` because of this
+   |                          ^^^^^ `async` because of this
    |
+   = note: allowed qualifiers are: `unsafe` and `extern`
 help: remove the `async` qualifier
    |
 LL - type FT6 = for<'a> const async unsafe extern "C" fn();
 LL + type FT6 = for<'a> const unsafe extern "C" fn();
    |
 
+error: an `fn` pointer type cannot be `const`
+  --> $DIR/recover-const-async-fn-ptr.rs:24:18
+   |
+LL | type W1 = unsafe const fn();
+   |                  ^^^^^ `const` because of this
+   |
+   = note: allowed qualifiers are: `unsafe` and `extern`
+help: remove the `const` qualifier
+   |
+LL - type W1 = unsafe const fn();
+LL + type W1 = unsafe fn();
+   |
+
+error: an `fn` pointer type cannot be `async`
+  --> $DIR/recover-const-async-fn-ptr.rs:26:18
+   |
+LL | type W2 = unsafe async fn();
+   |                  ^^^^^ `async` because of this
+   |
+   = note: allowed qualifiers are: `unsafe` and `extern`
+help: remove the `async` qualifier
+   |
+LL - type W2 = unsafe async fn();
+LL + type W2 = unsafe fn();
+   |
+
+error: an `fn` pointer type cannot be `const`
+  --> $DIR/recover-const-async-fn-ptr.rs:28:26
+   |
+LL | type W3 = for<'a> unsafe const fn();
+   |                          ^^^^^ `const` because of this
+   |
+   = note: allowed qualifiers are: `unsafe` and `extern`
+help: remove the `const` qualifier
+   |
+LL - type W3 = for<'a> unsafe const fn();
+LL + type W3 = for<'a> unsafe fn();
+   |
+
 error[E0308]: mismatched types
-  --> $DIR/recover-const-async-fn-ptr.rs:24:33
+  --> $DIR/recover-const-async-fn-ptr.rs:32:33
    |
 LL |     let _recovery_witness: () = 0;
    |                            --   ^ expected `()`, found integer
    |                            |
    |                            expected due to this
 
-error: aborting due to 17 previous errors
+error: aborting due to 20 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.rs b/tests/ui/target-feature/retpoline-target-feature-flag.rs
index 3e614a4236c..de3c44c3ed0 100644
--- a/tests/ui/target-feature/retpoline-target-feature-flag.rs
+++ b/tests/ui/target-feature/retpoline-target-feature-flag.rs
@@ -1,3 +1,4 @@
+//@ add-core-stubs
 //@ revisions: by_flag by_feature1 by_feature2 by_feature3
 //@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
 //@ needs-llvm-components: x86
@@ -11,12 +12,9 @@
 //@ [by_feature1]build-pass
 //@ [by_feature2]build-pass
 //@ [by_feature3]build-pass
-#![feature(no_core, lang_items)]
-#![no_std]
+#![feature(no_core)]
 #![no_core]
-
-#[lang = "sized"]
-pub trait Sized {}
+extern crate minicore;
 
 //[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead
 //[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
diff --git a/tests/ui/traits/object/no-incomplete-inference.current.stderr b/tests/ui/traits/object/no-incomplete-inference.current.stderr
new file mode 100644
index 00000000000..3c6b811a49e
--- /dev/null
+++ b/tests/ui/traits/object/no-incomplete-inference.current.stderr
@@ -0,0 +1,16 @@
+error[E0283]: type annotations needed
+  --> $DIR/no-incomplete-inference.rs:16:5
+   |
+LL |     impls_equals::<dyn Equals<u32>, _>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_equals`
+   |
+   = note: cannot satisfy `dyn Equals<u32>: Equals<_>`
+note: required by a bound in `impls_equals`
+  --> $DIR/no-incomplete-inference.rs:13:20
+   |
+LL | fn impls_equals<T: Equals<U> + ?Sized, U: ?Sized>() {}
+   |                    ^^^^^^^^^ required by this bound in `impls_equals`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/object/no-incomplete-inference.next.stderr b/tests/ui/traits/object/no-incomplete-inference.next.stderr
new file mode 100644
index 00000000000..3c6b811a49e
--- /dev/null
+++ b/tests/ui/traits/object/no-incomplete-inference.next.stderr
@@ -0,0 +1,16 @@
+error[E0283]: type annotations needed
+  --> $DIR/no-incomplete-inference.rs:16:5
+   |
+LL |     impls_equals::<dyn Equals<u32>, _>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_equals`
+   |
+   = note: cannot satisfy `dyn Equals<u32>: Equals<_>`
+note: required by a bound in `impls_equals`
+  --> $DIR/no-incomplete-inference.rs:13:20
+   |
+LL | fn impls_equals<T: Equals<U> + ?Sized, U: ?Sized>() {}
+   |                    ^^^^^^^^^ required by this bound in `impls_equals`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/object/no-incomplete-inference.rs b/tests/ui/traits/object/no-incomplete-inference.rs
new file mode 100644
index 00000000000..9ed8dd6c0b1
--- /dev/null
+++ b/tests/ui/traits/object/no-incomplete-inference.rs
@@ -0,0 +1,18 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+
+// Make sure that having an applicable user-written
+// and builtin impl is ambiguous.
+
+trait Equals<T: ?Sized> {}
+
+impl<T: ?Sized> Equals<T> for T {}
+
+fn impls_equals<T: Equals<U> + ?Sized, U: ?Sized>() {}
+
+fn main() {
+    impls_equals::<dyn Equals<u32>, _>();
+    //~^ ERROR type annotations needed
+}