about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock37
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs2
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl2
-rw-r--r--compiler/rustc_builtin_macros/src/alloc_error_handler.rs97
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs7
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/example/alloc_example.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/allocator.rs23
-rw-r--r--compiler/rustc_codegen_gcc/example/alloc_example.rs7
-rw-r--r--compiler/rustc_codegen_gcc/src/allocator.rs34
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs5
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs48
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs1
-rw-r--r--compiler/rustc_data_structures/src/lib.rs1
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr.rs31
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs144
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs34
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs88
-rw-r--r--compiler/rustc_driver_impl/src/print.rs20
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_feature/src/removed.rs2
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl37
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs160
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs22
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs138
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs3
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs2
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs2
-rw-r--r--compiler/rustc_interface/src/tests.rs2
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs4
-rw-r--r--compiler/rustc_lint/src/unused.rs2
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp5
-rw-r--r--compiler/rustc_metadata/messages.ftl10
-rw-r--r--compiler/rustc_metadata/src/creader.rs68
-rw-r--r--compiler/rustc_metadata/src/errors.rs17
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs45
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs5
-rw-r--r--compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs3
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs3
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs1
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs13
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs10
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs34
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs2
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs12
-rw-r--r--compiler/rustc_middle/src/ty/util.rs7
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs2
-rw-r--r--compiler/rustc_privacy/src/lib.rs4
-rw-r--r--compiler/rustc_query_impl/src/on_disk_cache.rs56
-rw-r--r--compiler/rustc_query_system/src/dep_graph/serialized.rs16
-rw-r--r--compiler/rustc_serialize/src/leb128.rs16
-rw-r--r--compiler/rustc_serialize/src/lib.rs1
-rw-r--r--compiler/rustc_serialize/src/opaque.rs155
-rw-r--r--compiler/rustc_serialize/src/serialize.rs2
-rw-r--r--compiler/rustc_serialize/tests/leb128.rs13
-rw-r--r--compiler/rustc_session/src/config.rs6
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_target/src/asm/loongarch.rs131
-rw-r--r--compiler/rustc_target/src/asm/mod.rs26
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs72
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs1084
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs26
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs4
-rw-r--r--compiler/rustc_traits/src/chalk/db.rs19
-rw-r--r--compiler/rustc_type_ir/src/codec.rs7
-rw-r--r--compiler/rustc_type_ir/src/lib.rs6
-rw-r--r--library/alloc/Cargo.toml3
-rw-r--r--library/alloc/src/alloc.rs94
-rw-r--r--library/alloc/src/collections/linked_list.rs359
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/task.rs3
-rw-r--r--library/core/benches/num/flt2dec/strategy/grisu.rs27
-rw-r--r--library/core/src/cell/lazy.rs28
-rw-r--r--library/core/src/macros/mod.rs10
-rw-r--r--library/core/src/num/flt2dec/strategy/grisu.rs16
-rw-r--r--library/core/src/prelude/v1.rs4
-rw-r--r--library/core/src/slice/sort.rs1
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/src/alloc.rs73
-rw-r--r--library/std/src/lib.rs2
-rw-r--r--library/std/src/panicking.rs43
-rw-r--r--library/std/src/prelude/v1.rs4
-rw-r--r--library/std/src/sync/lazy_lock.rs38
-rwxr-xr-xsrc/bootstrap/configure.py4
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile4
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile4
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile4
-rwxr-xr-xsrc/ci/run.sh6
m---------src/doc/book0
m---------src/doc/embedded-book0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/unstable-book/src/language-features/asm-experimental-arch.md17
-rw-r--r--src/librustdoc/clean/mod.rs13
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs4
-rw-r--r--tests/assembly/asm/loongarch-type.rs196
-rw-r--r--tests/debuginfo/pretty-std.rs4
-rw-r--r--tests/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir56
-rw-r--r--tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir34
-rw-r--r--tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir34
-rw-r--r--tests/mir-opt/storage_ranges.main.nll.0.mir22
-rw-r--r--tests/run-make/coverage-reports/expected_show_coverage.issue-84561.txt6
-rw-r--r--tests/run-make/issue-51671/Makefile1
-rw-r--r--tests/run-make/issue-51671/app.rs7
-rw-r--r--tests/run-make/issue-69368/Makefile19
-rw-r--r--tests/run-make/issue-69368/a.rs26
-rw-r--r--tests/run-make/issue-69368/b.rs8
-rw-r--r--tests/run-make/issue-69368/c.rs34
-rw-r--r--tests/run-make/wasm-symbols-not-exported/bar.rs7
-rw-r--r--tests/ui/alloc-error/alloc-error-handler-bad-signature-1.rs18
-rw-r--r--tests/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr44
-rw-r--r--tests/ui/alloc-error/alloc-error-handler-bad-signature-2.rs17
-rw-r--r--tests/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr50
-rw-r--r--tests/ui/alloc-error/alloc-error-handler-bad-signature-3.rs15
-rw-r--r--tests/ui/alloc-error/alloc-error-handler-bad-signature-3.stderr21
-rw-r--r--tests/ui/alloc-error/default-alloc-error-hook.rs4
-rw-r--r--tests/ui/allocator/no_std-alloc-error-handler-custom.rs84
-rw-r--r--tests/ui/associated-types/substs-ppaux.verbose.stderr2
-rw-r--r--tests/ui/closures/binder/nested-closures-regions.stderr10
-rw-r--r--tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr2
-rw-r--r--tests/ui/closures/print/closure-print-generic-verbose-1.stderr2
-rw-r--r--tests/ui/closures/print/closure-print-generic-verbose-2.stderr2
-rw-r--r--tests/ui/closures/print/closure-print-verbose.stderr2
-rw-r--r--tests/ui/const-generics/occurs-check/unused-substs-2.rs8
-rw-r--r--tests/ui/const-generics/occurs-check/unused-substs-3.rs8
-rw-r--r--tests/ui/feature-gates/feature-gate-alloc-error-handler.rs16
-rw-r--r--tests/ui/feature-gates/feature-gate-alloc-error-handler.stderr12
-rw-r--r--tests/ui/generator/issue-57084.rs2
-rw-r--r--tests/ui/impl-trait/wf-eval-order.rs4
-rw-r--r--tests/ui/missing/missing-allocator.rs6
-rw-r--r--tests/ui/nll/closure-requirements/escape-argument-callee.stderr2
-rw-r--r--tests/ui/nll/closure-requirements/escape-upvar-nested.stderr8
-rw-r--r--tests/ui/nll/closure-requirements/escape-upvar-ref.stderr4
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr12
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr8
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr6
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr10
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr10
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-val.stderr8
-rw-r--r--tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr6
-rw-r--r--tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr10
-rw-r--r--tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr10
-rw-r--r--tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr6
-rw-r--r--tests/ui/nll/member-constraints/min-choice.rs4
-rw-r--r--tests/ui/nll/member-constraints/nested-impl-trait-fail.rs6
-rw-r--r--tests/ui/nll/member-constraints/nested-impl-trait-pass.rs6
-rw-r--r--tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr32
-rw-r--r--tests/ui/nll/ty-outlives/projection-one-region-closure.stderr40
-rw-r--r--tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr42
-rw-r--r--tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr32
-rw-r--r--tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr82
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr10
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs4
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr8
-rw-r--r--tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr32
-rw-r--r--tests/ui/oom_unwind.rs2
-rw-r--r--tests/ui/repr/repr-transparent.stderr2
-rw-r--r--tests/ui/repr/transparent-enum-too-many-variants.stderr2
-rw-r--r--tests/ui/traits/infer-from-object-issue-26952.rs4
-rw-r--r--tests/ui/traits/new-solver/int-var-alias-eq.rs2
-rw-r--r--tests/ui/traits/new-solver/negative-coherence-bounds.rs40
-rw-r--r--tests/ui/traits/new-solver/negative-coherence-bounds.stderr12
-rw-r--r--tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/closure_parent_substs.rs10
185 files changed, 3551 insertions, 1400 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 696727c106b..c58147ad757 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1170,13 +1170,13 @@ dependencies = [
 
 [[package]]
 name = "errno"
-version = "0.2.8"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
+checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
 dependencies = [
  "errno-dragonfly",
  "libc",
- "winapi",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -1831,14 +1831,14 @@ dependencies = [
 
 [[package]]
 name = "is-terminal"
-version = "0.4.4"
+version = "0.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857"
+checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
 dependencies = [
  "hermit-abi 0.3.0",
  "io-lifetimes",
  "rustix",
- "windows-sys 0.45.0",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -2025,9 +2025,9 @@ dependencies = [
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.1.4"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
+checksum = "36eb31c1778188ae1e64398743890d0877fef36d11521ac60406b42016e8c2cf"
 
 [[package]]
 name = "litemap"
@@ -4350,16 +4350,16 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.36.5"
+version = "0.37.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
+checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d"
 dependencies = [
  "bitflags",
  "errno",
  "io-lifetimes",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.42.0",
+ "windows-sys 0.45.0",
 ]
 
 [[package]]
@@ -4791,12 +4791,12 @@ dependencies = [
 
 [[package]]
 name = "terminal_size"
-version = "0.2.3"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
+checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237"
 dependencies = [
  "rustix",
- "windows-sys 0.42.0",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -5514,6 +5514,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.0",
+]
+
+[[package]]
 name = "windows-targets"
 version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 8dd03aaa72d..5db0f72919d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -702,7 +702,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 .copied()
                 .find_map(find_fn_kind_from_did),
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx
-                .bound_explicit_item_bounds(def_id)
+                .explicit_item_bounds(def_id)
                 .subst_iter_copied(tcx, substs)
                 .find_map(find_fn_kind_from_did),
             ty::Closure(_, substs) => match substs.as_closure().kind() {
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index ee2aca6fc93..fca6012a408 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -4,6 +4,8 @@ builtin_macros_requires_cfg_pattern =
 
 builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern
 
+builtin_macros_alloc_error_must_be_fn = alloc_error_handler must be a function
+
 builtin_macros_assert_requires_boolean = macro requires a boolean expression as an argument
     .label = boolean expression required
 
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
new file mode 100644
index 00000000000..82bae9157e7
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
@@ -0,0 +1,97 @@
+use crate::errors;
+use crate::util::check_builtin_macro_attribute;
+
+use rustc_ast::ptr::P;
+use rustc_ast::{self as ast, FnHeader, FnSig, Generics, StmtKind};
+use rustc_ast::{Fn, ItemKind, Stmt, TyKind, Unsafe};
+use rustc_expand::base::{Annotatable, ExtCtxt};
+use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::Span;
+use thin_vec::{thin_vec, ThinVec};
+
+pub fn expand(
+    ecx: &mut ExtCtxt<'_>,
+    _span: Span,
+    meta_item: &ast::MetaItem,
+    item: Annotatable,
+) -> Vec<Annotatable> {
+    check_builtin_macro_attribute(ecx, meta_item, sym::alloc_error_handler);
+
+    let orig_item = item.clone();
+
+    // Allow using `#[alloc_error_handler]` on an item statement
+    // FIXME - if we get deref patterns, use them to reduce duplication here
+    let (item, is_stmt, sig_span) =
+        if let Annotatable::Item(item) = &item
+            && let ItemKind::Fn(fn_kind) = &item.kind
+        {
+            (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span))
+        } else if let Annotatable::Stmt(stmt) = &item
+            && let StmtKind::Item(item) = &stmt.kind
+            && let ItemKind::Fn(fn_kind) = &item.kind
+        {
+            (item, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
+        } else {
+            ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocErrorMustBeFn {span: item.span() });
+            return vec![orig_item];
+        };
+
+    // Generate a bunch of new items using the AllocFnFactory
+    let span = ecx.with_def_site_ctxt(item.span);
+
+    // Generate item statements for the allocator methods.
+    let stmts = thin_vec![generate_handler(ecx, item.ident, span, sig_span)];
+
+    // Generate anonymous constant serving as container for the allocator methods.
+    let const_ty = ecx.ty(sig_span, TyKind::Tup(ThinVec::new()));
+    let const_body = ecx.expr_block(ecx.block(span, stmts));
+    let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
+    let const_item = if is_stmt {
+        Annotatable::Stmt(P(ecx.stmt_item(span, const_item)))
+    } else {
+        Annotatable::Item(const_item)
+    };
+
+    // Return the original item and the new methods.
+    vec![orig_item, const_item]
+}
+
+// #[rustc_std_internal_symbol]
+// unsafe fn __rg_oom(size: usize, align: usize) -> ! {
+//     handler(core::alloc::Layout::from_size_align_unchecked(size, align))
+// }
+fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span) -> Stmt {
+    let usize = cx.path_ident(span, Ident::new(sym::usize, span));
+    let ty_usize = cx.ty_path(usize);
+    let size = Ident::from_str_and_span("size", span);
+    let align = Ident::from_str_and_span("align", span);
+
+    let layout_new = cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]);
+    let layout_new = cx.expr_path(cx.path(span, layout_new));
+    let layout = cx.expr_call(
+        span,
+        layout_new,
+        thin_vec![cx.expr_ident(span, size), cx.expr_ident(span, align)],
+    );
+
+    let call = cx.expr_call_ident(sig_span, handler, thin_vec![layout]);
+
+    let never = ast::FnRetTy::Ty(cx.ty(span, TyKind::Never));
+    let params = thin_vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)];
+    let decl = cx.fn_decl(params, never);
+    let header = FnHeader { unsafety: Unsafe::Yes(span), ..FnHeader::default() };
+    let sig = FnSig { decl, header, span: span };
+
+    let body = Some(cx.block_expr(call));
+    let kind = ItemKind::Fn(Box::new(Fn {
+        defaultness: ast::Defaultness::Final,
+        sig,
+        generics: Generics::default(),
+        body,
+    }));
+
+    let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span)];
+
+    let item = cx.item(span, Ident::from_str_and_span("__rg_oom", span), attrs, kind);
+    cx.stmt_item(sig_span, item)
+}
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index bf0ac3f0ee3..630f9b87bc3 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -20,6 +20,13 @@ pub(crate) struct OneCfgPattern {
 }
 
 #[derive(Diagnostic)]
+#[diag(builtin_macros_alloc_error_must_be_fn)]
+pub(crate) struct AllocErrorMustBeFn {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(builtin_macros_assert_requires_boolean)]
 pub(crate) struct AssertRequiresBoolean {
     #[primary_span]
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index b6170161d6b..8f86ef44aa3 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -27,6 +27,7 @@ use rustc_expand::proc_macro::BangProcMacro;
 use rustc_fluent_macro::fluent_messages;
 use rustc_span::symbol::sym;
 
+mod alloc_error_handler;
 mod assert;
 mod cfg;
 mod cfg_accessible;
@@ -103,6 +104,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
     }
 
     register_attr! {
+        alloc_error_handler: alloc_error_handler::expand,
         bench: test::expand_bench,
         cfg_accessible: cfg_accessible::Expander,
         cfg_eval: cfg_eval::expand,
diff --git a/compiler/rustc_codegen_cranelift/example/alloc_example.rs b/compiler/rustc_codegen_cranelift/example/alloc_example.rs
index e39c3272958..4ede2fe4efe 100644
--- a/compiler/rustc_codegen_cranelift/example/alloc_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/alloc_example.rs
@@ -1,4 +1,4 @@
-#![feature(start, core_intrinsics)]
+#![feature(start, core_intrinsics, alloc_error_handler)]
 #![no_std]
 
 extern crate alloc;
@@ -22,6 +22,11 @@ fn panic_handler(_: &core::panic::PanicInfo) -> ! {
     core::intrinsics::abort();
 }
 
+#[alloc_error_handler]
+fn alloc_error_handler(_: alloc::alloc::Layout) -> ! {
+    core::intrinsics::abort();
+}
+
 #[start]
 fn main(_argc: isize, _argv: *const *const u8) -> isize {
     let world: Box<&str> = Box::new("Hello World!\0");
diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs
index 9fb8079a21f..2c246ceb37d 100644
--- a/compiler/rustc_codegen_cranelift/src/allocator.rs
+++ b/compiler/rustc_codegen_cranelift/src/allocator.rs
@@ -6,6 +6,7 @@ use crate::prelude::*;
 use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
 use rustc_codegen_ssa::base::allocator_kind_for_codegen;
 use rustc_session::config::OomStrategy;
+use rustc_span::symbol::sym;
 
 /// Returns whether an allocator shim was created
 pub(crate) fn codegen(
@@ -14,7 +15,13 @@ pub(crate) fn codegen(
     unwind_context: &mut UnwindContext,
 ) -> bool {
     let Some(kind) = allocator_kind_for_codegen(tcx) else { return false };
-    codegen_inner(module, unwind_context, kind, tcx.sess.opts.unstable_opts.oom);
+    codegen_inner(
+        module,
+        unwind_context,
+        kind,
+        tcx.alloc_error_handler_kind(()).unwrap(),
+        tcx.sess.opts.unstable_opts.oom,
+    );
     true
 }
 
@@ -22,6 +29,7 @@ fn codegen_inner(
     module: &mut impl Module,
     unwind_context: &mut UnwindContext,
     kind: AllocatorKind,
+    alloc_error_handler_kind: AllocatorKind,
     oom_strategy: OomStrategy,
 ) {
     let usize_ty = module.target_config().pointer_type();
@@ -63,6 +71,19 @@ fn codegen_inner(
         );
     }
 
+    let sig = Signature {
+        call_conv: module.target_config().default_call_conv,
+        params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)],
+        returns: vec![],
+    };
+    crate::common::create_wrapper_function(
+        module,
+        unwind_context,
+        sig,
+        "__rust_alloc_error_handler",
+        &alloc_error_handler_kind.fn_name(sym::oom),
+    );
+
     let data_id = module.declare_data(OomStrategy::SYMBOL, Linkage::Export, false, false).unwrap();
     let mut data_ctx = DataContext::new();
     data_ctx.set_align(1);
diff --git a/compiler/rustc_codegen_gcc/example/alloc_example.rs b/compiler/rustc_codegen_gcc/example/alloc_example.rs
index faff1dca23f..754e7931412 100644
--- a/compiler/rustc_codegen_gcc/example/alloc_example.rs
+++ b/compiler/rustc_codegen_gcc/example/alloc_example.rs
@@ -1,4 +1,4 @@
-#![feature(start, core_intrinsics, lang_items)]
+#![feature(start, core_intrinsics, alloc_error_handler, lang_items)]
 #![no_std]
 
 extern crate alloc;
@@ -21,6 +21,11 @@ fn panic_handler(_: &core::panic::PanicInfo) -> ! {
     core::intrinsics::abort();
 }
 
+#[alloc_error_handler]
+fn alloc_error_handler(_: alloc::alloc::Layout) -> ! {
+    core::intrinsics::abort();
+}
+
 #[lang = "eh_personality"]
 fn eh_personality() -> ! {
     loop {}
diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs
index e90db44ece1..4bad33ee879 100644
--- a/compiler/rustc_codegen_gcc/src/allocator.rs
+++ b/compiler/rustc_codegen_gcc/src/allocator.rs
@@ -5,10 +5,11 @@ use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS
 use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::OomStrategy;
+use rustc_span::symbol::sym;
 
 use crate::GccContext;
 
-pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind) {
+pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) {
     let context = &mods.context;
     let usize =
         match tcx.sess.target.pointer_width {
@@ -86,6 +87,37 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
         // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643
     }
 
+    let types = [usize, usize];
+    let name = "__rust_alloc_error_handler".to_string();
+    let args: Vec<_> = types.iter().enumerate()
+        .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
+        .collect();
+    let func = context.new_function(None, FunctionType::Exported, void, &args, name, false);
+
+    if tcx.sess.target.default_hidden_visibility {
+        #[cfg(feature="master")]
+        func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
+    }
+
+    let callee = alloc_error_handler_kind.fn_name(sym::oom);
+    let args: Vec<_> = types.iter().enumerate()
+        .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
+        .collect();
+    let callee = context.new_function(None, FunctionType::Extern, void, &args, callee, false);
+    #[cfg(feature="master")]
+    callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
+
+    let block = func.new_block("entry");
+
+    let args = args
+        .iter()
+        .enumerate()
+        .map(|(i, _)| func.get_param(i as i32).to_rvalue())
+        .collect::<Vec<_>>();
+    let _ret = context.new_call(None, callee, &args);
+    //llvm::LLVMSetTailCall(ret, True);
+    block.end_with_void_return(None);
+
     let name = OomStrategy::SYMBOL.to_string();
     let global = context.new_global(None, GlobalKind::Exported, i8, name);
     let value = tcx.sess.opts.unstable_opts.oom.should_panic();
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 65de02b3567..738cdb6f119 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -593,6 +593,8 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
             InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
             InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
+            InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r",
+            InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f",
             InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a",
             InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d",
@@ -667,6 +669,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
         InlineAsmRegClass::Avr(_) => unimplemented!(),
         InlineAsmRegClass::Bpf(_) => unimplemented!(),
         InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(),
         InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(),
         InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(),
         InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => cx.type_i32(),
@@ -804,6 +808,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option
             }
         }
         InlineAsmRegClass::Hexagon(_) => None,
+        InlineAsmRegClass::LoongArch(_) => None,
         InlineAsmRegClass::Mips(_) => None,
         InlineAsmRegClass::Nvptx(_) => None,
         InlineAsmRegClass::PowerPC(_) => None,
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 1a20dbcebd4..1cabb05de97 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -163,11 +163,11 @@ impl CodegenBackend for GccCodegenBackend {
 }
 
 impl ExtraBackendMethods for GccCodegenBackend {
-    fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind) -> Self::Module {
+    fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module {
         let mut mods = GccContext {
             context: Context::default(),
         };
-        unsafe { allocator::codegen(tcx, &mut mods, module_name, kind); }
+        unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); }
         mods
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index fc9251dda82..668d9292705 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -4,6 +4,7 @@ use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS
 use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{DebugInfo, OomStrategy};
+use rustc_span::symbol::sym;
 
 use crate::debuginfo;
 use crate::llvm::{self, False, True};
@@ -14,6 +15,7 @@ pub(crate) unsafe fn codegen(
     module_llvm: &mut ModuleLlvm,
     module_name: &str,
     kind: AllocatorKind,
+    alloc_error_handler_kind: AllocatorKind,
 ) {
     let llcx = &*module_llvm.llcx;
     let llmod = module_llvm.llmod();
@@ -98,6 +100,52 @@ pub(crate) unsafe fn codegen(
         llvm::LLVMDisposeBuilder(llbuilder);
     }
 
+    // rust alloc error handler
+    let args = [usize, usize]; // size, align
+
+    let ty = llvm::LLVMFunctionType(void, args.as_ptr(), args.len() as c_uint, False);
+    let name = "__rust_alloc_error_handler";
+    let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
+    // -> ! DIFlagNoReturn
+    let no_return = llvm::AttributeKind::NoReturn.create_attr(llcx);
+    attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]);
+
+    if tcx.sess.target.default_hidden_visibility {
+        llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
+    }
+    if tcx.sess.must_emit_unwind_tables() {
+        let uwtable = attributes::uwtable_attr(llcx);
+        attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
+    }
+
+    let callee = alloc_error_handler_kind.fn_name(sym::oom);
+    let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
+    // -> ! DIFlagNoReturn
+    attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
+    llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
+
+    let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
+
+    let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
+    llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
+    let args = args
+        .iter()
+        .enumerate()
+        .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
+        .collect::<Vec<_>>();
+    let ret = llvm::LLVMRustBuildCall(
+        llbuilder,
+        ty,
+        callee,
+        args.as_ptr(),
+        args.len() as c_uint,
+        [].as_ptr(),
+        0 as c_uint,
+    );
+    llvm::LLVMSetTailCall(ret, True);
+    llvm::LLVMBuildRetVoid(llbuilder);
+    llvm::LLVMDisposeBuilder(llbuilder);
+
     // __rust_alloc_error_handler_should_panic
     let name = OomStrategy::SYMBOL;
     let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 1a3865360a3..98d5b3599d9 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -236,6 +236,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                 InlineAsmArch::Nvptx64 => {}
                 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {}
                 InlineAsmArch::Hexagon => {}
+                InlineAsmArch::LoongArch64 => {}
                 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
                 InlineAsmArch::S390x => {}
                 InlineAsmArch::SpirV => {}
@@ -633,6 +634,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
             InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
             | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w",
             InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
+            InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r",
+            InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f",
             InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f",
             InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
@@ -719,6 +722,7 @@ fn modifier_to_llvm(
             }
         }
         InlineAsmRegClass::Hexagon(_) => None,
+        InlineAsmRegClass::LoongArch(_) => None,
         InlineAsmRegClass::Mips(_) => None,
         InlineAsmRegClass::Nvptx(_) => None,
         InlineAsmRegClass::PowerPC(_) => None,
@@ -803,6 +807,8 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
             cx.type_vector(cx.type_i64(), 2)
         }
         InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(),
         InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(),
         InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(),
         InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 00b2dc1287a..8305a0a4c28 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -115,10 +115,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
         tcx: TyCtxt<'tcx>,
         module_name: &str,
         kind: AllocatorKind,
+        alloc_error_handler_kind: AllocatorKind,
     ) -> ModuleLlvm {
         let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
         unsafe {
-            allocator::codegen(tcx, &mut module_llvm, module_name, kind);
+            allocator::codegen(tcx, &mut module_llvm, module_name, kind, alloc_error_handler_kind);
         }
         module_llvm
     }
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index bda0cf764e5..8f2f829c17c 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -219,7 +219,7 @@ fn exported_symbols_provider_local(
         for symbol_name in ALLOCATOR_METHODS
             .iter()
             .map(|method| format!("__rust_{}", method.name))
-            .chain([OomStrategy::SYMBOL.to_string()])
+            .chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()])
         {
             let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
 
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 3e9d29df02c..c5ca7936a2b 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -635,9 +635,16 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
     if let Some(kind) = allocator_kind_for_codegen(tcx) {
         let llmod_id =
             cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
-        let module_llvm = tcx
-            .sess
-            .time("write_allocator_module", || backend.codegen_allocator(tcx, &llmod_id, kind));
+        let module_llvm = tcx.sess.time("write_allocator_module", || {
+            backend.codegen_allocator(
+                tcx,
+                &llmod_id,
+                kind,
+                // If allocator_kind is Some then alloc_error_handler_kind must
+                // also be Some.
+                tcx.alloc_error_handler_kind(()).unwrap(),
+            )
+        });
 
         ongoing_codegen.submit_pre_codegened_module_to_llvm(
             tcx,
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 2e88b7ce219..64bebe50ddb 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -123,6 +123,7 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se
         tcx: TyCtxt<'tcx>,
         module_name: &str,
         kind: AllocatorKind,
+        alloc_error_handler_kind: AllocatorKind,
     ) -> Self::Module;
     /// This generates the codegen unit and returns it along with
     /// a `u64` giving an estimate of the unit's processing cost.
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 426d2c4034b..004017ec5f3 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -31,6 +31,7 @@
 #![feature(unwrap_infallible)]
 #![feature(strict_provenance)]
 #![feature(ptr_alignment_type)]
+#![feature(macro_metavar_expr)]
 #![allow(rustc::default_hash_types)]
 #![allow(rustc::potential_query_instability)]
 #![deny(rustc::untranslatable_diagnostic)]
diff --git a/compiler/rustc_data_structures/src/tagged_ptr.rs b/compiler/rustc_data_structures/src/tagged_ptr.rs
index 8568aac67c0..2914eece679 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr.rs
@@ -24,6 +24,7 @@ use crate::aligned::Aligned;
 
 mod copy;
 mod drop;
+mod impl_tag;
 
 pub use copy::CopyTaggedPtr;
 pub use drop::TaggedPtr;
@@ -141,6 +142,30 @@ pub unsafe trait Tag: Copy {
     unsafe fn from_usize(tag: usize) -> Self;
 }
 
+/// Returns the number of bits available for use for tags in a pointer to `T`
+/// (this is based on `T`'s alignment).
+pub const fn bits_for<T: ?Sized + Aligned>() -> u32 {
+    crate::aligned::align_of::<T>().as_nonzero().trailing_zeros()
+}
+
+/// Returns the correct [`Tag::BITS`] constant for a set of tag values.
+pub const fn bits_for_tags(mut tags: &[usize]) -> u32 {
+    let mut bits = 0;
+
+    while let &[tag, ref rest @ ..] = tags {
+        tags = rest;
+
+        // bits required to represent `tag`,
+        // position of the most significant 1
+        let b = usize::BITS - tag.leading_zeros();
+        if b > bits {
+            bits = b;
+        }
+    }
+
+    bits
+}
+
 unsafe impl<T: ?Sized + Aligned> Pointer for Box<T> {
     const BITS: u32 = bits_for::<Self::Target>();
 
@@ -221,12 +246,6 @@ unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a mut T {
     }
 }
 
-/// Returns the number of bits available for use for tags in a pointer to `T`
-/// (this is based on `T`'s alignment).
-pub const fn bits_for<T: ?Sized + Aligned>() -> u32 {
-    crate::aligned::align_of::<T>().as_nonzero().trailing_zeros()
-}
-
 /// A tag type used in [`CopyTaggedPtr`] and [`TaggedPtr`] tests.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 #[cfg(test)]
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs
new file mode 100644
index 00000000000..cb7f7d318dc
--- /dev/null
+++ b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs
@@ -0,0 +1,144 @@
+/// Implements [`Tag`] for a given type.
+///
+/// You can use `impl_tag` on structs and enums.
+/// You need to specify the type and all its possible values,
+/// which can only be paths with optional fields.
+///
+/// [`Tag`]: crate::tagged_ptr::Tag
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// #![feature(macro_metavar_expr)]
+/// use rustc_data_structures::{impl_tag, tagged_ptr::Tag};
+///
+/// #[derive(Copy, Clone, PartialEq, Debug)]
+/// enum SomeTag {
+///     A,
+///     B,
+///     X { v: bool },
+///     Y(bool, bool),
+/// }
+///
+/// impl_tag! {
+///     // The type for which the `Tag` will be implemented
+///     impl Tag for SomeTag;
+///     // You need to specify all possible tag values:
+///     SomeTag::A, // 0
+///     SomeTag::B, // 1
+///     // For variants with fields, you need to specify the fields:
+///     SomeTag::X { v: true  }, // 2
+///     SomeTag::X { v: false }, // 3
+///     // For tuple variants use named syntax:
+///     SomeTag::Y { 0: true,  1: true  }, // 4
+///     SomeTag::Y { 0: false, 1: true  }, // 5
+///     SomeTag::Y { 0: true,  1: false }, // 6
+///     SomeTag::Y { 0: false, 1: false }, // 7
+/// }
+///
+/// // Tag values are assigned in order:
+/// assert_eq!(SomeTag::A.into_usize(), 0);
+/// assert_eq!(SomeTag::X { v: false }.into_usize(), 3);
+/// assert_eq!(SomeTag::Y(false, true).into_usize(), 5);
+///
+/// assert_eq!(unsafe { SomeTag::from_usize(1) }, SomeTag::B);
+/// assert_eq!(unsafe { SomeTag::from_usize(2) }, SomeTag::X { v: true });
+/// assert_eq!(unsafe { SomeTag::from_usize(7) }, SomeTag::Y(false, false));
+/// ```
+///
+/// Structs are supported:
+///
+/// ```
+/// #![feature(macro_metavar_expr)]
+/// # use rustc_data_structures::impl_tag;
+/// #[derive(Copy, Clone)]
+/// struct Flags { a: bool, b: bool }
+///
+/// impl_tag! {
+///     impl Tag for Flags;
+///     Flags { a: true,  b: true  },
+///     Flags { a: false, b: true  },
+///     Flags { a: true,  b: false },
+///     Flags { a: false, b: false },
+/// }
+/// ```
+///
+/// Not specifying all values results in a compile error:
+///
+/// ```compile_fail,E0004
+/// #![feature(macro_metavar_expr)]
+/// # use rustc_data_structures::impl_tag;
+/// #[derive(Copy, Clone)]
+/// enum E {
+///     A,
+///     B,
+/// }
+///
+/// impl_tag! {
+///     impl Tag for E;
+///     E::A,
+/// }
+/// ```
+#[macro_export]
+macro_rules! impl_tag {
+    (
+        impl Tag for $Self:ty;
+        $(
+            $($path:ident)::* $( { $( $fields:tt )* })?,
+        )*
+    ) => {
+        // Safety:
+        // `bits_for_tags` is called on the same `${index()}`-es as
+        // `into_usize` returns, thus `BITS` constant is correct.
+        unsafe impl $crate::tagged_ptr::Tag for $Self {
+            const BITS: u32 = $crate::tagged_ptr::bits_for_tags(&[
+                $(
+                    ${index()},
+                    $( ${ignore(path)} )*
+                )*
+            ]);
+
+            #[inline]
+            fn into_usize(self) -> usize {
+                // This forbids use of repeating patterns (`Enum::V`&`Enum::V`, etc)
+                // (or at least it should, see <https://github.com/rust-lang/rust/issues/110613>)
+                #[forbid(unreachable_patterns)]
+                match self {
+                    // `match` is doing heavy lifting here, by requiring exhaustiveness
+                    $(
+                        $($path)::* $( { $( $fields )* } )? => ${index()},
+                    )*
+                }
+            }
+
+            #[inline]
+            unsafe fn from_usize(tag: usize) -> Self {
+                match tag {
+                    $(
+                        ${index()} => $($path)::* $( { $( $fields )* } )?,
+                    )*
+
+                    // Safety:
+                    // `into_usize` only returns `${index()}` of the same
+                    // repetition as we are filtering above, thus if this is
+                    // reached, the safety contract of this function was
+                    // already breached.
+                    _ => unsafe {
+                        debug_assert!(
+                            false,
+                            "invalid tag: {tag}\
+                             (this is a bug in the caller of `from_usize`)"
+                        );
+                        std::hint::unreachable_unchecked()
+                    },
+                }
+            }
+
+        }
+    };
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs
new file mode 100644
index 00000000000..62c926153e1
--- /dev/null
+++ b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs
@@ -0,0 +1,34 @@
+#[test]
+fn bits_constant() {
+    use crate::tagged_ptr::Tag;
+
+    #[derive(Copy, Clone)]
+    struct Unit;
+    impl_tag! { impl Tag for Unit; Unit, }
+    assert_eq!(Unit::BITS, 0);
+
+    #[derive(Copy, Clone)]
+    enum Enum3 {
+        A,
+        B,
+        C,
+    }
+    impl_tag! { impl Tag for Enum3; Enum3::A, Enum3::B, Enum3::C, }
+    assert_eq!(Enum3::BITS, 2);
+
+    #[derive(Copy, Clone)]
+    struct Eight(bool, bool, bool);
+    impl_tag! {
+        impl Tag for Eight;
+        Eight { 0: true,  1: true,  2: true  },
+        Eight { 0: true,  1: true,  2: false },
+        Eight { 0: true,  1: false, 2: true  },
+        Eight { 0: true,  1: false, 2: false },
+        Eight { 0: false, 1: true,  2: true  },
+        Eight { 0: false, 1: true,  2: false },
+        Eight { 0: false, 1: false, 2: true  },
+        Eight { 0: false, 1: false, 2: false },
+    }
+
+    assert_eq!(Eight::BITS, 3);
+}
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 1a80b4fc314..5fac485de64 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -58,8 +58,16 @@ use std::str;
 use std::sync::LazyLock;
 use std::time::Instant;
 
+// This import blocks the use of panicking `print` and `println` in all the code
+// below. Please use `safe_print` and `safe_println` to avoid ICE when
+// encountering an I/O error during print.
+#[allow(unused_imports)]
+use std::{compile_error as print, compile_error as println};
+
 pub mod args;
 pub mod pretty;
+#[macro_use]
+mod print;
 mod session_diagnostics;
 
 use crate::session_diagnostics::{
@@ -511,7 +519,7 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
             if io::stdout().is_terminal() {
                 show_content_with_pager(&text);
             } else {
-                print!("{text}");
+                safe_print!("{text}");
             }
         }
         Err(InvalidErrorCode) => {
@@ -547,7 +555,7 @@ fn show_content_with_pager(content: &str) {
     // If pager fails for whatever reason, we should still print the content
     // to standard output
     if fallback_to_println {
-        print!("{content}");
+        safe_print!("{content}");
     }
 }
 
@@ -601,7 +609,7 @@ pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Co
                 let path = &(*ifile);
                 let mut v = Vec::new();
                 locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v).unwrap();
-                println!("{}", String::from_utf8(v).unwrap());
+                safe_println!("{}", String::from_utf8(v).unwrap());
             }
             Input::Str { .. } => {
                 early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
@@ -642,12 +650,12 @@ fn print_crate_info(
             TargetList => {
                 let mut targets = rustc_target::spec::TARGETS.to_vec();
                 targets.sort_unstable();
-                println!("{}", targets.join("\n"));
+                safe_println!("{}", targets.join("\n"));
             }
-            Sysroot => println!("{}", sess.sysroot.display()),
-            TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
+            Sysroot => safe_println!("{}", sess.sysroot.display()),
+            TargetLibdir => safe_println!("{}", sess.target_tlib_path.dir.display()),
             TargetSpec => {
-                println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
+                safe_println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
             }
             AllTargetSpecs => {
                 let mut targets = BTreeMap::new();
@@ -656,7 +664,7 @@ fn print_crate_info(
                     let target = Target::expect_builtin(&triple);
                     targets.insert(name, target.to_json());
                 }
-                println!("{}", serde_json::to_string_pretty(&targets).unwrap());
+                safe_println!("{}", serde_json::to_string_pretty(&targets).unwrap());
             }
             FileNames | CrateName => {
                 let Some(attrs) = attrs.as_ref() else {
@@ -666,14 +674,14 @@ fn print_crate_info(
                 let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess);
                 let id = rustc_session::output::find_crate_name(sess, attrs);
                 if *req == PrintRequest::CrateName {
-                    println!("{id}");
+                    safe_println!("{id}");
                     continue;
                 }
                 let crate_types = collect_crate_types(sess, attrs);
                 for &style in &crate_types {
                     let fname =
                         rustc_session::output::filename_for_input(sess, style, id, &t_outputs);
-                    println!("{}", fname.file_name().unwrap().to_string_lossy());
+                    safe_println!("{}", fname.file_name().unwrap().to_string_lossy());
                 }
             }
             Cfg => {
@@ -707,13 +715,13 @@ fn print_crate_info(
 
                 cfgs.sort();
                 for cfg in cfgs {
-                    println!("{cfg}");
+                    safe_println!("{cfg}");
                 }
             }
             CallingConventions => {
                 let mut calling_conventions = rustc_target::spec::abi::all_names();
                 calling_conventions.sort_unstable();
-                println!("{}", calling_conventions.join("\n"));
+                safe_println!("{}", calling_conventions.join("\n"));
             }
             RelocationModels
             | CodeModels
@@ -733,7 +741,7 @@ fn print_crate_info(
                     let stable = sess.target.options.supported_split_debuginfo.contains(split);
                     let unstable_ok = sess.unstable_options();
                     if stable || unstable_ok {
-                        println!("{split}");
+                        safe_println!("{split}");
                     }
                 }
             }
@@ -770,14 +778,14 @@ pub fn version_at_macro_invocation(
 ) {
     let verbose = matches.opt_present("verbose");
 
-    println!("{binary} {version}");
+    safe_println!("{binary} {version}");
 
     if verbose {
-        println!("binary: {binary}");
-        println!("commit-hash: {commit_hash}");
-        println!("commit-date: {commit_date}");
-        println!("host: {}", config::host_triple());
-        println!("release: {release}");
+        safe_println!("binary: {binary}");
+        safe_println!("commit-hash: {commit_hash}");
+        safe_println!("commit-date: {commit_date}");
+        safe_println!("host: {}", config::host_triple());
+        safe_println!("release: {release}");
 
         let debug_flags = matches.opt_strs("Z");
         let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
@@ -807,7 +815,7 @@ fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
     } else {
         ""
     };
-    println!(
+    safe_println!(
         "{options}{at_path}\nAdditional help:
     -C help             Print codegen options
     -W help             \
@@ -820,7 +828,7 @@ fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
 }
 
 fn print_wall_help() {
-    println!(
+    safe_println!(
         "
 The flag `-Wall` does not exist in `rustc`. Most useful lints are enabled by
 default. Use `rustc -W help` to see all available lints. It's more common to put
@@ -832,7 +840,7 @@ the command line flag directly.
 
 /// Write to stdout lint command options, together with a list of all available lints
 pub fn describe_lints(sess: &Session, lint_store: &LintStore, loaded_plugins: bool) {
-    println!(
+    safe_println!(
         "
 Available lint options:
     -W <foo>           Warn about <foo>
@@ -877,21 +885,21 @@ Available lint options:
         s
     };
 
-    println!("Lint checks provided by rustc:\n");
+    safe_println!("Lint checks provided by rustc:\n");
 
     let print_lints = |lints: Vec<&Lint>| {
-        println!("    {}  {:7.7}  {}", padded("name"), "default", "meaning");
-        println!("    {}  {:7.7}  {}", padded("----"), "-------", "-------");
+        safe_println!("    {}  {:7.7}  {}", padded("name"), "default", "meaning");
+        safe_println!("    {}  {:7.7}  {}", padded("----"), "-------", "-------");
         for lint in lints {
             let name = lint.name_lower().replace('_', "-");
-            println!(
+            safe_println!(
                 "    {}  {:7.7}  {}",
                 padded(&name),
                 lint.default_level(sess.edition()).as_str(),
                 lint.desc
             );
         }
-        println!("\n");
+        safe_println!("\n");
     };
 
     print_lints(builtin);
@@ -912,14 +920,14 @@ Available lint options:
         s
     };
 
-    println!("Lint groups provided by rustc:\n");
+    safe_println!("Lint groups provided by rustc:\n");
 
     let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>, all_warnings| {
-        println!("    {}  sub-lints", padded("name"));
-        println!("    {}  ---------", padded("----"));
+        safe_println!("    {}  sub-lints", padded("name"));
+        safe_println!("    {}  ---------", padded("----"));
 
         if all_warnings {
-            println!("    {}  all lints that are set to issue warnings", padded("warnings"));
+            safe_println!("    {}  all lints that are set to issue warnings", padded("warnings"));
         }
 
         for (name, to) in lints {
@@ -929,26 +937,26 @@ Available lint options:
                 .map(|x| x.to_string().replace('_', "-"))
                 .collect::<Vec<String>>()
                 .join(", ");
-            println!("    {}  {}", padded(&name), desc);
+            safe_println!("    {}  {}", padded(&name), desc);
         }
-        println!("\n");
+        safe_println!("\n");
     };
 
     print_lint_groups(builtin_groups, true);
 
     match (loaded_plugins, plugin.len(), plugin_groups.len()) {
         (false, 0, _) | (false, _, 0) => {
-            println!("Lint tools like Clippy can provide additional lints and lint groups.");
+            safe_println!("Lint tools like Clippy can provide additional lints and lint groups.");
         }
         (false, ..) => panic!("didn't load lint plugins but got them anyway!"),
-        (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."),
+        (true, 0, 0) => safe_println!("This crate does not load any lint plugins or lint groups."),
         (true, l, g) => {
             if l > 0 {
-                println!("Lint checks provided by plugins loaded by this crate:\n");
+                safe_println!("Lint checks provided by plugins loaded by this crate:\n");
                 print_lints(plugin);
             }
             if g > 0 {
-                println!("Lint groups provided by plugins loaded by this crate:\n");
+                safe_println!("Lint groups provided by plugins loaded by this crate:\n");
                 print_lint_groups(plugin_groups, false);
             }
         }
@@ -996,12 +1004,12 @@ pub fn describe_flag_categories(matches: &Matches) -> bool {
 }
 
 fn describe_debug_flags() {
-    println!("\nAvailable options:\n");
+    safe_println!("\nAvailable options:\n");
     print_flag_list("-Z", config::Z_OPTIONS);
 }
 
 fn describe_codegen_flags() {
-    println!("\nAvailable codegen options:\n");
+    safe_println!("\nAvailable codegen options:\n");
     print_flag_list("-C", config::CG_OPTIONS);
 }
 
@@ -1012,7 +1020,7 @@ fn print_flag_list<T>(
     let max_len = flag_list.iter().map(|&(name, _, _, _)| name.chars().count()).max().unwrap_or(0);
 
     for &(name, _, _, desc) in flag_list {
-        println!(
+        safe_println!(
             "    {} {:>width$}=val -- {}",
             cmdline_opt,
             name.replace('_', "-"),
diff --git a/compiler/rustc_driver_impl/src/print.rs b/compiler/rustc_driver_impl/src/print.rs
new file mode 100644
index 00000000000..70de55320f7
--- /dev/null
+++ b/compiler/rustc_driver_impl/src/print.rs
@@ -0,0 +1,20 @@
+use std::fmt;
+use std::io::{self, Write as _};
+
+macro_rules! safe_print {
+    ($($arg:tt)*) => {{
+        $crate::print::print(std::format_args!($($arg)*));
+    }};
+}
+
+macro_rules! safe_println {
+    ($($arg:tt)*) => {
+        safe_print!("{}\n", std::format_args!($($arg)*))
+    };
+}
+
+pub(crate) fn print(args: fmt::Arguments<'_>) {
+    if let Err(_) = io::stdout().write_fmt(args) {
+        rustc_errors::FatalError.raise();
+    }
+}
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 594e6cca912..48f5bd1cb50 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -291,6 +291,8 @@ declare_features! (
     (active, abi_x86_interrupt, "1.17.0", Some(40180), None),
     /// Allows additional const parameter types, such as `&'static str` or user defined types
     (incomplete, adt_const_params, "1.56.0", Some(95174), None),
+    /// Allows defining an `#[alloc_error_handler]`.
+    (active, alloc_error_handler, "1.29.0", Some(51540), None),
     /// Allows trait methods with arbitrary self types.
     (active, arbitrary_self_types, "1.23.0", Some(44874), None),
     /// Allows using `const` operands in inline assembly.
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index c978d6472c8..876a31abdf8 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -47,8 +47,6 @@ declare_features! (
 
     (removed, advanced_slice_patterns, "1.0.0", Some(62254), None,
      Some("merged into `#![feature(slice_patterns)]`")),
-    /// Allows defining an `#[alloc_error_handler]`.
-    (removed, alloc_error_handler, "CURRENT_RUSTC_VERSION", Some(51540), None, Some("now handled by panic handler")),
     (removed, allocator, "1.0.0", None, None, None),
     /// Allows a test to fail without failing the whole suite.
     (removed, allow_fail, "1.19.0", Some(46488), None, Some("removed due to no clear use cases")),
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 1d7965ff5f6..f32ae509e33 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -225,3 +225,40 @@ hir_analysis_functions_names_duplicated = functions names are duplicated
 
 hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is highly experimental and may result in invalid code
     .help = add `#![feature(simd_ffi)]` to the crate attributes to enable
+
+hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
+    .label = cannot specialize default item `{$ident}`
+    .ok_label = parent `impl` is here
+    .note = to specialize, `{$ident}` in the parent `impl` must be marked `default`
+
+hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
+    .note = parent implementation is in crate `{$cname}`
+
+hir_analysis_missing_trait_item = not all trait items implemented, missing: `{$missing_items_msg}`
+    .label = missing `{$missing_items_msg}` in implementation
+
+hir_analysis_missing_trait_item_suggestion = implement the missing item: `{$snippet}`
+
+hir_analysis_missing_trait_item_label = `{$item}` from trait
+
+hir_analysis_missing_one_of_trait_item = not all trait items implemented, missing one of: `{$missing_items_msg}`
+    .label = missing one of `{$missing_items_msg}` in implementation
+    .note = required because of this annotation
+
+hir_analysis_missing_trait_item_unstable = not all trait items implemented, missing: `{$missing_item_name}`
+    .note = default implementation of `{$missing_item_name}` is unstable
+    .some_note = use of unstable library feature '{$feature}': {$r}
+    .none_note = use of unstable library feature '{$feature}'
+
+hir_analysis_transparent_enum_variant = transparent enum needs exactly one variant, but has {$number}
+    .label = needs exactly one variant, but has {$number}
+    .many_label = too many variants in `{$path}`
+    .multi_label = variant here
+
+hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$desc} needs at most one non-zero-sized field, but has {$field_count}
+    .label = needs at most one non-zero-sized field, but has {$field_count}
+    .labels = this field is non-zero-sized
+
+hir_analysis_transparent_non_zero_sized = transparent {$desc} needs at most one non-zero-sized field, but has {$field_count}
+    .label = needs at most one non-zero-sized field, but has {$field_count}
+    .labels = this field is non-zero-sized
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index ad2624a5d2d..65c2f5955cd 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -320,7 +320,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
         };
         let prohibit_opaque = tcx
             .explicit_item_bounds(def_id)
-            .iter()
+            .subst_identity_iter_copied()
             .try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
 
         if let Some(ty) = prohibit_opaque.break_value() {
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index fe87aae8ed1..48214b899a4 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -839,7 +839,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> {
             });
             self.types.insert(proj.def_id, (infer_ty, proj.substs));
             // Recurse into bounds
-            for (pred, pred_span) in self.interner().bound_explicit_item_bounds(proj.def_id).subst_iter_copied(self.interner(), proj.substs) {
+            for (pred, pred_span) in self.interner().explicit_item_bounds(proj.def_id).subst_iter_copied(self.interner(), proj.substs) {
                 let pred = pred.fold_with(self);
                 let pred = self.ocx.normalize(
                     &ObligationCause::misc(self.span, self.body_id),
@@ -2023,7 +2023,7 @@ pub(super) fn check_type_bounds<'tcx>(
     };
 
     let obligations: Vec<_> = tcx
-        .bound_explicit_item_bounds(trait_ty.def_id)
+        .explicit_item_bounds(trait_ty.def_id)
         .subst_iter_copied(tcx, rebased_substs)
         .map(|(concrete_ty_bound, span)| {
             debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 4b3f3cf169d..08154cdae47 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -74,7 +74,7 @@ pub use check::check_abi;
 
 use check::check_mod_item_types;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder};
+use rustc_errors::{pluralize, struct_span_err, Diagnostic, DiagnosticBuilder};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_index::bit_set::BitSet;
@@ -90,6 +90,7 @@ use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
 use std::num::NonZeroU32;
 
+use crate::errors;
 use crate::require_c_abi_if_c_variadic;
 use crate::util::common::indenter;
 
@@ -171,29 +172,13 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
 fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_impl: DefId) {
     let span = tcx.def_span(impl_item);
     let ident = tcx.item_name(impl_item);
-    let mut err = struct_span_err!(
-        tcx.sess,
-        span,
-        E0520,
-        "`{}` specializes an item from a parent `impl`, but that item is not marked `default`",
-        ident,
-    );
-    err.span_label(span, format!("cannot specialize default item `{}`", ident));
-
-    match tcx.span_of_impl(parent_impl) {
-        Ok(span) => {
-            err.span_label(span, "parent `impl` is here");
-            err.note(&format!(
-                "to specialize, `{}` in the parent `impl` must be marked `default`",
-                ident
-            ));
-        }
-        Err(cname) => {
-            err.note(&format!("parent implementation is in crate `{cname}`"));
-        }
-    }
 
-    err.emit();
+    let err = match tcx.span_of_impl(parent_impl) {
+        Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },
+        Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },
+    };
+
+    tcx.sess.emit_err(err);
 }
 
 fn missing_items_err(
@@ -211,15 +196,6 @@ fn missing_items_err(
         .collect::<Vec<_>>()
         .join("`, `");
 
-    let impl_span = tcx.def_span(impl_def_id);
-    let mut err = struct_span_err!(
-        tcx.sess,
-        impl_span,
-        E0046,
-        "not all trait items implemented, missing: `{missing_items_msg}`",
-    );
-    err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation"));
-
     // `Span` before impl block closing brace.
     let hi = full_impl_span.hi() - BytePos(1);
     // Point at the place right before the closing brace of the relevant `impl` to suggest
@@ -228,6 +204,8 @@ fn missing_items_err(
     // Obtain the level of indentation ending in `sugg_sp`.
     let padding =
         tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new());
+    let (mut missing_trait_item, mut missing_trait_item_none, mut missing_trait_item_label) =
+        (Vec::new(), Vec::new(), Vec::new());
 
     for &trait_item in missing_items {
         let snippet = suggestion_signature(
@@ -236,16 +214,30 @@ fn missing_items_err(
             tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity(),
         );
         let code = format!("{}{}\n{}", padding, snippet, padding);
-        let msg = format!("implement the missing item: `{snippet}`");
-        let appl = Applicability::HasPlaceholders;
         if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
-            err.span_label(span, format!("`{}` from trait", trait_item.name));
-            err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
+            missing_trait_item_label
+                .push(errors::MissingTraitItemLabel { span, item: trait_item.name });
+            missing_trait_item.push(errors::MissingTraitItemSuggestion {
+                span: sugg_sp,
+                code,
+                snippet,
+            });
         } else {
-            err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
+            missing_trait_item_none.push(errors::MissingTraitItemSuggestionNone {
+                span: sugg_sp,
+                code,
+                snippet,
+            })
         }
     }
-    err.emit();
+
+    tcx.sess.emit_err(errors::MissingTraitItem {
+        span: tcx.span_of_impl(impl_def_id.to_def_id()).unwrap(),
+        missing_items_msg,
+        missing_trait_item_label,
+        missing_trait_item,
+        missing_trait_item_none,
+    });
 }
 
 fn missing_items_must_implement_one_of_err(
@@ -257,19 +249,11 @@ fn missing_items_must_implement_one_of_err(
     let missing_items_msg =
         missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
 
-    let mut err = struct_span_err!(
-        tcx.sess,
-        impl_span,
-        E0046,
-        "not all trait items implemented, missing one of: `{missing_items_msg}`",
-    );
-    err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation"));
-
-    if let Some(annotation_span) = annotation_span {
-        err.span_note(annotation_span, "required because of this annotation");
-    }
-
-    err.emit();
+    tcx.sess.emit_err(errors::MissingOneOfTraitItem {
+        span: impl_span,
+        note: annotation_span,
+        missing_items_msg,
+    });
 }
 
 fn default_body_is_unstable(
@@ -281,25 +265,31 @@ fn default_body_is_unstable(
     issue: Option<NonZeroU32>,
 ) {
     let missing_item_name = tcx.associated_item(item_did).name;
-    let use_of_unstable_library_feature_note = match reason {
-        Some(r) => format!("use of unstable library feature '{feature}': {r}"),
-        None => format!("use of unstable library feature '{feature}'"),
+    let (mut some_note, mut none_note, mut reason_str) = (false, false, String::new());
+    match reason {
+        Some(r) => {
+            some_note = true;
+            reason_str = r.to_string();
+        }
+        None => none_note = true,
     };
 
-    let mut err = struct_span_err!(
-        tcx.sess,
-        impl_span,
-        E0046,
-        "not all trait items implemented, missing: `{missing_item_name}`",
-    );
-    err.note(format!("default implementation of `{missing_item_name}` is unstable"));
-    err.note(use_of_unstable_library_feature_note);
+    let mut err = tcx.sess.create_err(errors::MissingTraitItemUnstable {
+        span: impl_span,
+        some_note,
+        none_note,
+        missing_item_name,
+        feature,
+        reason: reason_str,
+    });
+
     rustc_session::parse::add_feature_diagnostics_for_issue(
         &mut err,
         &tcx.sess.parse_sess,
         feature,
         rustc_feature::GateIssue::Library(issue),
     );
+
     err.emit();
 }
 
@@ -488,16 +478,18 @@ fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, d
         .iter()
         .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
         .collect();
-    let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),);
-    let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}");
-    err.span_label(sp, &msg);
+    let (mut spans, mut many) = (Vec::new(), None);
     if let [start @ .., end] = &*variant_spans {
-        for variant_span in start {
-            err.span_label(*variant_span, "");
-        }
-        err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did)));
+        spans = start.to_vec();
+        many = Some(*end);
     }
-    err.emit();
+    tcx.sess.emit_err(errors::TransparentEnumVariant {
+        span: sp,
+        spans,
+        many,
+        number: adt.variants().len(),
+        path: tcx.def_path_str(did),
+    });
 }
 
 /// Emit an error when encountering two or more non-zero-sized fields in a transparent
@@ -509,21 +501,21 @@ fn bad_non_zero_sized_fields<'tcx>(
     field_spans: impl Iterator<Item = Span>,
     sp: Span,
 ) {
-    let msg = format!("needs at most one non-zero-sized field, but has {field_count}");
-    let mut err = struct_span_err!(
-        tcx.sess,
-        sp,
-        E0690,
-        "{}transparent {} {}",
-        if adt.is_enum() { "the variant of a " } else { "" },
-        adt.descr(),
-        msg,
-    );
-    err.span_label(sp, &msg);
-    for sp in field_spans {
-        err.span_label(sp, "this field is non-zero-sized");
+    if adt.is_enum() {
+        tcx.sess.emit_err(errors::TransparentNonZeroSizedEnum {
+            span: sp,
+            spans: field_spans.collect(),
+            field_count,
+            desc: adt.descr(),
+        });
+    } else {
+        tcx.sess.emit_err(errors::TransparentNonZeroSized {
+            span: sp,
+            spans: field_spans.collect(),
+            field_count,
+            desc: adt.descr(),
+        });
     }
-    err.emit();
 }
 
 // FIXME: Consider moving this method to a more fitting place.
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index b2ebbf993a1..0eafab017c7 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -360,7 +360,9 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
                             tcx,
                             param_env,
                             item_def_id,
-                            tcx.explicit_item_bounds(item_def_id).to_vec(),
+                            tcx.explicit_item_bounds(item_def_id)
+                                .subst_identity_iter_copied()
+                                .collect::<Vec<_>>(),
                             &FxIndexSet::default(),
                             gat_def_id.def_id,
                             gat_generics,
@@ -1125,7 +1127,7 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt
     let bounds = wfcx.tcx().explicit_item_bounds(item.def_id);
 
     debug!("check_associated_type_bounds: bounds={:?}", bounds);
-    let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
+    let wf_obligations = bounds.subst_identity_iter_copied().flat_map(|(bound, bound_span)| {
         let normalized_bound = wfcx.normalize(span, None, bound);
         traits::wf::predicate_obligations(
             wfcx.infcx,
@@ -1588,7 +1590,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
                 }
             });
             for (bound, bound_span) in tcx
-                .bound_explicit_item_bounds(opaque_ty.def_id)
+                .explicit_item_bounds(opaque_ty.def_id)
                 .subst_iter_copied(tcx, opaque_ty.substs)
             {
                 let bound = self.wfcx.normalize(bound_span, None, bound);
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 2e56d24638c..80d6bc7db9e 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -79,14 +79,14 @@ fn opaque_type_bounds<'tcx>(
 pub(super) fn explicit_item_bounds(
     tcx: TyCtxt<'_>,
     def_id: LocalDefId,
-) -> &'_ [(ty::Predicate<'_>, Span)] {
+) -> ty::EarlyBinder<&'_ [(ty::Predicate<'_>, Span)]> {
     match tcx.opt_rpitit_info(def_id.to_def_id()) {
         // RPITIT's bounds are the same as opaque type bounds, but with
         // a projection self type.
         Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
             let item = tcx.hir().get_by_def_id(opaque_def_id.expect_local()).expect_item();
             let opaque_ty = item.expect_opaque_ty();
-            return opaque_type_bounds(
+            return ty::EarlyBinder(opaque_type_bounds(
                 tcx,
                 opaque_def_id.expect_local(),
                 opaque_ty.bounds,
@@ -95,7 +95,7 @@ pub(super) fn explicit_item_bounds(
                     ty::InternalSubsts::identity_for_item(tcx, def_id),
                 ),
                 item.span,
-            );
+            ));
         }
         // These should have been fed!
         Some(ty::ImplTraitInTraitData::Impl { .. }) => unreachable!(),
@@ -103,7 +103,7 @@ pub(super) fn explicit_item_bounds(
     }
 
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-    match tcx.hir().get(hir_id) {
+    let bounds = match tcx.hir().get(hir_id) {
         hir::Node::TraitItem(hir::TraitItem {
             kind: hir::TraitItemKind::Type(bounds, _),
             span,
@@ -123,16 +123,18 @@ pub(super) fn explicit_item_bounds(
             opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
         }
         _ => bug!("item_bounds called on {:?}", def_id),
-    }
+    };
+    ty::EarlyBinder(bounds)
 }
 
 pub(super) fn item_bounds(
     tcx: TyCtxt<'_>,
     def_id: DefId,
 ) -> ty::EarlyBinder<&'_ ty::List<ty::Predicate<'_>>> {
-    let bounds = tcx.mk_predicates_from_iter(util::elaborate(
-        tcx,
-        tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound),
-    ));
-    ty::EarlyBinder(bounds)
+    tcx.explicit_item_bounds(def_id).map_bound(|bounds| {
+        tcx.mk_predicates_from_iter(util::elaborate(
+            tcx,
+            bounds.iter().map(|&(bound, _span)| bound),
+        ))
+    })
 }
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 2a3a683489d..cfce2463b18 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -631,3 +631,141 @@ pub(crate) struct SIMDFFIHighlyExperimental {
     pub span: Span,
     pub snip: String,
 }
+
+#[derive(Diagnostic)]
+pub enum ImplNotMarkedDefault {
+    #[diag(hir_analysis_impl_not_marked_default, code = "E0520")]
+    #[note]
+    Ok {
+        #[primary_span]
+        #[label]
+        span: Span,
+        #[label(hir_analysis_ok_label)]
+        ok_label: Span,
+        ident: Symbol,
+    },
+    #[diag(hir_analysis_impl_not_marked_default_err, code = "E0520")]
+    #[note]
+    Err {
+        #[primary_span]
+        #[label]
+        span: Span,
+        cname: Symbol,
+        ident: Symbol,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_missing_trait_item, code = "E0046")]
+pub(crate) struct MissingTraitItem {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[subdiagnostic]
+    pub missing_trait_item_label: Vec<MissingTraitItemLabel>,
+    #[subdiagnostic]
+    pub missing_trait_item: Vec<MissingTraitItemSuggestion>,
+    #[subdiagnostic]
+    pub missing_trait_item_none: Vec<MissingTraitItemSuggestionNone>,
+    pub missing_items_msg: String,
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_missing_trait_item_label)]
+pub(crate) struct MissingTraitItemLabel {
+    #[primary_span]
+    pub span: Span,
+    pub item: Symbol,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(
+    hir_analysis_missing_trait_item_suggestion,
+    style = "tool-only",
+    applicability = "has-placeholders",
+    code = "{code}"
+)]
+pub(crate) struct MissingTraitItemSuggestion {
+    #[primary_span]
+    pub span: Span,
+    pub code: String,
+    pub snippet: String,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(
+    hir_analysis_missing_trait_item_suggestion,
+    style = "hidden",
+    applicability = "has-placeholders",
+    code = "{code}"
+)]
+pub(crate) struct MissingTraitItemSuggestionNone {
+    #[primary_span]
+    pub span: Span,
+    pub code: String,
+    pub snippet: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_missing_one_of_trait_item, code = "E0046")]
+pub(crate) struct MissingOneOfTraitItem {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[note]
+    pub note: Option<Span>,
+    pub missing_items_msg: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_missing_trait_item_unstable, code = "E0046")]
+#[note]
+pub(crate) struct MissingTraitItemUnstable {
+    #[primary_span]
+    pub span: Span,
+    #[note(hir_analysis_some_note)]
+    pub some_note: bool,
+    #[note(hir_analysis_none_note)]
+    pub none_note: bool,
+    pub missing_item_name: Symbol,
+    pub feature: Symbol,
+    pub reason: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_transparent_enum_variant, code = "E0731")]
+pub(crate) struct TransparentEnumVariant {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(hir_analysis_multi_label)]
+    pub spans: Vec<Span>,
+    #[label(hir_analysis_many_label)]
+    pub many: Option<Span>,
+    pub number: usize,
+    pub path: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_transparent_non_zero_sized_enum, code = "E0690")]
+pub(crate) struct TransparentNonZeroSizedEnum<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(hir_analysis_labels)]
+    pub spans: Vec<Span>,
+    pub field_count: usize,
+    pub desc: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_transparent_non_zero_sized, code = "E0690")]
+pub(crate) struct TransparentNonZeroSized<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(hir_analysis_labels)]
+    pub spans: Vec<Span>,
+    pub field_count: usize,
+    pub desc: &'a str,
+}
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 4d240e90b14..e735b048d73 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -153,8 +153,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
     let mut collector =
         OpaqueTypeLifetimeCollector { tcx, root_def_id: item_def_id.to_def_id(), variances };
     let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id);
-    for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() {
-        let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs);
+    for (pred, _) in tcx.explicit_item_bounds(item_def_id).subst_iter_copied(tcx, id_substs) {
         debug!(?pred);
 
         // We only ignore opaque type substs if the opaque type is the outermost type.
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 6c2ce62722a..aefde8109a0 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -530,7 +530,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 for ty in [first_ty, second_ty] {
                     for (pred, _) in self
                         .tcx
-                        .bound_explicit_item_bounds(rpit_def_id)
+                        .explicit_item_bounds(rpit_def_id)
                         .subst_iter_copied(self.tcx, substs)
                     {
                         let pred = pred.kind().rebind(match pred.kind().skip_binder() {
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 8c2495e1dd8..7046269c2de 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -172,7 +172,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
                 .deduce_closure_signature_from_predicates(
                     expected_ty,
-                    self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
+                    self.tcx.explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
                 ),
             ty::Dynamic(ref object_type, ..) => {
                 let sig = object_type.projection_bounds().find_map(|pb| {
@@ -713,13 +713,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
                 .tcx
-                .bound_explicit_item_bounds(def_id)
+                .explicit_item_bounds(def_id)
                 .subst_iter_copied(self.tcx, substs)
                 .find_map(|(p, s)| get_future_output(p, s))?,
             ty::Error(_) => return None,
             ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self
                 .tcx
-                .bound_explicit_item_bounds(proj.def_id)
+                .explicit_item_bounds(proj.def_id)
                 .subst_iter_copied(self.tcx, proj.substs)
                 .find_map(|(p, s)| get_future_output(p, s))?,
             _ => span_bug!(
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index 8feef332de8..5b432475fc3 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -571,7 +571,7 @@ fn check_must_not_suspend_ty<'tcx>(
         // FIXME: support adding the attribute to TAITs
         ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
             let mut has_emitted = false;
-            for &(predicate, _) in fcx.tcx.explicit_item_bounds(def) {
+            for &(predicate, _) in fcx.tcx.explicit_item_bounds(def).skip_binder() {
                 // We only look at the `DefId`, so it is safe to skip the binder here.
                 if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) =
                     predicate.kind().skip_binder()
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 0456dd56c34..fab9a8a5f4f 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -300,8 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         trait_def_id: DefId,
         self_ty: Ty<'tcx>,
         opt_input_types: Option<&[Ty<'tcx>]>,
-    ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>)
-    {
+    ) -> (traits::PredicateObligation<'tcx>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>) {
         // Construct a trait-reference `self_ty : Trait<input_tys>`
         let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
             match param.kind {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index b0c376a26f6..547f851526f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -402,7 +402,7 @@ impl<'tcx> InferCtxt<'tcx> {
         let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
         let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
 
-        self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs).find_map(
+        self.tcx.explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs).find_map(
             |(predicate, _)| {
                 predicate
                     .kind()
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 680465bdab6..334395945ea 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -540,7 +540,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 .obligations;
         }
 
-        let item_bounds = tcx.bound_explicit_item_bounds(def_id.to_def_id());
+        let item_bounds = tcx.explicit_item_bounds(def_id);
 
         for (predicate, _) in item_bounds.subst_iter_copied(tcx, substs) {
             let predicate = predicate.fold_with(&mut BottomUpFolder {
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 9dd4f0a8e4c..8ce8b4e2024 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -123,7 +123,7 @@ pub struct FulfillmentError<'tcx> {
 #[derive(Clone)]
 pub enum FulfillmentErrorCode<'tcx> {
     /// Inherently impossible to fulfill; this trait is implemented if and only if it is already implemented.
-    CodeCycle(Vec<Obligation<'tcx, ty::Predicate<'tcx>>>),
+    CodeCycle(Vec<PredicateObligation<'tcx>>),
     CodeSelectionError(SelectionError<'tcx>),
     CodeProjectionError(MismatchedProjectionTypes<'tcx>),
     CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index ce0f90bc1cc..7b0b5102c2d 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -777,7 +777,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(no_link, true);
     tracked!(no_profiler_runtime, true);
     tracked!(no_unique_section_names, true);
-    tracked!(oom, OomStrategy::Unwind);
+    tracked!(oom, OomStrategy::Panic);
     tracked!(osx_rpath_install_name, true);
     tracked!(packed_bundled_libs, true);
     tracked!(panic_abort_tests, true);
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index f9d43fe2200..15715c8fca0 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
         // For every projection predicate in the opaque type's explicit bounds,
         // check that the type that we're assigning actually satisfies the bounds
         // of the associated type.
-        for &(pred, pred_span) in cx.tcx.explicit_item_bounds(def_id) {
+        for (pred, pred_span) in cx.tcx.explicit_item_bounds(def_id).subst_identity_iter_copied() {
             // Liberate bound regions in the predicate since we
             // don't actually care about lifetimes in this check.
             let predicate = cx.tcx.liberate_late_bound_regions(def_id, pred.kind());
@@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
             // with `impl Send: OtherTrait`.
             for (assoc_pred, assoc_pred_span) in cx
                 .tcx
-                .bound_explicit_item_bounds(proj.projection_ty.def_id)
+                .explicit_item_bounds(proj.projection_ty.def_id)
                 .subst_iter_copied(cx.tcx, &proj.projection_ty.substs)
             {
                 let assoc_pred = assoc_pred.fold_with(proj_replacer);
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index d677d51881e..eb175e96997 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -254,7 +254,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                 }
                 ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
                 ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
-                    elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).iter().cloned())
+                    elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).subst_identity_iter_copied())
                         // We only care about self bounds for the impl-trait
                         .filter_only_self()
                         .find_map(|(pred, _span)| {
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 90cce9a8650..1acdc95ca8d 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -410,10 +410,15 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
   }
   Options.RelaxELFRelocations = RelaxELFRelocations;
   Options.UseInitArray = UseInitArray;
+
+#if LLVM_VERSION_LT(17, 0)
   if (ForceEmulatedTls) {
     Options.ExplicitEmulatedTLS = true;
     Options.EmulatedTLS = true;
   }
+#else
+  Options.EmulatedTLS = ForceEmulatedTls || Trip.hasDefaultEmulatedTLS();
+#endif
 
   if (TrapUnreachable) {
     // Tell LLVM to codegen `unreachable` into an explicit trap instruction.
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index f0158aeae85..79b8b417257 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -155,9 +155,19 @@ metadata_no_multiple_global_alloc =
 metadata_prev_global_alloc =
     previous global allocator defined here
 
+metadata_no_multiple_alloc_error_handler =
+    cannot define multiple allocation error handlers
+    .label = cannot define a new allocation error handler
+
+metadata_prev_alloc_error_handler =
+    previous allocation error handler defined here
+
 metadata_conflicting_global_alloc =
     the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name}
 
+metadata_conflicting_alloc_error_handler =
+    the `#[alloc_error_handler]` in {$other_crate_name} conflicts with allocation error handler in: {$crate_name}
+
 metadata_global_alloc_required =
     no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait
 
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 8bacd136647..179453238f2 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -38,8 +38,13 @@ pub struct CStore {
     /// This crate needs an allocator and either provides it itself, or finds it in a dependency.
     /// If the above is true, then this field denotes the kind of the found allocator.
     allocator_kind: Option<AllocatorKind>,
+    /// This crate needs an allocation error handler and either provides it itself, or finds it in a dependency.
+    /// If the above is true, then this field denotes the kind of the found allocator.
+    alloc_error_handler_kind: Option<AllocatorKind>,
     /// This crate has a `#[global_allocator]` item.
     has_global_allocator: bool,
+    /// This crate has a `#[alloc_error_handler]` item.
+    has_alloc_error_handler: bool,
 
     /// The interned [StableCrateId]s.
     pub(crate) stable_crate_ids: StableCrateIdMap,
@@ -216,10 +221,18 @@ impl CStore {
         self.allocator_kind
     }
 
+    pub(crate) fn alloc_error_handler_kind(&self) -> Option<AllocatorKind> {
+        self.alloc_error_handler_kind
+    }
+
     pub(crate) fn has_global_allocator(&self) -> bool {
         self.has_global_allocator
     }
 
+    pub(crate) fn has_alloc_error_handler(&self) -> bool {
+        self.has_alloc_error_handler
+    }
+
     pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) {
         let json_unused_externs = tcx.sess.opts.json_unused_externs;
 
@@ -255,7 +268,9 @@ impl CStore {
             metas: IndexVec::from_iter(iter::once(None)),
             injected_panic_runtime: None,
             allocator_kind: None,
+            alloc_error_handler_kind: None,
             has_global_allocator: false,
+            has_alloc_error_handler: false,
             stable_crate_ids,
             unused_externs: Vec::new(),
         }
@@ -761,6 +776,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             }
             spans => !spans.is_empty(),
         };
+        self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(krate) {
+            [span1, span2, ..] => {
+                self.sess
+                    .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
+                true
+            }
+            spans => !spans.is_empty(),
+        };
 
         // Check to see if we actually need an allocator. This desire comes
         // about through the `#![needs_allocator]` attribute and is typically
@@ -801,6 +824,21 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 }
             }
         }
+        let mut alloc_error_handler =
+            self.cstore.has_alloc_error_handler.then(|| Symbol::intern("this crate"));
+        for (_, data) in self.cstore.iter_crate_data() {
+            if data.has_alloc_error_handler() {
+                match alloc_error_handler {
+                    Some(other_crate) => {
+                        self.sess.emit_err(errors::ConflictingAllocErrorHandler {
+                            crate_name: data.name(),
+                            other_crate_name: other_crate,
+                        });
+                    }
+                    None => alloc_error_handler = Some(data.name()),
+                }
+            }
+        }
 
         if global_allocator.is_some() {
             self.cstore.allocator_kind = Some(AllocatorKind::Global);
@@ -816,6 +854,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             }
             self.cstore.allocator_kind = Some(AllocatorKind::Default);
         }
+
+        if alloc_error_handler.is_some() {
+            self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Global);
+        } else {
+            // The alloc crate provides a default allocation error handler if
+            // one isn't specified.
+            self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Default);
+        }
     }
 
     fn inject_dependency_if(
@@ -991,6 +1037,28 @@ fn global_allocator_spans(krate: &ast::Crate) -> Vec<Span> {
     f.spans
 }
 
+fn alloc_error_handler_spans(krate: &ast::Crate) -> Vec<Span> {
+    struct Finder {
+        name: Symbol,
+        spans: Vec<Span>,
+    }
+    impl<'ast> visit::Visitor<'ast> for Finder {
+        fn visit_item(&mut self, item: &'ast ast::Item) {
+            if item.ident.name == self.name
+                && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol)
+            {
+                self.spans.push(item.span);
+            }
+            visit::walk_item(self, item)
+        }
+    }
+
+    let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::oom));
+    let mut f = Finder { name, spans: Vec::new() };
+    visit::walk_crate(&mut f, krate);
+    f.spans
+}
+
 // On Windows the compiler would sometimes intermittently fail to open the
 // proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the
 // system still holds a lock on the file, so we retry a few times before calling it
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index 7ecb551a3e5..51b41b5f6a2 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -353,6 +353,16 @@ pub struct NoMultipleGlobalAlloc {
 }
 
 #[derive(Diagnostic)]
+#[diag(metadata_no_multiple_alloc_error_handler)]
+pub struct NoMultipleAllocErrorHandler {
+    #[primary_span]
+    #[label]
+    pub span2: Span,
+    #[label(metadata_prev_alloc_error_handler)]
+    pub span1: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(metadata_conflicting_global_alloc)]
 pub struct ConflictingGlobalAlloc {
     pub crate_name: Symbol,
@@ -360,6 +370,13 @@ pub struct ConflictingGlobalAlloc {
 }
 
 #[derive(Diagnostic)]
+#[diag(metadata_conflicting_alloc_error_handler)]
+pub struct ConflictingAllocErrorHandler {
+    pub crate_name: Symbol,
+    pub other_crate_name: Symbol,
+}
+
+#[derive(Diagnostic)]
 #[diag(metadata_global_alloc_required)]
 pub struct GlobalAllocRequired;
 
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 820a502d04c..a310cbb8029 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -23,7 +23,7 @@ use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::ty::codec::TyDecoder;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::GeneratorDiagnosticData;
-use rustc_middle::ty::{self, ParameterizedOverTcx, Ty, TyCtxt, Visibility};
+use rustc_middle::ty::{self, ParameterizedOverTcx, Predicate, Ty, TyCtxt, Visibility};
 use rustc_serialize::opaque::MemDecoder;
 use rustc_serialize::{Decodable, Decoder};
 use rustc_session::cstore::{
@@ -373,16 +373,6 @@ impl<'a, 'tcx> TyDecoder for DecodeContext<'a, 'tcx> {
         self.tcx()
     }
 
-    #[inline]
-    fn peek_byte(&self) -> u8 {
-        self.opaque.data[self.opaque.position()]
-    }
-
-    #[inline]
-    fn position(&self) -> usize {
-        self.opaque.position()
-    }
-
     fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx>
     where
         F: FnOnce(&mut Self) -> Ty<'tcx>,
@@ -404,7 +394,7 @@ impl<'a, 'tcx> TyDecoder for DecodeContext<'a, 'tcx> {
     where
         F: FnOnce(&mut Self) -> R,
     {
-        let new_opaque = MemDecoder::new(self.opaque.data, pos);
+        let new_opaque = MemDecoder::new(self.opaque.data(), pos);
         let old_opaque = mem::replace(&mut self.opaque, new_opaque);
         let old_state = mem::replace(&mut self.lazy_state, LazyState::NoNode);
         let r = f(self);
@@ -625,17 +615,12 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Symbol {
             SYMBOL_OFFSET => {
                 // read str offset
                 let pos = d.read_usize();
-                let old_pos = d.opaque.position();
 
                 // move to str offset and read
-                d.opaque.set_position(pos);
-                let s = d.read_str();
-                let sym = Symbol::intern(s);
-
-                // restore position
-                d.opaque.set_position(old_pos);
-
-                sym
+                d.opaque.with_position(pos, |d| {
+                    let s = d.read_str();
+                    Symbol::intern(s)
+                })
             }
             SYMBOL_PREINTERNED => {
                 let symbol_index = d.read_u32();
@@ -857,6 +842,20 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         )
     }
 
+    fn get_explicit_item_bounds(
+        self,
+        index: DefIndex,
+        tcx: TyCtxt<'tcx>,
+    ) -> ty::EarlyBinder<&'tcx [(Predicate<'tcx>, Span)]> {
+        let lazy = self.root.tables.explicit_item_bounds.get(self, index);
+        let output = if lazy.is_default() {
+            &mut []
+        } else {
+            tcx.arena.alloc_from_iter(lazy.decode((self, tcx)))
+        };
+        ty::EarlyBinder(&*output)
+    }
+
     fn get_variant(self, kind: &DefKind, index: DefIndex, parent_did: DefId) -> ty::VariantDef {
         let adt_kind = match kind {
             DefKind::Variant => ty::AdtKind::Enum,
@@ -1683,6 +1682,10 @@ impl CrateMetadata {
         self.root.has_global_allocator
     }
 
+    pub(crate) fn has_alloc_error_handler(&self) -> bool {
+        self.root.has_alloc_error_handler
+    }
+
     pub(crate) fn has_default_lib_allocator(&self) -> bool {
         self.root.has_default_lib_allocator
     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 4aa3768fc3b..4a3b783c636 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -203,7 +203,7 @@ impl IntoArgs for (CrateNum, SimplifiedType) {
 }
 
 provide! { tcx, def_id, other, cdata,
-    explicit_item_bounds => { table_defaulted_array }
+    explicit_item_bounds => { cdata.get_explicit_item_bounds(def_id.index, tcx) }
     explicit_predicates_of => { table }
     generics_of => { table }
     inferred_outlives_of => { table_defaulted_array }
@@ -290,6 +290,7 @@ provide! { tcx, def_id, other, cdata,
     is_panic_runtime => { cdata.root.panic_runtime }
     is_compiler_builtins => { cdata.root.compiler_builtins }
     has_global_allocator => { cdata.root.has_global_allocator }
+    has_alloc_error_handler => { cdata.root.has_alloc_error_handler }
     has_panic_handler => { cdata.root.has_panic_handler }
     is_profiler_runtime => { cdata.root.profiler_runtime }
     required_panic_strategy => { cdata.root.required_panic_strategy }
@@ -378,6 +379,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
     // resolve! Does this work? Unsure! That's what the issue is about
     *providers = Providers {
         allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(),
+        alloc_error_handler_kind: |tcx, ()| CStore::from_tcx(tcx).alloc_error_handler_kind(),
         is_private_dep: |_tcx, LocalCrate| false,
         native_library: |tcx, id| {
             tcx.native_libraries(id.krate)
@@ -494,6 +496,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
 
         dependency_formats: |tcx, ()| Lrc::new(crate::dependency_format::calculate(tcx)),
         has_global_allocator: |tcx, LocalCrate| CStore::from_tcx(tcx).has_global_allocator(),
+        has_alloc_error_handler: |tcx, LocalCrate| CStore::from_tcx(tcx).has_alloc_error_handler(),
         postorder_cnums: |tcx, ()| {
             tcx.arena
                 .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE))
diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
index 02cab561b8f..05402a58701 100644
--- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
+++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
@@ -45,9 +45,6 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for DefPathHashMapRef<'tcx> {
 
 impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefPathHashMapRef<'static> {
     fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefPathHashMapRef<'static> {
-        // Import TyDecoder so we can access the DecodeContext::position() method
-        use crate::rustc_middle::ty::codec::TyDecoder;
-
         let len = d.read_usize();
         let pos = d.position();
         let o = slice_owned(d.blob().clone(), |blob| &blob[pos..pos + len]);
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index fd8e49efea0..f5ffdd27cae 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -676,6 +676,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop,
                 edition: tcx.sess.edition(),
                 has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
+                has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE),
                 has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
                 has_default_lib_allocator: attr::contains_name(&attrs, sym::default_lib_allocator),
                 proc_macro_data,
@@ -1422,7 +1423,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
     fn encode_explicit_item_bounds(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_explicit_item_bounds({:?})", def_id);
-        let bounds = self.tcx.explicit_item_bounds(def_id);
+        let bounds = self.tcx.explicit_item_bounds(def_id).skip_binder();
         record_defaulted_array!(self.tables.explicit_item_bounds[def_id] <- bounds);
     }
 
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 1bb0eabc64f..dd02463e16a 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -225,6 +225,7 @@ pub(crate) struct CrateRoot {
     panic_in_drop_strategy: PanicStrategy,
     edition: Edition,
     has_global_allocator: bool,
+    has_alloc_error_handler: bool,
     has_panic_handler: bool,
     has_default_lib_allocator: bool,
 
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 76a8367b2c4..e9172e767e0 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -60,6 +60,7 @@
 #![feature(const_option)]
 #![feature(trait_alias)]
 #![feature(ptr_alignment_type)]
+#![feature(macro_metavar_expr)]
 #![recursion_limit = "512"]
 #![allow(rustc::potential_query_instability)]
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 4b7bc60926e..84b5d6b0d0f 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -251,7 +251,7 @@ rustc_queries! {
     /// `key` is the `DefId` of the associated type or opaque type.
     ///
     /// Bounds from the parent (e.g. with nested impl trait) are not included.
-    query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
+    query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, Span)]> {
         desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
@@ -1351,6 +1351,13 @@ rustc_queries! {
         desc { "checking if the crate has_global_allocator" }
         separate_provide_extern
     }
+    query has_alloc_error_handler(_: CrateNum) -> bool {
+        // This query depends on untracked global state in CStore
+        eval_always
+        fatal_cycle
+        desc { "checking if the crate has_alloc_error_handler" }
+        separate_provide_extern
+    }
     query has_panic_handler(_: CrateNum) -> bool {
         fatal_cycle
         desc { "checking if the crate has_panic_handler" }
@@ -1723,6 +1730,10 @@ rustc_queries! {
         eval_always
         desc { "getting the allocator kind for the current crate" }
     }
+    query alloc_error_handler_kind(_: ()) -> Option<AllocatorKind> {
+        eval_always
+        desc { "alloc error handler kind for the current crate" }
+    }
 
     query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
         desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 5454d406dd1..3793d85c85a 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -530,6 +530,16 @@ macro_rules! implement_ty_decoder {
                 fn read_raw_bytes(&mut self, len: usize) -> &[u8] {
                     self.opaque.read_raw_bytes(len)
                 }
+
+                #[inline]
+                fn position(&self) -> usize {
+                    self.opaque.position()
+                }
+
+                #[inline]
+                fn peek_byte(&self) -> u8 {
+                    self.opaque.peek_byte()
+                }
             }
         }
     }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 4a4f6770fc4..7df4be263d5 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1603,7 +1603,7 @@ impl<'tcx> TyCtxt<'tcx> {
         let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false };
         let future_trait = self.require_lang_item(LangItem::Future, None);
 
-        self.explicit_item_bounds(def_id).iter().any(|(predicate, _)| {
+        self.explicit_item_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| {
             let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() else {
                 return false;
             };
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 17647d13f99..8e4e708b73c 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -861,6 +861,11 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
     pub fn is_const_if_const(self) -> bool {
         self.skip_binder().is_const_if_const()
     }
+
+    #[inline]
+    pub fn polarity(self) -> ImplPolarity {
+        self.skip_binder().polarity
+    }
 }
 
 /// `A: B`
@@ -1497,29 +1502,12 @@ struct ParamTag {
     constness: hir::Constness,
 }
 
-unsafe impl rustc_data_structures::tagged_ptr::Tag for ParamTag {
-    const BITS: u32 = 2;
-
-    #[inline]
-    fn into_usize(self) -> usize {
-        match self {
-            Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst } => 0,
-            Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst } => 1,
-            Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const } => 2,
-            Self { reveal: traits::Reveal::All, constness: hir::Constness::Const } => 3,
-        }
-    }
-
-    #[inline]
-    unsafe fn from_usize(ptr: usize) -> Self {
-        match ptr {
-            0 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst },
-            1 => Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst },
-            2 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const },
-            3 => Self { reveal: traits::Reveal::All, constness: hir::Constness::Const },
-            _ => std::hint::unreachable_unchecked(),
-        }
-    }
+impl_tag! {
+    impl Tag for ParamTag;
+    ParamTag { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst },
+    ParamTag { reveal: traits::Reveal::All,        constness: hir::Constness::NotConst },
+    ParamTag { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const    },
+    ParamTag { reveal: traits::Reveal::All,        constness: hir::Constness::Const    },
 }
 
 impl<'tcx> fmt::Debug for ParamEnv<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 4c95d0f8415..1c1432ecd5a 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -914,7 +914,7 @@ pub trait PrettyPrinter<'tcx>:
 
         // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
         // by looking up the projections associated with the def_id.
-        let bounds = tcx.bound_explicit_item_bounds(def_id);
+        let bounds = tcx.explicit_item_bounds(def_id);
 
         let mut traits = FxIndexMap::default();
         let mut fn_traits = FxIndexMap::default();
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index a2611022406..b35b514d795 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -95,7 +95,7 @@ impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
 
 impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "_#{}c", self.index)
+        write!(f, "?{}c", self.index)
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 29ae42be096..82dec7d98ad 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1436,7 +1436,7 @@ pub struct ConstVid<'tcx> {
 rustc_index::newtype_index! {
     /// A **region** (lifetime) **v**ariable **ID**.
     #[derive(HashStable)]
-    #[debug_format = "'_#{}r"]
+    #[debug_format = "'?{}"]
     pub struct RegionVid {}
 }
 
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index a439211ca33..63b2acdbe4e 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -612,6 +612,12 @@ where
     ) -> SubstIter<'s, 'tcx, I> {
         SubstIter { it: self.0.into_iter(), tcx, substs }
     }
+
+    /// Similar to [`subst_identity`](EarlyBinder::subst_identity),
+    /// but on an iterator of `TypeFoldable` values.
+    pub fn subst_identity_iter(self) -> I::IntoIter {
+        self.0.into_iter()
+    }
 }
 
 pub struct SubstIter<'s, 'tcx, I: IntoIterator> {
@@ -664,6 +670,12 @@ where
     ) -> SubstIterCopied<'s, 'tcx, I> {
         SubstIterCopied { it: self.0.into_iter(), tcx, substs }
     }
+
+    /// Similar to [`subst_identity`](EarlyBinder::subst_identity),
+    /// but on an iterator of values that deref to a `TypeFoldable`.
+    pub fn subst_identity_iter_copied(self) -> impl Iterator<Item = <I::Item as Deref>::Target> {
+        self.0.into_iter().map(|v| *v)
+    }
 }
 
 pub struct SubstIterCopied<'a, 'tcx, I: IntoIterator> {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 7127fdbf26a..4c346b00256 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -701,13 +701,6 @@ impl<'tcx> TyCtxt<'tcx> {
         if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) }
     }
 
-    pub fn bound_explicit_item_bounds(
-        self,
-        def_id: DefId,
-    ) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, rustc_span::Span)]> {
-        ty::EarlyBinder(self.explicit_item_bounds(def_id))
-    }
-
     /// Returns names of captured upvars for closures and generators.
     ///
     /// Here are some examples:
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 34a7ee9e264..e44dd084b2d 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -1800,7 +1800,7 @@ fn check_must_not_suspend_ty<'tcx>(
         // FIXME: support adding the attribute to TAITs
         ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
             let mut has_emitted = false;
-            for &(predicate, _) in tcx.explicit_item_bounds(def) {
+            for &(predicate, _) in tcx.explicit_item_bounds(def).skip_binder() {
                 // We only look at the `DefId`, so it is safe to skip the binder here.
                 if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) =
                     predicate.kind().skip_binder()
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 9567329192d..c607c7fd5f4 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -269,7 +269,7 @@ where
                     // and are visited by shallow visitors.
                     self.visit_predicates(ty::GenericPredicates {
                         parent: None,
-                        predicates: tcx.explicit_item_bounds(def_id),
+                        predicates: tcx.explicit_item_bounds(def_id).skip_binder(),
                     })?;
                 }
             }
@@ -1784,7 +1784,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
     fn bounds(&mut self) -> &mut Self {
         self.visit_predicates(ty::GenericPredicates {
             parent: None,
-            predicates: self.tcx.explicit_item_bounds(self.item_def_id),
+            predicates: self.tcx.explicit_item_bounds(self.item_def_id).skip_binder(),
         });
         self
     }
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index 91b56660b15..c0f2d7803d4 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -169,13 +169,12 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
 
             // Decode the *position* of the footer, which can be found in the
             // last 8 bytes of the file.
-            decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE);
-            let footer_pos = IntEncodedWithFixedSize::decode(&mut decoder).0 as usize;
-
+            let footer_pos = decoder
+                .with_position(decoder.len() - IntEncodedWithFixedSize::ENCODED_SIZE, |decoder| {
+                    IntEncodedWithFixedSize::decode(decoder).0 as usize
+                });
             // Decode the file footer, which contains all the lookup tables, etc.
-            decoder.set_position(footer_pos);
-
-            decode_tagged(&mut decoder, TAG_FILE_FOOTER)
+            decoder.with_position(footer_pos, |decoder| decode_tagged(decoder, TAG_FILE_FOOTER))
         };
 
         Self {
@@ -522,29 +521,13 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> {
     }
 }
 
-trait DecoderWithPosition: Decoder {
-    fn position(&self) -> usize;
-}
-
-impl<'a> DecoderWithPosition for MemDecoder<'a> {
-    fn position(&self) -> usize {
-        self.position()
-    }
-}
-
-impl<'a, 'tcx> DecoderWithPosition for CacheDecoder<'a, 'tcx> {
-    fn position(&self) -> usize {
-        self.opaque.position()
-    }
-}
-
 // Decodes something that was encoded with `encode_tagged()` and verify that the
 // tag matches and the correct amount of bytes was read.
 fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> V
 where
     T: Decodable<D> + Eq + std::fmt::Debug,
     V: Decodable<D>,
-    D: DecoderWithPosition,
+    D: Decoder,
 {
     let start_pos = decoder.position();
 
@@ -568,16 +551,6 @@ impl<'a, 'tcx> TyDecoder for CacheDecoder<'a, 'tcx> {
         self.tcx
     }
 
-    #[inline]
-    fn position(&self) -> usize {
-        self.opaque.position()
-    }
-
-    #[inline]
-    fn peek_byte(&self) -> u8 {
-        self.opaque.data[self.opaque.position()]
-    }
-
     fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx>
     where
         F: FnOnce(&mut Self) -> Ty<'tcx>,
@@ -600,9 +573,9 @@ impl<'a, 'tcx> TyDecoder for CacheDecoder<'a, 'tcx> {
     where
         F: FnOnce(&mut Self) -> R,
     {
-        debug_assert!(pos < self.opaque.data.len());
+        debug_assert!(pos < self.opaque.len());
 
-        let new_opaque = MemDecoder::new(self.opaque.data, pos);
+        let new_opaque = MemDecoder::new(self.opaque.data(), pos);
         let old_opaque = mem::replace(&mut self.opaque, new_opaque);
         let r = f(self);
         self.opaque = old_opaque;
@@ -743,17 +716,12 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Symbol {
             SYMBOL_OFFSET => {
                 // read str offset
                 let pos = d.read_usize();
-                let old_pos = d.opaque.position();
 
                 // move to str offset and read
-                d.opaque.set_position(pos);
-                let s = d.read_str();
-                let sym = Symbol::intern(s);
-
-                // restore position
-                d.opaque.set_position(old_pos);
-
-                sym
+                d.opaque.with_position(pos, |d| {
+                    let s = d.read_str();
+                    Symbol::intern(s)
+                })
             }
             SYMBOL_PREINTERNED => {
                 let symbol_index = d.read_u32();
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index 59c1333fb5a..edddfda6242 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -94,21 +94,19 @@ impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>>
 {
     #[instrument(level = "debug", skip(d))]
     fn decode(d: &mut MemDecoder<'a>) -> SerializedDepGraph<K> {
-        let start_position = d.position();
-
         // The last 16 bytes are the node count and edge count.
         debug!("position: {:?}", d.position());
-        d.set_position(d.data.len() - 2 * IntEncodedWithFixedSize::ENCODED_SIZE);
+        let (node_count, edge_count) =
+            d.with_position(d.len() - 2 * IntEncodedWithFixedSize::ENCODED_SIZE, |d| {
+                debug!("position: {:?}", d.position());
+                let node_count = IntEncodedWithFixedSize::decode(d).0 as usize;
+                let edge_count = IntEncodedWithFixedSize::decode(d).0 as usize;
+                (node_count, edge_count)
+            });
         debug!("position: {:?}", d.position());
 
-        let node_count = IntEncodedWithFixedSize::decode(d).0 as usize;
-        let edge_count = IntEncodedWithFixedSize::decode(d).0 as usize;
         debug!(?node_count, ?edge_count);
 
-        debug!("position: {:?}", d.position());
-        d.set_position(start_position);
-        debug!("position: {:?}", d.position());
-
         let mut nodes = IndexVec::with_capacity(node_count);
         let mut fingerprints = IndexVec::with_capacity(node_count);
         let mut edge_list_indices = IndexVec::with_capacity(node_count);
diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs
index 7dad9aa01fa..e568b9e6786 100644
--- a/compiler/rustc_serialize/src/leb128.rs
+++ b/compiler/rustc_serialize/src/leb128.rs
@@ -1,3 +1,6 @@
+use crate::opaque::MemDecoder;
+use crate::serialize::Decoder;
+
 /// Returns the length of the longest LEB128 encoding for `T`, assuming `T` is an integer type
 pub const fn max_leb128_len<T>() -> usize {
     // The longest LEB128 encoding for an integer uses 7 bits per byte.
@@ -50,21 +53,19 @@ impl_write_unsigned_leb128!(write_usize_leb128, usize);
 macro_rules! impl_read_unsigned_leb128 {
     ($fn_name:ident, $int_ty:ty) => {
         #[inline]
-        pub fn $fn_name(slice: &[u8], position: &mut usize) -> $int_ty {
+        pub fn $fn_name(decoder: &mut MemDecoder<'_>) -> $int_ty {
             // The first iteration of this loop is unpeeled. This is a
             // performance win because this code is hot and integer values less
             // than 128 are very common, typically occurring 50-80% or more of
             // the time, even for u64 and u128.
-            let byte = slice[*position];
-            *position += 1;
+            let byte = decoder.read_u8();
             if (byte & 0x80) == 0 {
                 return byte as $int_ty;
             }
             let mut result = (byte & 0x7F) as $int_ty;
             let mut shift = 7;
             loop {
-                let byte = slice[*position];
-                *position += 1;
+                let byte = decoder.read_u8();
                 if (byte & 0x80) == 0 {
                     result |= (byte as $int_ty) << shift;
                     return result;
@@ -127,14 +128,13 @@ impl_write_signed_leb128!(write_isize_leb128, isize);
 macro_rules! impl_read_signed_leb128 {
     ($fn_name:ident, $int_ty:ty) => {
         #[inline]
-        pub fn $fn_name(slice: &[u8], position: &mut usize) -> $int_ty {
+        pub fn $fn_name(decoder: &mut MemDecoder<'_>) -> $int_ty {
             let mut result = 0;
             let mut shift = 0;
             let mut byte;
 
             loop {
-                byte = slice[*position];
-                *position += 1;
+                byte = decoder.read_u8();
                 result |= <$int_ty>::from(byte & 0x7F) << shift;
                 shift += 7;
 
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index 1f8d2336c4e..ce8503918b4 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -16,6 +16,7 @@ Core encoding and decoding interfaces.
 #![feature(maybe_uninit_slice)]
 #![feature(new_uninit)]
 #![feature(allocator_api)]
+#![feature(ptr_sub_ptr)]
 #![cfg_attr(test, feature(test))]
 #![allow(rustc::internal)]
 #![deny(rustc::untranslatable_diagnostic)]
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index 53e5c896736..b7976ea3b1c 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -2,7 +2,9 @@ use crate::leb128::{self, largest_max_leb128_len};
 use crate::serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::fs::File;
 use std::io::{self, Write};
+use std::marker::PhantomData;
 use std::mem::MaybeUninit;
+use std::ops::Range;
 use std::path::Path;
 use std::ptr;
 
@@ -510,39 +512,126 @@ impl Encoder for FileEncoder {
 // Decoder
 // -----------------------------------------------------------------------------
 
+// Conceptually, `MemDecoder` wraps a `&[u8]` with a cursor into it that is always valid.
+// This is implemented with three pointers, two which represent the original slice and a
+// third that is our cursor.
+// It is an invariant of this type that start <= current <= end.
+// Additionally, the implementation of this type never modifies start and end.
 pub struct MemDecoder<'a> {
-    pub data: &'a [u8],
-    position: usize,
+    start: *const u8,
+    current: *const u8,
+    end: *const u8,
+    _marker: PhantomData<&'a u8>,
 }
 
 impl<'a> MemDecoder<'a> {
     #[inline]
     pub fn new(data: &'a [u8], position: usize) -> MemDecoder<'a> {
-        MemDecoder { data, position }
+        let Range { start, end } = data.as_ptr_range();
+        MemDecoder { start, current: data[position..].as_ptr(), end, _marker: PhantomData }
     }
 
     #[inline]
-    pub fn position(&self) -> usize {
-        self.position
+    pub fn data(&self) -> &'a [u8] {
+        // SAFETY: This recovers the original slice, only using members we never modify.
+        unsafe { std::slice::from_raw_parts(self.start, self.len()) }
     }
 
     #[inline]
-    pub fn set_position(&mut self, pos: usize) {
-        self.position = pos
+    pub fn len(&self) -> usize {
+        // SAFETY: This recovers the length of the original slice, only using members we never modify.
+        unsafe { self.end.sub_ptr(self.start) }
+    }
+
+    #[inline]
+    pub fn remaining(&self) -> usize {
+        // SAFETY: This type guarantees current <= end.
+        unsafe { self.end.sub_ptr(self.current) }
+    }
+
+    #[cold]
+    #[inline(never)]
+    fn decoder_exhausted() -> ! {
+        panic!("MemDecoder exhausted")
     }
 
     #[inline]
-    pub fn advance(&mut self, bytes: usize) {
-        self.position += bytes;
+    fn read_byte(&mut self) -> u8 {
+        if self.current == self.end {
+            Self::decoder_exhausted();
+        }
+        // SAFETY: This type guarantees current <= end, and we just checked current == end.
+        unsafe {
+            let byte = *self.current;
+            self.current = self.current.add(1);
+            byte
+        }
+    }
+
+    #[inline]
+    fn read_array<const N: usize>(&mut self) -> [u8; N] {
+        self.read_raw_bytes(N).try_into().unwrap()
+    }
+
+    // The trait method doesn't have a lifetime parameter, and we need a version of this
+    // that definitely returns a slice based on the underlying storage as opposed to
+    // the Decoder itself in order to implement read_str efficiently.
+    #[inline]
+    fn read_raw_bytes_inherent(&mut self, bytes: usize) -> &'a [u8] {
+        if bytes > self.remaining() {
+            Self::decoder_exhausted();
+        }
+        // SAFETY: We just checked if this range is in-bounds above.
+        unsafe {
+            let slice = std::slice::from_raw_parts(self.current, bytes);
+            self.current = self.current.add(bytes);
+            slice
+        }
+    }
+
+    /// While we could manually expose manipulation of the decoder position,
+    /// all current users of that method would need to reset the position later,
+    /// incurring the bounds check of set_position twice.
+    #[inline]
+    pub fn with_position<F, T>(&mut self, pos: usize, func: F) -> T
+    where
+        F: Fn(&mut MemDecoder<'a>) -> T,
+    {
+        struct SetOnDrop<'a, 'guarded> {
+            decoder: &'guarded mut MemDecoder<'a>,
+            current: *const u8,
+        }
+        impl Drop for SetOnDrop<'_, '_> {
+            fn drop(&mut self) {
+                self.decoder.current = self.current;
+            }
+        }
+
+        if pos >= self.len() {
+            Self::decoder_exhausted();
+        }
+        let previous = self.current;
+        // SAFETY: We just checked if this add is in-bounds above.
+        unsafe {
+            self.current = self.start.add(pos);
+        }
+        let guard = SetOnDrop { current: previous, decoder: self };
+        func(guard.decoder)
     }
 }
 
 macro_rules! read_leb128 {
-    ($dec:expr, $fun:ident) => {{ leb128::$fun($dec.data, &mut $dec.position) }};
+    ($dec:expr, $fun:ident) => {{ leb128::$fun($dec) }};
 }
 
 impl<'a> Decoder for MemDecoder<'a> {
     #[inline]
+    fn position(&self) -> usize {
+        // SAFETY: This type guarantees start <= current
+        unsafe { self.current.sub_ptr(self.start) }
+    }
+
+    #[inline]
     fn read_u128(&mut self) -> u128 {
         read_leb128!(self, read_u128_leb128)
     }
@@ -559,17 +648,12 @@ impl<'a> Decoder for MemDecoder<'a> {
 
     #[inline]
     fn read_u16(&mut self) -> u16 {
-        let bytes = [self.data[self.position], self.data[self.position + 1]];
-        let value = u16::from_le_bytes(bytes);
-        self.position += 2;
-        value
+        u16::from_le_bytes(self.read_array())
     }
 
     #[inline]
     fn read_u8(&mut self) -> u8 {
-        let value = self.data[self.position];
-        self.position += 1;
-        value
+        self.read_byte()
     }
 
     #[inline]
@@ -594,17 +678,12 @@ impl<'a> Decoder for MemDecoder<'a> {
 
     #[inline]
     fn read_i16(&mut self) -> i16 {
-        let bytes = [self.data[self.position], self.data[self.position + 1]];
-        let value = i16::from_le_bytes(bytes);
-        self.position += 2;
-        value
+        i16::from_le_bytes(self.read_array())
     }
 
     #[inline]
     fn read_i8(&mut self) -> i8 {
-        let value = self.data[self.position];
-        self.position += 1;
-        value as i8
+        self.read_byte() as i8
     }
 
     #[inline]
@@ -625,22 +704,26 @@ impl<'a> Decoder for MemDecoder<'a> {
     }
 
     #[inline]
-    fn read_str(&mut self) -> &'a str {
+    fn read_str(&mut self) -> &str {
         let len = self.read_usize();
-        let sentinel = self.data[self.position + len];
-        assert!(sentinel == STR_SENTINEL);
-        let s = unsafe {
-            std::str::from_utf8_unchecked(&self.data[self.position..self.position + len])
-        };
-        self.position += len + 1;
-        s
+        let bytes = self.read_raw_bytes_inherent(len + 1);
+        assert!(bytes[len] == STR_SENTINEL);
+        unsafe { std::str::from_utf8_unchecked(&bytes[..len]) }
     }
 
     #[inline]
-    fn read_raw_bytes(&mut self, bytes: usize) -> &'a [u8] {
-        let start = self.position;
-        self.position += bytes;
-        &self.data[start..self.position]
+    fn read_raw_bytes(&mut self, bytes: usize) -> &[u8] {
+        self.read_raw_bytes_inherent(bytes)
+    }
+
+    #[inline]
+    fn peek_byte(&self) -> u8 {
+        if self.current == self.end {
+            Self::decoder_exhausted();
+        }
+        // SAFETY: This type guarantees current is inbounds or one-past-the-end, which is end.
+        // Since we just checked current == end, the current pointer must be inbounds.
+        unsafe { *self.current }
     }
 }
 
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index 527abc23727..a6d9c7b7d42 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -84,6 +84,8 @@ pub trait Decoder {
     fn read_char(&mut self) -> char;
     fn read_str(&mut self) -> &str;
     fn read_raw_bytes(&mut self, len: usize) -> &[u8];
+    fn peek_byte(&self) -> u8;
+    fn position(&self) -> usize;
 }
 
 /// Trait for types that can be serialized
diff --git a/compiler/rustc_serialize/tests/leb128.rs b/compiler/rustc_serialize/tests/leb128.rs
index 314c07db981..7872e778431 100644
--- a/compiler/rustc_serialize/tests/leb128.rs
+++ b/compiler/rustc_serialize/tests/leb128.rs
@@ -3,6 +3,7 @@
 
 use rustc_serialize::leb128::*;
 use std::mem::MaybeUninit;
+use rustc_serialize::Decoder;
 
 macro_rules! impl_test_unsigned_leb128 {
     ($test_name:ident, $write_fn_name:ident, $read_fn_name:ident, $int_ty:ident) => {
@@ -28,12 +29,12 @@ macro_rules! impl_test_unsigned_leb128 {
                 stream.extend($write_fn_name(&mut buf, x));
             }
 
-            let mut position = 0;
+            let mut decoder = rustc_serialize::opaque::MemDecoder::new(&stream, 0);
             for &expected in &values {
-                let actual = $read_fn_name(&stream, &mut position);
+                let actual = $read_fn_name(&mut decoder);
                 assert_eq!(expected, actual);
             }
-            assert_eq!(stream.len(), position);
+            assert_eq!(stream.len(), decoder.position());
         }
     };
 }
@@ -74,12 +75,12 @@ macro_rules! impl_test_signed_leb128 {
                 stream.extend($write_fn_name(&mut buf, x));
             }
 
-            let mut position = 0;
+            let mut decoder = rustc_serialize::opaque::MemDecoder::new(&stream, 0);
             for &expected in &values {
-                let actual = $read_fn_name(&stream, &mut position);
+                let actual = $read_fn_name(&mut decoder);
                 assert_eq!(expected, actual);
             }
-            assert_eq!(stream.len(), position);
+            assert_eq!(stream.len(), decoder.position());
         }
     };
 }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 419b6afe7c6..79eb31bb105 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -3048,9 +3048,9 @@ pub(crate) mod dep_tracking {
 #[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
 pub enum OomStrategy {
     /// Generate a panic that can be caught by `catch_unwind`.
-    Unwind,
+    Panic,
 
-    /// Calls the panic hook as normal but aborts instead of unwinding.
+    /// Abort the process immediately.
     Abort,
 }
 
@@ -3059,7 +3059,7 @@ impl OomStrategy {
 
     pub fn should_panic(self) -> u8 {
         match self {
-            OomStrategy::Unwind => 1,
+            OomStrategy::Panic => 1,
             OomStrategy::Abort => 0,
         }
     }
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 98bcacbe7ff..d9f03fe1407 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -662,7 +662,7 @@ mod parse {
 
     pub(crate) fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool {
         match v {
-            Some("unwind") => *slot = OomStrategy::Unwind,
+            Some("panic") => *slot = OomStrategy::Panic,
             Some("abort") => *slot = OomStrategy::Abort,
             _ => return false,
         }
diff --git a/compiler/rustc_target/src/asm/loongarch.rs b/compiler/rustc_target/src/asm/loongarch.rs
new file mode 100644
index 00000000000..7ace1647ded
--- /dev/null
+++ b/compiler/rustc_target/src/asm/loongarch.rs
@@ -0,0 +1,131 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+use std::fmt;
+
+def_reg_class! {
+    LoongArch LoongArchInlineAsmRegClass {
+        reg,
+        freg,
+    }
+}
+
+impl LoongArchInlineAsmRegClass {
+    pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
+        &[]
+    }
+
+    pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+        None
+    }
+
+    pub fn suggest_modifier(
+        self,
+        _arch: InlineAsmArch,
+        _ty: InlineAsmType,
+    ) -> Option<(char, &'static str)> {
+        None
+    }
+
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+        None
+    }
+
+    pub fn supported_types(
+        self,
+        arch: InlineAsmArch,
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
+        match (self, arch) {
+            (Self::reg, InlineAsmArch::LoongArch64) => types! { _: I8, I16, I32, I64, F32, F64; },
+            (Self::reg, _) => types! { _: I8, I16, I32, F32; },
+            (Self::freg, _) => types! { _: F32, F64; },
+        }
+    }
+}
+
+// The reserved registers are taken from <https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp#79>
+def_regs! {
+    LoongArch LoongArchInlineAsmReg LoongArchInlineAsmRegClass {
+        r1: reg = ["$r1","$ra"],
+        r4: reg = ["$r4","$a0"],
+        r5: reg = ["$r5","$a1"],
+        r6: reg = ["$r6","$a2"],
+        r7: reg = ["$r7","$a3"],
+        r8: reg = ["$r8","$a4"],
+        r9: reg = ["$r9","$a5"],
+        r10: reg = ["$r10","$a6"],
+        r11: reg = ["$r11","$a7"],
+        r12: reg = ["$r12","$t0"],
+        r13: reg = ["$r13","$t1"],
+        r14: reg = ["$r14","$t2"],
+        r15: reg = ["$r15","$t3"],
+        r16: reg = ["$r16","$t4"],
+        r17: reg = ["$r17","$t5"],
+        r18: reg = ["$r18","$t6"],
+        r19: reg = ["$r19","$t7"],
+        r20: reg = ["$r20","$t8"],
+        r23: reg = ["$r23","$s0"],
+        r24: reg = ["$r24","$s1"],
+        r25: reg = ["$r25","$s2"],
+        r26: reg = ["$r26","$s3"],
+        r27: reg = ["$r27","$s4"],
+        r28: reg = ["$r28","$s5"],
+        r29: reg = ["$r29","$s6"],
+        r30: reg = ["$r30","$s7"],
+        f0: freg = ["$f0","$fa0"],
+        f1: freg = ["$f1","$fa1"],
+        f2: freg = ["$f2","$fa2"],
+        f3: freg = ["$f3","$fa3"],
+        f4: freg = ["$f4","$fa4"],
+        f5: freg = ["$f5","$fa5"],
+        f6: freg = ["$f6","$fa6"],
+        f7: freg = ["$f7","$fa7"],
+        f8: freg = ["$f8","$ft0"],
+        f9: freg = ["$f9","$ft1"],
+        f10: freg = ["$f10","$ft2"],
+        f11: freg = ["$f11","$ft3"],
+        f12: freg = ["$f12","$ft4"],
+        f13: freg = ["$f13","$ft5"],
+        f14: freg = ["$f14","$ft6"],
+        f15: freg = ["$f15","$ft7"],
+        f16: freg = ["$f16","$ft8"],
+        f17: freg = ["$f17","$ft9"],
+        f18: freg = ["$f18","$ft10"],
+        f19: freg = ["$f19","$ft11"],
+        f20: freg = ["$f20","$ft12"],
+        f21: freg = ["$f21","$ft13"],
+        f22: freg = ["$f22","$ft14"],
+        f23: freg = ["$f23","$ft15"],
+        f24: freg = ["$f24","$fs0"],
+        f25: freg = ["$f25","$fs1"],
+        f26: freg = ["$f26","$fs2"],
+        f27: freg = ["$f27","$fs3"],
+        f28: freg = ["$f28","$fs4"],
+        f29: freg = ["$f29","$fs5"],
+        f30: freg = ["$f30","$fs6"],
+        f31: freg = ["$f31","$fs7"],
+        #error = ["$r0","$zero"] =>
+            "constant zero cannot be used as an operand for inline asm",
+        #error = ["$r2","$tp"] =>
+            "reserved for TLS",
+        #error = ["$r3","$sp"] =>
+            "the stack pointer cannot be used as an operand for inline asm",
+        #error = ["$r21"] =>
+            "reserved by the ABI",
+        #error = ["$r22","$fp"] =>
+            "the frame pointer cannot be used as an operand for inline asm",
+        #error = ["$r31","$s8"] =>
+            "$r31 is used internally by LLVM and cannot be used as an operand for inline asm",
+    }
+}
+
+impl LoongArchInlineAsmReg {
+    pub fn emit(
+        self,
+        out: &mut dyn fmt::Write,
+        _arch: InlineAsmArch,
+        _modifier: Option<char>,
+    ) -> fmt::Result {
+        out.write_str(self.name())
+    }
+}
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 3f9c850b352..266691b2c88 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -168,6 +168,7 @@ mod arm;
 mod avr;
 mod bpf;
 mod hexagon;
+mod loongarch;
 mod m68k;
 mod mips;
 mod msp430;
@@ -184,6 +185,7 @@ pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
 pub use avr::{AvrInlineAsmReg, AvrInlineAsmRegClass};
 pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
 pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
+pub use loongarch::{LoongArchInlineAsmReg, LoongArchInlineAsmRegClass};
 pub use m68k::{M68kInlineAsmReg, M68kInlineAsmRegClass};
 pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
 pub use msp430::{Msp430InlineAsmReg, Msp430InlineAsmRegClass};
@@ -205,6 +207,7 @@ pub enum InlineAsmArch {
     RiscV64,
     Nvptx64,
     Hexagon,
+    LoongArch64,
     Mips,
     Mips64,
     PowerPC,
@@ -234,6 +237,7 @@ impl FromStr for InlineAsmArch {
             "powerpc" => Ok(Self::PowerPC),
             "powerpc64" => Ok(Self::PowerPC64),
             "hexagon" => Ok(Self::Hexagon),
+            "loongarch64" => Ok(Self::LoongArch64),
             "mips" => Ok(Self::Mips),
             "mips64" => Ok(Self::Mips64),
             "s390x" => Ok(Self::S390x),
@@ -259,6 +263,7 @@ pub enum InlineAsmReg {
     Nvptx(NvptxInlineAsmReg),
     PowerPC(PowerPCInlineAsmReg),
     Hexagon(HexagonInlineAsmReg),
+    LoongArch(LoongArchInlineAsmReg),
     Mips(MipsInlineAsmReg),
     S390x(S390xInlineAsmReg),
     SpirV(SpirVInlineAsmReg),
@@ -280,6 +285,7 @@ impl InlineAsmReg {
             Self::RiscV(r) => r.name(),
             Self::PowerPC(r) => r.name(),
             Self::Hexagon(r) => r.name(),
+            Self::LoongArch(r) => r.name(),
             Self::Mips(r) => r.name(),
             Self::S390x(r) => r.name(),
             Self::Bpf(r) => r.name(),
@@ -298,6 +304,7 @@ impl InlineAsmReg {
             Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
             Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
             Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
+            Self::LoongArch(r) => InlineAsmRegClass::LoongArch(r.reg_class()),
             Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
             Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()),
             Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
@@ -324,6 +331,7 @@ impl InlineAsmReg {
                 Self::PowerPC(PowerPCInlineAsmReg::parse(name)?)
             }
             InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse(name)?),
+            InlineAsmArch::LoongArch64 => Self::LoongArch(LoongArchInlineAsmReg::parse(name)?),
             InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
                 Self::Mips(MipsInlineAsmReg::parse(name)?)
             }
@@ -354,6 +362,9 @@ impl InlineAsmReg {
             Self::RiscV(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
             Self::PowerPC(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
             Self::Hexagon(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
+            Self::LoongArch(r) => {
+                r.validate(arch, reloc_model, target_features, target, is_clobber)
+            }
             Self::Mips(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
             Self::S390x(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
             Self::Bpf(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
@@ -379,6 +390,7 @@ impl InlineAsmReg {
             Self::RiscV(r) => r.emit(out, arch, modifier),
             Self::PowerPC(r) => r.emit(out, arch, modifier),
             Self::Hexagon(r) => r.emit(out, arch, modifier),
+            Self::LoongArch(r) => r.emit(out, arch, modifier),
             Self::Mips(r) => r.emit(out, arch, modifier),
             Self::S390x(r) => r.emit(out, arch, modifier),
             Self::Bpf(r) => r.emit(out, arch, modifier),
@@ -397,6 +409,7 @@ impl InlineAsmReg {
             Self::RiscV(_) => cb(self),
             Self::PowerPC(r) => r.overlapping_regs(|r| cb(Self::PowerPC(r))),
             Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
+            Self::LoongArch(_) => cb(self),
             Self::Mips(_) => cb(self),
             Self::S390x(_) => cb(self),
             Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
@@ -418,6 +431,7 @@ pub enum InlineAsmRegClass {
     Nvptx(NvptxInlineAsmRegClass),
     PowerPC(PowerPCInlineAsmRegClass),
     Hexagon(HexagonInlineAsmRegClass),
+    LoongArch(LoongArchInlineAsmRegClass),
     Mips(MipsInlineAsmRegClass),
     S390x(S390xInlineAsmRegClass),
     SpirV(SpirVInlineAsmRegClass),
@@ -440,6 +454,7 @@ impl InlineAsmRegClass {
             Self::Nvptx(r) => r.name(),
             Self::PowerPC(r) => r.name(),
             Self::Hexagon(r) => r.name(),
+            Self::LoongArch(r) => r.name(),
             Self::Mips(r) => r.name(),
             Self::S390x(r) => r.name(),
             Self::SpirV(r) => r.name(),
@@ -464,6 +479,7 @@ impl InlineAsmRegClass {
             Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
             Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC),
             Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
+            Self::LoongArch(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::LoongArch),
             Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
             Self::S390x(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::S390x),
             Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
@@ -495,6 +511,7 @@ impl InlineAsmRegClass {
             Self::Nvptx(r) => r.suggest_modifier(arch, ty),
             Self::PowerPC(r) => r.suggest_modifier(arch, ty),
             Self::Hexagon(r) => r.suggest_modifier(arch, ty),
+            Self::LoongArch(r) => r.suggest_modifier(arch, ty),
             Self::Mips(r) => r.suggest_modifier(arch, ty),
             Self::S390x(r) => r.suggest_modifier(arch, ty),
             Self::SpirV(r) => r.suggest_modifier(arch, ty),
@@ -522,6 +539,7 @@ impl InlineAsmRegClass {
             Self::Nvptx(r) => r.default_modifier(arch),
             Self::PowerPC(r) => r.default_modifier(arch),
             Self::Hexagon(r) => r.default_modifier(arch),
+            Self::LoongArch(r) => r.default_modifier(arch),
             Self::Mips(r) => r.default_modifier(arch),
             Self::S390x(r) => r.default_modifier(arch),
             Self::SpirV(r) => r.default_modifier(arch),
@@ -548,6 +566,7 @@ impl InlineAsmRegClass {
             Self::Nvptx(r) => r.supported_types(arch),
             Self::PowerPC(r) => r.supported_types(arch),
             Self::Hexagon(r) => r.supported_types(arch),
+            Self::LoongArch(r) => r.supported_types(arch),
             Self::Mips(r) => r.supported_types(arch),
             Self::S390x(r) => r.supported_types(arch),
             Self::SpirV(r) => r.supported_types(arch),
@@ -575,6 +594,7 @@ impl InlineAsmRegClass {
                 Self::PowerPC(PowerPCInlineAsmRegClass::parse(name)?)
             }
             InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(name)?),
+            InlineAsmArch::LoongArch64 => Self::LoongArch(LoongArchInlineAsmRegClass::parse(name)?),
             InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
                 Self::Mips(MipsInlineAsmRegClass::parse(name)?)
             }
@@ -601,6 +621,7 @@ impl InlineAsmRegClass {
             Self::Nvptx(r) => r.valid_modifiers(arch),
             Self::PowerPC(r) => r.valid_modifiers(arch),
             Self::Hexagon(r) => r.valid_modifiers(arch),
+            Self::LoongArch(r) => r.valid_modifiers(arch),
             Self::Mips(r) => r.valid_modifiers(arch),
             Self::S390x(r) => r.valid_modifiers(arch),
             Self::SpirV(r) => r.valid_modifiers(arch),
@@ -760,6 +781,11 @@ pub fn allocatable_registers(
             hexagon::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
             map
         }
+        InlineAsmArch::LoongArch64 => {
+            let mut map = loongarch::regclass_map();
+            loongarch::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
+            map
+        }
         InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
             let mut map = mips::regclass_map();
             mips::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 8e7097ce4a7..c97473e6241 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -86,8 +86,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     ) -> QueryResult<'tcx> {
         if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
             && poly_trait_pred.def_id() == goal.predicate.def_id()
+            && poly_trait_pred.polarity() == goal.predicate.polarity
         {
-            // FIXME: Constness and polarity
+            // FIXME: Constness
             ecx.probe(|ecx| {
                 let assumption_trait_pred =
                     ecx.instantiate_binder_with_infer(poly_trait_pred);
@@ -111,6 +112,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     ) -> QueryResult<'tcx> {
         if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
             && poly_trait_pred.def_id() == goal.predicate.def_id()
+            && poly_trait_pred.polarity() == goal.predicate.polarity
         {
             // FIXME: Constness and polarity
             ecx.probe(|ecx| {
@@ -147,6 +149,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
         if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) {
             return result;
         }
@@ -161,6 +167,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
         let tcx = ecx.tcx();
 
         ecx.probe(|ecx| {
@@ -176,6 +186,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
         ecx.probe_and_evaluate_goal_for_constituent_tys(
             goal,
             structural_traits::instantiate_constituent_tys_for_sized_trait,
@@ -186,6 +200,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
         ecx.probe_and_evaluate_goal_for_constituent_tys(
             goal,
             structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
@@ -196,6 +214,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
         if goal.predicate.self_ty().has_non_region_infer() {
             return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
         }
@@ -217,6 +239,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
         if let ty::FnPtr(..) = goal.predicate.self_ty().kind() {
             ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         } else {
@@ -229,6 +255,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         goal: Goal<'tcx, Self>,
         goal_kind: ty::ClosureKind,
     ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
         let tcx = ecx.tcx();
         let tupled_inputs_and_output =
             match structural_traits::extract_tupled_inputs_and_output_from_callable(
@@ -259,6 +289,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
         if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
             ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         } else {
@@ -268,8 +302,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
 
     fn consider_builtin_pointee_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
-        _goal: Goal<'tcx, Self>,
+        goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
         ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
 
@@ -277,6 +315,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
         let ty::Generator(def_id, _, _) = *goal.predicate.self_ty().kind() else {
             return Err(NoSolution);
         };
@@ -297,6 +339,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
         let self_ty = goal.predicate.self_ty();
         let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
             return Err(NoSolution);
@@ -326,6 +372,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
         let tcx = ecx.tcx();
         let a_ty = goal.predicate.self_ty();
         let b_ty = goal.predicate.trait_ref.substs.type_at(1);
@@ -447,6 +497,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> Vec<CanonicalResponse<'tcx>> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return vec![];
+        }
+
         let tcx = ecx.tcx();
 
         let a_ty = goal.predicate.self_ty();
@@ -521,8 +575,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
 
     fn consider_builtin_discriminant_kind_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
-        _goal: Goal<'tcx, Self>,
+        goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
         // `DiscriminantKind` is automatically implemented for every type.
         ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
@@ -531,6 +589,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
         if !goal.param_env.is_const() {
             // `Destruct` is automatically implemented for every type in
             // non-const environments.
@@ -545,6 +607,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+            return Err(NoSolution);
+        }
+
         // `rustc_transmute` does not have support for type or const params
         if goal.has_non_region_placeholders() {
             return Err(NoSolution);
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 222af4c2ace..e82672e8368 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -591,7 +591,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
     fn evaluate_nested_obligations(
         &self,
         ty: Ty<'_>,
-        nested: impl Iterator<Item = Obligation<'tcx, ty::Predicate<'tcx>>>,
+        nested: impl Iterator<Item = PredicateObligation<'tcx>>,
         computed_preds: &mut FxIndexSet<ty::Predicate<'tcx>>,
         fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
         predicates: &mut VecDeque<ty::PolyTraitPredicate<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 61e382bbe49..ce187fbdf84 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -15,8 +15,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use crate::traits::query::normalize::QueryNormalizeExt as _;
 use crate::traits::specialize::to_pretty_impl_header;
 use crate::traits::NormalizeExt;
-use on_unimplemented::OnUnimplementedNote;
-use on_unimplemented::TypeErrCtxtExt as _;
+use on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
@@ -706,35 +705,19 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                      conversion on the error value using the `From` trait"
                                         .to_owned(),
                                 ),
-                                Some(None),
+                                Some(AppendConstMessage::Default),
                             )
                         } else {
                             (message, note, append_const_msg)
                         };
 
-                        let err_msg = message
-                            .and_then(|cannot_do_this| {
-                                match (predicate_is_const, append_const_msg) {
-                                    // do nothing if predicate is not const
-                                    (false, _) => Some(cannot_do_this),
-                                    // suggested using default post message
-                                    (true, Some(None)) => {
-                                        Some(format!("{cannot_do_this} in const contexts"))
-                                    }
-                                    // overridden post message
-                                    (true, Some(Some(post_message))) => {
-                                        Some(format!("{cannot_do_this}{post_message}"))
-                                    }
-                                    // fallback to generic message
-                                    (true, None) => None,
-                                }
-                            })
-                            .unwrap_or_else(|| {
-                                format!(
-                                    "the trait bound `{}` is not satisfied{}",
-                                    trait_predicate, post_message,
-                                )
-                            });
+                        let err_msg = self.get_standard_error_message(
+                            &trait_predicate,
+                            message,
+                            predicate_is_const,
+                            append_const_msg,
+                            post_message,
+                        );
 
                         let (err_msg, safe_transmute_explanation) = if Some(trait_ref.def_id())
                             == self.tcx.lang_items().transmute_trait()
@@ -762,22 +745,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         }
 
                         if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
-                            match obligation.cause.code().peel_derives() {
-                                ObligationCauseCode::RustCall => {
-                                    err.set_primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument");
-                                }
-                                ObligationCauseCode::BindingObligation(def_id, _)
-                                | ObligationCauseCode::ItemObligation(def_id)
-                                    if tcx.is_fn_trait(*def_id) =>
-                                {
-                                    err.code(rustc_errors::error_code!(E0059));
-                                    err.set_primary_message(format!(
-                                        "type parameter to bare `{}` trait must be a tuple",
-                                        tcx.def_path_str(*def_id)
-                                    ));
-                                }
-                                _ => {}
-                            }
+                            self.add_tuple_trait_message(
+                                &obligation.cause.code().peel_derives(),
+                                &mut err,
+                            );
                         }
 
                         if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait()
@@ -787,33 +758,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             err.note("See <https://github.com/rust-lang/rust/pull/94901> for more details");
                         }
 
-                        let explanation = if let ObligationCauseCode::MainFunctionType =
-                            obligation.cause.code()
-                        {
-                            "consider using `()`, or a `Result`".to_owned()
-                        } else {
-                            let ty_desc = match trait_ref.skip_binder().self_ty().kind() {
-                                ty::FnDef(_, _) => Some("fn item"),
-                                ty::Closure(_, _) => Some("closure"),
-                                _ => None,
-                            };
+                        let explanation = get_explanation_based_on_obligation(
+                            &obligation,
+                            trait_ref,
+                            &trait_predicate,
+                            pre_message,
+                        );
 
-                            match ty_desc {
-                                Some(desc) => format!(
-                                    "{}the trait `{}` is not implemented for {} `{}`",
-                                    pre_message,
-                                    trait_predicate.print_modifiers_and_trait_path(),
-                                    desc,
-                                    trait_ref.skip_binder().self_ty(),
-                                ),
-                                None => format!(
-                                    "{}the trait `{}` is not implemented for `{}`",
-                                    pre_message,
-                                    trait_predicate.print_modifiers_and_trait_path(),
-                                    trait_ref.skip_binder().self_ty(),
-                                ),
-                            }
-                        };
                         self.check_for_binding_assigned_block_without_tail_expression(
                             &obligation,
                             &mut err,
@@ -850,28 +801,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty);
                         }
 
-                        let mut unsatisfied_const = false;
-                        if trait_predicate.is_const_if_const() && obligation.param_env.is_const() {
-                            let non_const_predicate = trait_ref.without_const();
-                            let non_const_obligation = Obligation {
-                                cause: obligation.cause.clone(),
-                                param_env: obligation.param_env.without_const(),
-                                predicate: non_const_predicate.to_predicate(tcx),
-                                recursion_depth: obligation.recursion_depth,
-                            };
-                            if self.predicate_may_hold(&non_const_obligation) {
-                                unsatisfied_const = true;
-                                err.span_note(
-                                    span,
-                                    &format!(
-                                        "the trait `{}` is implemented for `{}`, \
-                                        but that implementation is not `const`",
-                                        non_const_predicate.print_modifiers_and_trait_path(),
-                                        trait_ref.skip_binder().self_ty(),
-                                    ),
-                                );
-                            }
-                        }
+                        let UnsatisfiedConst(unsatisfied_const) = self
+                            .maybe_add_note_for_unsatisfied_const(
+                                &obligation,
+                                trait_ref,
+                                &trait_predicate,
+                                &mut err,
+                                span,
+                            );
 
                         if let Some((msg, span)) = type_def {
                             err.span_label(span, &msg);
@@ -969,137 +906,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             );
                         }
 
-                        let body_def_id = obligation.cause.body_id;
-                        // Try to report a help message
-                        if is_fn_trait
-                            && let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
-                            obligation.param_env,
-                            trait_ref.self_ty(),
-                            trait_predicate.skip_binder().constness,
-                            trait_predicate.skip_binder().polarity,
-                        )
-                        {
-                            // If the type implements `Fn`, `FnMut`, or `FnOnce`, suppress the following
-                            // suggestion to add trait bounds for the type, since we only typically implement
-                            // these traits once.
-
-                            // Note if the `FnMut` or `FnOnce` is less general than the trait we're trying
-                            // to implement.
-                            let selected_kind =
-                                self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id())
-                                    .expect("expected to map DefId to ClosureKind");
-                            if !implemented_kind.extends(selected_kind) {
-                                err.note(
-                                    &format!(
-                                        "`{}` implements `{}`, but it must implement `{}`, which is more general",
-                                        trait_ref.skip_binder().self_ty(),
-                                        implemented_kind,
-                                        selected_kind
-                                    )
-                                );
-                            }
-
-                            // Note any argument mismatches
-                            let given_ty = params.skip_binder();
-                            let expected_ty = trait_ref.skip_binder().substs.type_at(1);
-                            if let ty::Tuple(given) = given_ty.kind()
-                                && let ty::Tuple(expected) = expected_ty.kind()
-                            {
-                                if expected.len() != given.len() {
-                                    // Note number of types that were expected and given
-                                    err.note(
-                                        &format!(
-                                            "expected a closure taking {} argument{}, but one taking {} argument{} was given",
-                                            given.len(),
-                                            pluralize!(given.len()),
-                                            expected.len(),
-                                            pluralize!(expected.len()),
-                                        )
-                                    );
-                                } else if !self.same_type_modulo_infer(given_ty, expected_ty) {
-                                    // Print type mismatch
-                                    let (expected_args, given_args) =
-                                        self.cmp(given_ty, expected_ty);
-                                    err.note_expected_found(
-                                        &"a closure with arguments",
-                                        expected_args,
-                                        &"a closure with arguments",
-                                        given_args,
-                                    );
-                                }
-                            }
-                        } else if !trait_ref.has_non_region_infer()
-                            && self.predicate_can_apply(obligation.param_env, trait_predicate)
-                        {
-                            // If a where-clause may be useful, remind the
-                            // user that they can add it.
-                            //
-                            // don't display an on-unimplemented note, as
-                            // these notes will often be of the form
-                            //     "the type `T` can't be frobnicated"
-                            // which is somewhat confusing.
-                            self.suggest_restricting_param_bound(
-                                &mut err,
-                                trait_predicate,
-                                None,
-                                obligation.cause.body_id,
-                            );
-                        } else if !suggested && !unsatisfied_const {
-                            // Can't show anything else useful, try to find similar impls.
-                            let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
-                            if !self.report_similar_impl_candidates(
-                                &impl_candidates,
-                                trait_ref,
-                                body_def_id,
-                                &mut err,
-                                true,
-                            ) {
-                                // This is *almost* equivalent to
-                                // `obligation.cause.code().peel_derives()`, but it gives us the
-                                // trait predicate for that corresponding root obligation. This
-                                // lets us get a derived obligation from a type parameter, like
-                                // when calling `string.strip_suffix(p)` where `p` is *not* an
-                                // implementer of `Pattern<'_>`.
-                                let mut code = obligation.cause.code();
-                                let mut trait_pred = trait_predicate;
-                                let mut peeled = false;
-                                while let Some((parent_code, parent_trait_pred)) = code.parent() {
-                                    code = parent_code;
-                                    if let Some(parent_trait_pred) = parent_trait_pred {
-                                        trait_pred = parent_trait_pred;
-                                        peeled = true;
-                                    }
-                                }
-                                let def_id = trait_pred.def_id();
-                                // Mention *all* the `impl`s for the *top most* obligation, the
-                                // user might have meant to use one of them, if any found. We skip
-                                // auto-traits or fundamental traits that might not be exactly what
-                                // the user might expect to be presented with. Instead this is
-                                // useful for less general traits.
-                                if peeled
-                                    && !self.tcx.trait_is_auto(def_id)
-                                    && !self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
-                                {
-                                    let trait_ref = trait_pred.to_poly_trait_ref();
-                                    let impl_candidates =
-                                        self.find_similar_impl_candidates(trait_pred);
-                                    self.report_similar_impl_candidates(
-                                        &impl_candidates,
-                                        trait_ref,
-                                        body_def_id,
-                                        &mut err,
-                                        true,
-                                    );
-                                }
-                            }
-
-                            self.maybe_suggest_convert_to_slice(
-                                &mut err,
-                                trait_ref,
-                                impl_candidates.as_slice(),
-                                span,
-                            );
-                        }
+                        self.try_to_add_help_message(
+                            &obligation,
+                            trait_ref,
+                            &trait_predicate,
+                            &mut err,
+                            span,
+                            is_fn_trait,
+                            suggested,
+                            unsatisfied_const,
+                        );
 
                         // Changing mutability doesn't make a difference to whether we have
                         // an `Unsize` impl (Fixes ICE in #71036)
@@ -1194,59 +1010,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
                     ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
                         let found_kind = self.closure_kind(closure_substs).unwrap();
-                        let closure_span = self.tcx.def_span(closure_def_id);
-                        let mut err = struct_span_err!(
-                            self.tcx.sess,
-                            closure_span,
-                            E0525,
-                            "expected a closure that implements the `{}` trait, \
-                             but this closure only implements `{}`",
-                            kind,
-                            found_kind
-                        );
-
-                        err.span_label(
-                            closure_span,
-                            format!("this closure implements `{}`, not `{}`", found_kind, kind),
-                        );
-                        err.span_label(
-                            obligation.cause.span,
-                            format!("the requirement to implement `{}` derives from here", kind),
-                        );
-
-                        // Additional context information explaining why the closure only implements
-                        // a particular trait.
-                        if let Some(typeck_results) = &self.typeck_results {
-                            let hir_id = self
-                                .tcx
-                                .hir()
-                                .local_def_id_to_hir_id(closure_def_id.expect_local());
-                            match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
-                                (ty::ClosureKind::FnOnce, Some((span, place))) => {
-                                    err.span_label(
-                                        *span,
-                                        format!(
-                                            "closure is `FnOnce` because it moves the \
-                                         variable `{}` out of its environment",
-                                            ty::place_to_string_for_capture(tcx, place)
-                                        ),
-                                    );
-                                }
-                                (ty::ClosureKind::FnMut, Some((span, place))) => {
-                                    err.span_label(
-                                        *span,
-                                        format!(
-                                            "closure is `FnMut` because it mutates the \
-                                         variable `{}` here",
-                                            ty::place_to_string_for_capture(tcx, place)
-                                        ),
-                                    );
-                                }
-                                _ => {}
-                            }
-                        }
-
-                        err
+                        self.report_closure_error(&obligation, closure_def_id, found_kind, kind)
                     }
 
                     ty::PredicateKind::WellFormed(ty) => {
@@ -1327,117 +1091,21 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 found_trait_ref,
                 expected_trait_ref,
                 terr @ TypeError::CyclicTy(_),
-            ) => {
-                let self_ty = found_trait_ref.self_ty().skip_binder();
-                let (cause, terr) = if let ty::Closure(def_id, _) = self_ty.kind() {
-                    (
-                        ObligationCause::dummy_with_span(tcx.def_span(def_id)),
-                        TypeError::CyclicTy(self_ty),
-                    )
-                } else {
-                    (obligation.cause.clone(), terr)
-                };
-                self.report_and_explain_type_error(
-                    TypeTrace::poly_trait_refs(&cause, true, expected_trait_ref, found_trait_ref),
-                    terr,
-                )
-            }
+            ) => self.report_type_parameter_mismatch_cyclic_type_error(
+                &obligation,
+                found_trait_ref,
+                expected_trait_ref,
+                terr,
+            ),
             OutputTypeParameterMismatch(found_trait_ref, expected_trait_ref, _) => {
-                let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref);
-                let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref);
-
-                if expected_trait_ref.self_ty().references_error() {
-                    return;
-                }
-
-                let Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else {
-                    return;
-                };
-
-                let found_did = match *found_trait_ty.kind() {
-                    ty::Closure(did, _)
-                    | ty::Foreign(did)
-                    | ty::FnDef(did, _)
-                    | ty::Generator(did, ..) => Some(did),
-                    ty::Adt(def, _) => Some(def.did()),
-                    _ => None,
-                };
-
-                let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did));
-                let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did));
-
-                if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) {
-                    // We check closures twice, with obligations flowing in different directions,
-                    // but we want to complain about them only once.
-                    return;
-                }
-
-                self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
-
-                let mut not_tupled = false;
-
-                let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() {
-                    ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
-                    _ => {
-                        not_tupled = true;
-                        vec![ArgKind::empty()]
-                    }
-                };
-
-                let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
-                let expected = match expected_ty.kind() {
-                    ty::Tuple(ref tys) => {
-                        tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect()
-                    }
-                    _ => {
-                        not_tupled = true;
-                        vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())]
-                    }
-                };
-
-                // If this is a `Fn` family trait and either the expected or found
-                // is not tupled, then fall back to just a regular mismatch error.
-                // This shouldn't be common unless manually implementing one of the
-                // traits manually, but don't make it more confusing when it does
-                // happen.
-                if Some(expected_trait_ref.def_id()) != tcx.lang_items().gen_trait() && not_tupled {
-                    self.report_and_explain_type_error(
-                        TypeTrace::poly_trait_refs(
-                            &obligation.cause,
-                            true,
-                            expected_trait_ref,
-                            found_trait_ref,
-                        ),
-                        ty::error::TypeError::Mismatch,
-                    )
-                } else if found.len() == expected.len() {
-                    self.report_closure_arg_mismatch(
-                        span,
-                        found_span,
-                        found_trait_ref,
-                        expected_trait_ref,
-                        obligation.cause.code(),
-                        found_node,
-                        obligation.param_env,
-                    )
-                } else {
-                    let (closure_span, closure_arg_span, found) = found_did
-                        .and_then(|did| {
-                            let node = self.tcx.hir().get_if_local(did)?;
-                            let (found_span, closure_arg_span, found) =
-                                self.get_fn_like_arguments(node)?;
-                            Some((Some(found_span), closure_arg_span, found))
-                        })
-                        .unwrap_or((found_span, None, found));
-
-                    self.report_arg_count_mismatch(
-                        span,
-                        closure_span,
-                        expected,
-                        found,
-                        found_trait_ty.is_closure(),
-                        closure_arg_span,
-                    )
+                match self.report_type_parameter_mismatch_error(
+                    &obligation,
+                    span,
+                    found_trait_ref,
+                    expected_trait_ref,
+                ) {
+                    Some(err) => err,
+                    None => return,
                 }
             }
 
@@ -1452,45 +1120,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 )
             }
             SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => {
-                if !self.tcx.features().generic_const_exprs {
-                    let mut err = self.tcx.sess.struct_span_err(
-                        span,
-                        "constant expression depends on a generic parameter",
-                    );
-                    // FIXME(const_generics): we should suggest to the user how they can resolve this
-                    // issue. However, this is currently not actually possible
-                    // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083).
-                    //
-                    // Note that with `feature(generic_const_exprs)` this case should not
-                    // be reachable.
-                    err.note("this may fail depending on what value the parameter takes");
-                    err.emit();
-                    return;
-                }
-
-                match obligation.predicate.kind().skip_binder() {
-                    ty::PredicateKind::ConstEvaluatable(ct) => {
-                        let ty::ConstKind::Unevaluated(uv) = ct.kind() else {
-                            bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
-                        };
-                        let mut err =
-                            self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
-                        let const_span = self.tcx.def_span(uv.def);
-                        match self.tcx.sess.source_map().span_to_snippet(const_span) {
-                            Ok(snippet) => err.help(&format!(
-                                "try adding a `where` bound using this expression: `where [(); {}]:`",
-                                snippet
-                            )),
-                            _ => err.help("consider adding a `where` bound using this expression"),
-                        };
-                        err
-                    }
-                    _ => {
-                        span_bug!(
-                            span,
-                            "unexpected non-ConstEvaluatable predicate, this should not be reachable"
-                        )
-                    }
+                match self.report_not_const_evaluatable_error(&obligation, span) {
+                    Some(err) => err,
+                    None => return,
                 }
             }
 
@@ -1562,6 +1194,14 @@ trait InferCtxtPrivExt<'tcx> {
         other: bool,
     ) -> bool;
 
+    fn report_similar_impl_candidates_for_root_obligation(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
+        body_def_id: LocalDefId,
+        err: &mut Diagnostic,
+    );
+
     /// Gets the parent trait chain start
     fn get_parent_trait_ref(
         &self,
@@ -1625,12 +1265,86 @@ trait InferCtxtPrivExt<'tcx> {
         cause_code: &ObligationCauseCode<'tcx>,
     ) -> bool;
 
+    fn get_standard_error_message(
+        &self,
+        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+        message: Option<String>,
+        predicate_is_const: bool,
+        append_const_msg: Option<AppendConstMessage>,
+        post_message: String,
+    ) -> String;
+
     fn get_safe_transmute_error_and_reason(
         &self,
-        obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        obligation: PredicateObligation<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
         span: Span,
     ) -> (String, Option<String>);
+
+    fn add_tuple_trait_message(
+        &self,
+        obligation_cause_code: &ObligationCauseCode<'tcx>,
+        err: &mut Diagnostic,
+    );
+
+    fn try_to_add_help_message(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+        err: &mut Diagnostic,
+        span: Span,
+        is_fn_trait: bool,
+        suggested: bool,
+        unsatisfied_const: bool,
+    );
+
+    fn add_help_message_for_fn_trait(
+        &self,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        err: &mut Diagnostic,
+        implemented_kind: ty::ClosureKind,
+        params: ty::Binder<'tcx, Ty<'tcx>>,
+    );
+
+    fn maybe_add_note_for_unsatisfied_const(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+        err: &mut Diagnostic,
+        span: Span,
+    ) -> UnsatisfiedConst;
+
+    fn report_closure_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        closure_def_id: DefId,
+        found_kind: ty::ClosureKind,
+        kind: ty::ClosureKind,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+
+    fn report_type_parameter_mismatch_cyclic_type_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        terr: TypeError<'tcx>,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+
+    fn report_type_parameter_mismatch_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        span: Span,
+        found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+    ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
+
+    fn report_not_const_evaluatable_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        span: Span,
+    ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
 }
 
 impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
@@ -2198,6 +1912,51 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         report(normalized_impl_candidates, err)
     }
 
+    fn report_similar_impl_candidates_for_root_obligation(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
+        body_def_id: LocalDefId,
+        err: &mut Diagnostic,
+    ) {
+        // This is *almost* equivalent to
+        // `obligation.cause.code().peel_derives()`, but it gives us the
+        // trait predicate for that corresponding root obligation. This
+        // lets us get a derived obligation from a type parameter, like
+        // when calling `string.strip_suffix(p)` where `p` is *not* an
+        // implementer of `Pattern<'_>`.
+        let mut code = obligation.cause.code();
+        let mut trait_pred = trait_predicate;
+        let mut peeled = false;
+        while let Some((parent_code, parent_trait_pred)) = code.parent() {
+            code = parent_code;
+            if let Some(parent_trait_pred) = parent_trait_pred {
+                trait_pred = parent_trait_pred;
+                peeled = true;
+            }
+        }
+        let def_id = trait_pred.def_id();
+        // Mention *all* the `impl`s for the *top most* obligation, the
+        // user might have meant to use one of them, if any found. We skip
+        // auto-traits or fundamental traits that might not be exactly what
+        // the user might expect to be presented with. Instead this is
+        // useful for less general traits.
+        if peeled
+            && !self.tcx.trait_is_auto(def_id)
+            && !self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
+        {
+            let trait_ref = trait_pred.to_poly_trait_ref();
+            let impl_candidates = self.find_similar_impl_candidates(trait_pred);
+            self.report_similar_impl_candidates(
+                &impl_candidates,
+                trait_ref,
+                body_def_id,
+                err,
+                true,
+            );
+        }
+    }
+
     /// Gets the parent trait chain start
     fn get_parent_trait_ref(
         &self,
@@ -2930,10 +2689,40 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         false
     }
 
+    fn get_standard_error_message(
+        &self,
+        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+        message: Option<String>,
+        predicate_is_const: bool,
+        append_const_msg: Option<AppendConstMessage>,
+        post_message: String,
+    ) -> String {
+        message
+            .and_then(|cannot_do_this| {
+                match (predicate_is_const, append_const_msg) {
+                    // do nothing if predicate is not const
+                    (false, _) => Some(cannot_do_this),
+                    // suggested using default post message
+                    (true, Some(AppendConstMessage::Default)) => {
+                        Some(format!("{cannot_do_this} in const contexts"))
+                    }
+                    // overridden post message
+                    (true, Some(AppendConstMessage::Custom(custom_msg))) => {
+                        Some(format!("{cannot_do_this}{custom_msg}"))
+                    }
+                    // fallback to generic message
+                    (true, None) => None,
+                }
+            })
+            .unwrap_or_else(|| {
+                format!("the trait bound `{}` is not satisfied{}", trait_predicate, post_message)
+            })
+    }
+
     fn get_safe_transmute_error_and_reason(
         &self,
-        obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        obligation: PredicateObligation<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
         span: Span,
     ) -> (String, Option<String>) {
         // Erase regions because layout code doesn't particularly care about regions.
@@ -2991,8 +2780,449 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             _ => span_bug!(span, "Unsupported rustc_transmute::Reason variant"),
         }
     }
+
+    fn add_tuple_trait_message(
+        &self,
+        obligation_cause_code: &ObligationCauseCode<'tcx>,
+        err: &mut Diagnostic,
+    ) {
+        match obligation_cause_code {
+            ObligationCauseCode::RustCall => {
+                err.set_primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument");
+            }
+            ObligationCauseCode::BindingObligation(def_id, _)
+            | ObligationCauseCode::ItemObligation(def_id)
+                if self.tcx.is_fn_trait(*def_id) =>
+            {
+                err.code(rustc_errors::error_code!(E0059));
+                err.set_primary_message(format!(
+                    "type parameter to bare `{}` trait must be a tuple",
+                    self.tcx.def_path_str(*def_id)
+                ));
+            }
+            _ => {}
+        }
+    }
+
+    fn try_to_add_help_message(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+        err: &mut Diagnostic,
+        span: Span,
+        is_fn_trait: bool,
+        suggested: bool,
+        unsatisfied_const: bool,
+    ) {
+        let body_def_id = obligation.cause.body_id;
+        // Try to report a help message
+        if is_fn_trait
+            && let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
+            obligation.param_env,
+            trait_ref.self_ty(),
+            trait_predicate.skip_binder().constness,
+            trait_predicate.skip_binder().polarity,
+        )
+        {
+            self.add_help_message_for_fn_trait(trait_ref, err, implemented_kind, params);
+        } else if !trait_ref.has_non_region_infer()
+            && self.predicate_can_apply(obligation.param_env, *trait_predicate)
+        {
+            // If a where-clause may be useful, remind the
+            // user that they can add it.
+            //
+            // don't display an on-unimplemented note, as
+            // these notes will often be of the form
+            //     "the type `T` can't be frobnicated"
+            // which is somewhat confusing.
+            self.suggest_restricting_param_bound(
+                err,
+                *trait_predicate,
+                None,
+                obligation.cause.body_id,
+            );
+        } else if !suggested && !unsatisfied_const {
+            // Can't show anything else useful, try to find similar impls.
+            let impl_candidates = self.find_similar_impl_candidates(*trait_predicate);
+            if !self.report_similar_impl_candidates(
+                &impl_candidates,
+                trait_ref,
+                body_def_id,
+                err,
+                true,
+            ) {
+                self.report_similar_impl_candidates_for_root_obligation(&obligation, *trait_predicate, body_def_id, err);
+            }
+
+            self.maybe_suggest_convert_to_slice(
+                err,
+                trait_ref,
+                impl_candidates.as_slice(),
+                span,
+            );
+        }
+    }
+
+    fn add_help_message_for_fn_trait(
+        &self,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        err: &mut Diagnostic,
+        implemented_kind: ty::ClosureKind,
+        params: ty::Binder<'tcx, Ty<'tcx>>,
+    ) {
+        // If the type implements `Fn`, `FnMut`, or `FnOnce`, suppress the following
+        // suggestion to add trait bounds for the type, since we only typically implement
+        // these traits once.
+
+        // Note if the `FnMut` or `FnOnce` is less general than the trait we're trying
+        // to implement.
+        let selected_kind = self
+            .tcx
+            .fn_trait_kind_from_def_id(trait_ref.def_id())
+            .expect("expected to map DefId to ClosureKind");
+        if !implemented_kind.extends(selected_kind) {
+            err.note(&format!(
+                "`{}` implements `{}`, but it must implement `{}`, which is more general",
+                trait_ref.skip_binder().self_ty(),
+                implemented_kind,
+                selected_kind
+            ));
+        }
+
+        // Note any argument mismatches
+        let given_ty = params.skip_binder();
+        let expected_ty = trait_ref.skip_binder().substs.type_at(1);
+        if let ty::Tuple(given) = given_ty.kind()
+            && let ty::Tuple(expected) = expected_ty.kind()
+        {
+            if expected.len() != given.len() {
+                // Note number of types that were expected and given
+                err.note(
+                    &format!(
+                        "expected a closure taking {} argument{}, but one taking {} argument{} was given",
+                        given.len(),
+                        pluralize!(given.len()),
+                        expected.len(),
+                        pluralize!(expected.len()),
+                    )
+                );
+            } else if !self.same_type_modulo_infer(given_ty, expected_ty) {
+                // Print type mismatch
+                let (expected_args, given_args) =
+                    self.cmp(given_ty, expected_ty);
+                err.note_expected_found(
+                    &"a closure with arguments",
+                    expected_args,
+                    &"a closure with arguments",
+                    given_args,
+                );
+            }
+        }
+    }
+
+    fn maybe_add_note_for_unsatisfied_const(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+        err: &mut Diagnostic,
+        span: Span,
+    ) -> UnsatisfiedConst {
+        let mut unsatisfied_const = UnsatisfiedConst(false);
+        if trait_predicate.is_const_if_const() && obligation.param_env.is_const() {
+            let non_const_predicate = trait_ref.without_const();
+            let non_const_obligation = Obligation {
+                cause: obligation.cause.clone(),
+                param_env: obligation.param_env.without_const(),
+                predicate: non_const_predicate.to_predicate(self.tcx),
+                recursion_depth: obligation.recursion_depth,
+            };
+            if self.predicate_may_hold(&non_const_obligation) {
+                unsatisfied_const = UnsatisfiedConst(true);
+                err.span_note(
+                    span,
+                    &format!(
+                        "the trait `{}` is implemented for `{}`, \
+                        but that implementation is not `const`",
+                        non_const_predicate.print_modifiers_and_trait_path(),
+                        trait_ref.skip_binder().self_ty(),
+                    ),
+                );
+            }
+        }
+        unsatisfied_const
+    }
+
+    fn report_closure_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        closure_def_id: DefId,
+        found_kind: ty::ClosureKind,
+        kind: ty::ClosureKind,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+        let closure_span = self.tcx.def_span(closure_def_id);
+        let mut err = struct_span_err!(
+            self.tcx.sess,
+            closure_span,
+            E0525,
+            "expected a closure that implements the `{}` trait, \
+                but this closure only implements `{}`",
+            kind,
+            found_kind
+        );
+
+        err.span_label(
+            closure_span,
+            format!("this closure implements `{}`, not `{}`", found_kind, kind),
+        );
+        err.span_label(
+            obligation.cause.span,
+            format!("the requirement to implement `{}` derives from here", kind),
+        );
+
+        // Additional context information explaining why the closure only implements
+        // a particular trait.
+        if let Some(typeck_results) = &self.typeck_results {
+            let hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
+            match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
+                (ty::ClosureKind::FnOnce, Some((span, place))) => {
+                    err.span_label(
+                        *span,
+                        format!(
+                            "closure is `FnOnce` because it moves the \
+                            variable `{}` out of its environment",
+                            ty::place_to_string_for_capture(self.tcx, place)
+                        ),
+                    );
+                }
+                (ty::ClosureKind::FnMut, Some((span, place))) => {
+                    err.span_label(
+                        *span,
+                        format!(
+                            "closure is `FnMut` because it mutates the \
+                            variable `{}` here",
+                            ty::place_to_string_for_capture(self.tcx, place)
+                        ),
+                    );
+                }
+                _ => {}
+            }
+        }
+
+        err
+    }
+
+    fn report_type_parameter_mismatch_cyclic_type_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        terr: TypeError<'tcx>,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+        let self_ty = found_trait_ref.self_ty().skip_binder();
+        let (cause, terr) = if let ty::Closure(def_id, _) = self_ty.kind() {
+            (
+                ObligationCause::dummy_with_span(self.tcx.def_span(def_id)),
+                TypeError::CyclicTy(self_ty),
+            )
+        } else {
+            (obligation.cause.clone(), terr)
+        };
+        self.report_and_explain_type_error(
+            TypeTrace::poly_trait_refs(&cause, true, expected_trait_ref, found_trait_ref),
+            terr,
+        )
+    }
+
+    fn report_type_parameter_mismatch_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        span: Span,
+        found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+    ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
+        let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref);
+        let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref);
+
+        if expected_trait_ref.self_ty().references_error() {
+            return None;
+        }
+
+        let Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else {
+            return None;
+        };
+
+        let found_did = match *found_trait_ty.kind() {
+            ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) | ty::Generator(did, ..) => {
+                Some(did)
+            }
+            ty::Adt(def, _) => Some(def.did()),
+            _ => None,
+        };
+
+        let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did));
+        let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did));
+
+        if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) {
+            // We check closures twice, with obligations flowing in different directions,
+            // but we want to complain about them only once.
+            return None;
+        }
+
+        self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
+
+        let mut not_tupled = false;
+
+        let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() {
+            ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
+            _ => {
+                not_tupled = true;
+                vec![ArgKind::empty()]
+            }
+        };
+
+        let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
+        let expected = match expected_ty.kind() {
+            ty::Tuple(ref tys) => {
+                tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect()
+            }
+            _ => {
+                not_tupled = true;
+                vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())]
+            }
+        };
+
+        // If this is a `Fn` family trait and either the expected or found
+        // is not tupled, then fall back to just a regular mismatch error.
+        // This shouldn't be common unless manually implementing one of the
+        // traits manually, but don't make it more confusing when it does
+        // happen.
+        Some(
+            if Some(expected_trait_ref.def_id()) != self.tcx.lang_items().gen_trait() && not_tupled
+            {
+                self.report_and_explain_type_error(
+                    TypeTrace::poly_trait_refs(
+                        &obligation.cause,
+                        true,
+                        expected_trait_ref,
+                        found_trait_ref,
+                    ),
+                    ty::error::TypeError::Mismatch,
+                )
+            } else if found.len() == expected.len() {
+                self.report_closure_arg_mismatch(
+                    span,
+                    found_span,
+                    found_trait_ref,
+                    expected_trait_ref,
+                    obligation.cause.code(),
+                    found_node,
+                    obligation.param_env,
+                )
+            } else {
+                let (closure_span, closure_arg_span, found) = found_did
+                    .and_then(|did| {
+                        let node = self.tcx.hir().get_if_local(did)?;
+                        let (found_span, closure_arg_span, found) =
+                            self.get_fn_like_arguments(node)?;
+                        Some((Some(found_span), closure_arg_span, found))
+                    })
+                    .unwrap_or((found_span, None, found));
+
+                self.report_arg_count_mismatch(
+                    span,
+                    closure_span,
+                    expected,
+                    found,
+                    found_trait_ty.is_closure(),
+                    closure_arg_span,
+                )
+            },
+        )
+    }
+
+    fn report_not_const_evaluatable_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        span: Span,
+    ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
+        if !self.tcx.features().generic_const_exprs {
+            let mut err = self
+                .tcx
+                .sess
+                .struct_span_err(span, "constant expression depends on a generic parameter");
+            // FIXME(const_generics): we should suggest to the user how they can resolve this
+            // issue. However, this is currently not actually possible
+            // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083).
+            //
+            // Note that with `feature(generic_const_exprs)` this case should not
+            // be reachable.
+            err.note("this may fail depending on what value the parameter takes");
+            err.emit();
+            return None;
+        }
+
+        match obligation.predicate.kind().skip_binder() {
+            ty::PredicateKind::ConstEvaluatable(ct) => {
+                let ty::ConstKind::Unevaluated(uv) = ct.kind() else {
+                    bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
+                };
+                let mut err = self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
+                let const_span = self.tcx.def_span(uv.def);
+                match self.tcx.sess.source_map().span_to_snippet(const_span) {
+                    Ok(snippet) => err.help(&format!(
+                        "try adding a `where` bound using this expression: `where [(); {}]:`",
+                        snippet
+                    )),
+                    _ => err.help("consider adding a `where` bound using this expression"),
+                };
+                Some(err)
+            }
+            _ => {
+                span_bug!(
+                    span,
+                    "unexpected non-ConstEvaluatable predicate, this should not be reachable"
+                )
+            }
+        }
+    }
 }
 
+struct UnsatisfiedConst(pub bool);
+
+fn get_explanation_based_on_obligation<'tcx>(
+    obligation: &PredicateObligation<'tcx>,
+    trait_ref: ty::PolyTraitRef<'tcx>,
+    trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+    pre_message: String,
+) -> String {
+    if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
+        "consider using `()`, or a `Result`".to_owned()
+    } else {
+        let ty_desc = match trait_ref.skip_binder().self_ty().kind() {
+            ty::FnDef(_, _) => Some("fn item"),
+            ty::Closure(_, _) => Some("closure"),
+            _ => None,
+        };
+
+        match ty_desc {
+            Some(desc) => format!(
+                "{}the trait `{}` is not implemented for {} `{}`",
+                pre_message,
+                trait_predicate.print_modifiers_and_trait_path(),
+                desc,
+                trait_ref.skip_binder().self_ty(),
+            ),
+            None => format!(
+                "{}the trait `{}` is not implemented for `{}`",
+                pre_message,
+                trait_predicate.print_modifiers_and_trait_path(),
+                trait_ref.skip_binder().self_ty(),
+            ),
+        }
+    }
+}
 /// Crude way of getting back an `Expr` from a `Span`.
 pub struct FindExprBySpan<'hir> {
     pub span: Span,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index a9c4e126816..88525e1b720 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -327,7 +327,7 @@ pub struct OnUnimplementedDirective {
     pub label: Option<OnUnimplementedFormatString>,
     pub note: Option<OnUnimplementedFormatString>,
     pub parent_label: Option<OnUnimplementedFormatString>,
-    pub append_const_msg: Option<Option<Symbol>>,
+    pub append_const_msg: Option<AppendConstMessage>,
 }
 
 /// For the `#[rustc_on_unimplemented]` attribute
@@ -337,11 +337,21 @@ pub struct OnUnimplementedNote {
     pub label: Option<String>,
     pub note: Option<String>,
     pub parent_label: Option<String>,
-    /// Append a message for `~const Trait` errors. `None` means not requested and
-    /// should fallback to a generic message, `Some(None)` suggests using the default
-    /// appended message, `Some(Some(s))` suggests use the `s` message instead of the
-    /// default one..
-    pub append_const_msg: Option<Option<Symbol>>,
+    // If none, should fall back to a generic message
+    pub append_const_msg: Option<AppendConstMessage>,
+}
+
+/// Append a message for `~const Trait` errors.
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum AppendConstMessage {
+    Default,
+    Custom(Symbol),
+}
+
+impl Default for AppendConstMessage {
+    fn default() -> Self {
+        AppendConstMessage::Default
+    }
 }
 
 impl<'tcx> OnUnimplementedDirective {
@@ -419,10 +429,10 @@ impl<'tcx> OnUnimplementedDirective {
                 }
             } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() {
                 if let Some(msg) = item.value_str() {
-                    append_const_msg = Some(Some(msg));
+                    append_const_msg = Some(AppendConstMessage::Custom(msg));
                     continue;
                 } else if item.is_word() {
-                    append_const_msg = Some(None);
+                    append_const_msg = Some(AppendConstMessage::Default);
                     continue;
                 }
             }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 73207f183a1..c969e5d4975 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -386,7 +386,7 @@ pub trait TypeErrCtxtExt<'tcx> {
     fn maybe_suggest_convert_to_slice(
         &self,
         err: &mut Diagnostic,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
         candidate_impls: &[ImplCandidate<'tcx>],
         span: Span,
     );
@@ -3848,7 +3848,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
     fn maybe_suggest_convert_to_slice(
         &self,
         err: &mut Diagnostic,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
         candidate_impls: &[ImplCandidate<'tcx>],
         span: Span,
     ) {
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index b8ad1925e4e..73e2efc3b00 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -297,8 +297,8 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
     tcx.associated_items(trait_def_id)
         .in_definition_order()
         .filter(|item| item.kind == ty::AssocKind::Type)
-        .flat_map(|item| tcx.explicit_item_bounds(item.def_id))
-        .filter_map(|pred_span| predicate_references_self(tcx, *pred_span))
+        .flat_map(|item| tcx.explicit_item_bounds(item.def_id).subst_identity_iter_copied())
+        .filter_map(|pred_span| predicate_references_self(tcx, pred_span))
         .collect()
 }
 
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 9683e48478e..c319b2e31c7 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -50,12 +50,11 @@ impl<'tcx> RustIrDatabase<'tcx> {
     where
         ty::Predicate<'tcx>: LowerInto<'tcx, std::option::Option<T>>,
     {
-        let bounds = self.interner.tcx.bound_explicit_item_bounds(def_id);
-        bounds
-            .0
-            .iter()
-            .map(|(bound, _)| bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars))
-            .filter_map(|bound| LowerInto::<Option<_>>::lower_into(bound, self.interner))
+        self.interner
+            .tcx
+            .explicit_item_bounds(def_id)
+            .subst_iter_copied(self.interner.tcx, &bound_vars)
+            .filter_map(|(bound, _)| LowerInto::<Option<_>>::lower_into(bound, self.interner))
             .collect()
     }
 }
@@ -506,15 +505,11 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
 
         let identity_substs = InternalSubsts::identity_for_item(self.interner.tcx, opaque_ty_id.0);
 
-        let explicit_item_bounds = self.interner.tcx.bound_explicit_item_bounds(opaque_ty_id.0);
+        let explicit_item_bounds = self.interner.tcx.explicit_item_bounds(opaque_ty_id.0);
         let bounds =
             explicit_item_bounds
-                .0
-                .iter()
+                .subst_iter_copied(self.interner.tcx, &bound_vars)
                 .map(|(bound, _)| {
-                    explicit_item_bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars)
-                })
-                .map(|bound| {
                     bound.fold_with(&mut ReplaceOpaqueTyFolder {
                         tcx: self.interner.tcx,
                         opaque_ty_id,
diff --git a/compiler/rustc_type_ir/src/codec.rs b/compiler/rustc_type_ir/src/codec.rs
index ee249050cc6..3b638934629 100644
--- a/compiler/rustc_type_ir/src/codec.rs
+++ b/compiler/rustc_type_ir/src/codec.rs
@@ -27,10 +27,13 @@ pub trait TyEncoder: Encoder {
     const CLEAR_CROSS_CRATE: bool;
 
     fn position(&self) -> usize;
+
     fn type_shorthands(&mut self) -> &mut FxHashMap<<Self::I as Interner>::Ty, usize>;
+
     fn predicate_shorthands(
         &mut self,
     ) -> &mut FxHashMap<<Self::I as Interner>::PredicateKind, usize>;
+
     fn encode_alloc_id(&mut self, alloc_id: &<Self::I as Interner>::AllocId);
 }
 
@@ -40,10 +43,6 @@ pub trait TyDecoder: Decoder {
 
     fn interner(&self) -> Self::I;
 
-    fn peek_byte(&self) -> u8;
-
-    fn position(&self) -> usize;
-
     fn cached_ty_for_shorthand<F>(
         &mut self,
         shorthand: usize,
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index a3c98ae007e..95237dda8c2 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -537,7 +537,7 @@ pub struct FloatVarValue(pub FloatTy);
 
 rustc_index::newtype_index! {
     /// A **ty**pe **v**ariable **ID**.
-    #[debug_format = "_#{}t"]
+    #[debug_format = "?{}t"]
     pub struct TyVid {}
 }
 
@@ -739,13 +739,13 @@ impl fmt::Debug for FloatVarValue {
 
 impl fmt::Debug for IntVid {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "_#{}i", self.index)
+        write!(f, "?{}i", self.index)
     }
 }
 
 impl fmt::Debug for FloatVid {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "_#{}f", self.index)
+        write!(f, "?{}f", self.index)
     }
 }
 
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index 8975ba3f06b..95c07abf731 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -35,6 +35,3 @@ compiler-builtins-mem = ['compiler_builtins/mem']
 compiler-builtins-c = ["compiler_builtins/c"]
 compiler-builtins-no-asm = ["compiler_builtins/no-asm"]
 compiler-builtins-mangled-names = ["compiler_builtins/mangled-names"]
-
-# Make panics and failed asserts immediately abort without formatting any message
-panic_immediate_abort = ["core/panic_immediate_abort"]
diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs
index 0db23e55a86..6f2ba957bcd 100644
--- a/library/alloc/src/alloc.rs
+++ b/library/alloc/src/alloc.rs
@@ -14,11 +14,6 @@ use core::ptr::{self, NonNull};
 #[doc(inline)]
 pub use core::alloc::*;
 
-#[cfg(not(no_global_oom_handling))]
-use core::any::Any;
-#[cfg(not(no_global_oom_handling))]
-use core::panic::BoxMeUp;
-
 #[cfg(test)]
 mod tests;
 
@@ -348,77 +343,14 @@ pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A)
     }
 }
 
-/// Payload passed to the panic handler when `handle_alloc_error` is called.
-#[unstable(feature = "panic_oom_payload", issue = "none")]
-#[derive(Debug)]
-pub struct AllocErrorPanicPayload {
-    layout: Layout,
-}
-
-impl AllocErrorPanicPayload {
-    /// Internal function for the standard library to clone a payload.
-    #[unstable(feature = "std_internals", issue = "none")]
-    #[doc(hidden)]
-    pub fn internal_clone(&self) -> Self {
-        AllocErrorPanicPayload { layout: self.layout }
-    }
-
-    /// Returns the [`Layout`] of the allocation attempt that caused the error.
-    #[unstable(feature = "panic_oom_payload", issue = "none")]
-    pub fn layout(&self) -> Layout {
-        self.layout
-    }
-}
-
-#[unstable(feature = "std_internals", issue = "none")]
-#[cfg(not(no_global_oom_handling))]
-unsafe impl BoxMeUp for AllocErrorPanicPayload {
-    fn take_box(&mut self) -> *mut (dyn Any + Send) {
-        use crate::boxed::Box;
-        Box::into_raw(Box::new(self.internal_clone()))
-    }
-
-    fn get(&mut self) -> &(dyn Any + Send) {
-        self
-    }
-}
-
 // # Allocation error handler
 
-#[cfg(all(not(no_global_oom_handling), not(test)))]
-fn rust_oom(layout: Layout) -> ! {
-    if cfg!(feature = "panic_immediate_abort") {
-        core::intrinsics::abort()
-    }
-
-    extern "Rust" {
-        // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
-        // that gets resolved to the `#[panic_handler]` function.
-        #[lang = "panic_impl"]
-        fn panic_impl(pi: &core::panic::PanicInfo<'_>) -> !;
-
-        // This symbol is emitted by rustc .
-        // Its value depends on the -Zoom={unwind,abort} compiler option.
-        static __rust_alloc_error_handler_should_panic: u8;
-    }
-
-    // Hack to work around issues with the lifetime of Arguments.
-    match format_args!("memory allocation of {} bytes failed", layout.size()) {
-        fmt => {
-            // Create a PanicInfo with a custom payload for the panic handler.
-            let can_unwind = unsafe { __rust_alloc_error_handler_should_panic != 0 };
-            let mut pi = core::panic::PanicInfo::internal_constructor(
-                Some(&fmt),
-                core::panic::Location::caller(),
-                can_unwind,
-            );
-            let payload = AllocErrorPanicPayload { layout };
-            pi.set_payload(&payload);
-
-            // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
-            unsafe { panic_impl(&pi) }
-        }
-    }
+#[cfg(not(no_global_oom_handling))]
+extern "Rust" {
+    // This is the magic symbol to call the global alloc error handler. rustc generates
+    // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
+    // default implementations below (`__rdl_oom`) otherwise.
+    fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
 }
 
 /// Abort on memory allocation error or failure.
@@ -426,6 +358,13 @@ fn rust_oom(layout: Layout) -> ! {
 /// Callers of memory allocation APIs wishing to abort computation
 /// in response to an allocation error are encouraged to call this function,
 /// rather than directly invoking `panic!` or similar.
+///
+/// The default behavior of this function is to print a message to standard error
+/// and abort the process.
+/// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`].
+///
+/// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
+/// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
 #[stable(feature = "global_alloc", since = "1.28.0")]
 #[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")]
 #[cfg(all(not(no_global_oom_handling), not(test)))]
@@ -436,7 +375,9 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
     }
 
     fn rt_error(layout: Layout) -> ! {
-        rust_oom(layout);
+        unsafe {
+            __rust_alloc_error_handler(layout.size(), layout.align());
+        }
     }
 
     unsafe { core::intrinsics::const_eval_select((layout,), ct_error, rt_error) }
@@ -446,7 +387,6 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
 #[cfg(all(not(no_global_oom_handling), test))]
 pub use std::alloc::handle_alloc_error;
 
-#[cfg(bootstrap)]
 #[cfg(all(not(no_global_oom_handling), not(test)))]
 #[doc(hidden)]
 #[allow(unused_attributes)]
@@ -458,7 +398,7 @@ pub mod __alloc_error_handler {
     pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
         extern "Rust" {
             // This symbol is emitted by rustc next to __rust_alloc_error_handler.
-            // Its value depends on the -Zoom={unwind,abort} compiler option.
+            // Its value depends on the -Zoom={panic,abort} compiler option.
             static __rust_alloc_error_handler_should_panic: u8;
         }
 
diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs
index 1743a155c5a..0cb7e82beb0 100644
--- a/library/alloc/src/collections/linked_list.rs
+++ b/library/alloc/src/collections/linked_list.rs
@@ -18,9 +18,10 @@ use core::hash::{Hash, Hasher};
 use core::iter::FusedIterator;
 use core::marker::PhantomData;
 use core::mem;
-use core::ptr::NonNull;
+use core::ptr::{NonNull, Unique};
 
 use super::SpecExtend;
+use crate::alloc::{Allocator, Global};
 use crate::boxed::Box;
 
 #[cfg(test)]
@@ -47,11 +48,15 @@ mod tests;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "LinkedList")]
 #[rustc_insignificant_dtor]
-pub struct LinkedList<T> {
+pub struct LinkedList<
+    T,
+    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+> {
     head: Option<NonNull<Node<T>>>,
     tail: Option<NonNull<Node<T>>>,
     len: usize,
-    marker: PhantomData<Box<Node<T>>>,
+    alloc: A,
+    marker: PhantomData<Box<Node<T>, A>>,
 }
 
 struct Node<T> {
@@ -81,6 +86,7 @@ impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
                 head: self.head,
                 tail: self.tail,
                 len: self.len,
+                alloc: Global,
                 marker: PhantomData,
             }))
             .field(&self.len)
@@ -117,6 +123,7 @@ impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> {
                 head: self.head,
                 tail: self.tail,
                 len: self.len,
+                alloc: Global,
                 marker: PhantomData,
             }))
             .field(&self.len)
@@ -132,12 +139,15 @@ impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> {
 /// [`into_iter`]: LinkedList::into_iter
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct IntoIter<T> {
-    list: LinkedList<T>,
+pub struct IntoIter<
+    T,
+    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+> {
+    list: LinkedList<T, A>,
 }
 
 #[stable(feature = "collection_debug", since = "1.17.0")]
-impl<T: fmt::Debug> fmt::Debug for IntoIter<T> {
+impl<T: fmt::Debug, A: Allocator> fmt::Debug for IntoIter<T, A> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_tuple("IntoIter").field(&self.list).finish()
     }
@@ -148,22 +158,25 @@ impl<T> Node<T> {
         Node { next: None, prev: None, element }
     }
 
-    fn into_element(self: Box<Self>) -> T {
+    fn into_element<A: Allocator>(self: Box<Self, A>) -> T {
         self.element
     }
 }
 
 // private methods
-impl<T> LinkedList<T> {
+impl<T, A: Allocator> LinkedList<T, A> {
     /// Adds the given node to the front of the list.
+    ///
+    /// # Safety
+    /// `node` must point to a valid node that was boxed using the list's allocator.
     #[inline]
-    fn push_front_node(&mut self, mut node: Box<Node<T>>) {
+    unsafe fn push_front_node(&mut self, node: Unique<Node<T>>) {
         // This method takes care not to create mutable references to whole nodes,
         // to maintain validity of aliasing pointers into `element`.
         unsafe {
-            node.next = self.head;
-            node.prev = None;
-            let node = Some(Box::leak(node).into());
+            (*node.as_ptr()).next = self.head;
+            (*node.as_ptr()).prev = None;
+            let node = Some(NonNull::from(node));
 
             match self.head {
                 None => self.tail = node,
@@ -178,11 +191,11 @@ impl<T> LinkedList<T> {
 
     /// Removes and returns the node at the front of the list.
     #[inline]
-    fn pop_front_node(&mut self) -> Option<Box<Node<T>>> {
+    fn pop_front_node(&mut self) -> Option<Box<Node<T>, &A>> {
         // This method takes care not to create mutable references to whole nodes,
         // to maintain validity of aliasing pointers into `element`.
         self.head.map(|node| unsafe {
-            let node = Box::from_raw(node.as_ptr());
+            let node = Box::from_raw_in(node.as_ptr(), &self.alloc);
             self.head = node.next;
 
             match self.head {
@@ -197,14 +210,17 @@ impl<T> LinkedList<T> {
     }
 
     /// Adds the given node to the back of the list.
+    ///
+    /// # Safety
+    /// `node` must point to a valid node that was boxed using the list's allocator.
     #[inline]
-    fn push_back_node(&mut self, mut node: Box<Node<T>>) {
+    unsafe fn push_back_node(&mut self, node: Unique<Node<T>>) {
         // This method takes care not to create mutable references to whole nodes,
         // to maintain validity of aliasing pointers into `element`.
         unsafe {
-            node.next = None;
-            node.prev = self.tail;
-            let node = Some(Box::leak(node).into());
+            (*node.as_ptr()).next = None;
+            (*node.as_ptr()).prev = self.tail;
+            let node = Some(NonNull::from(node));
 
             match self.tail {
                 None => self.head = node,
@@ -219,11 +235,11 @@ impl<T> LinkedList<T> {
 
     /// Removes and returns the node at the back of the list.
     #[inline]
-    fn pop_back_node(&mut self) -> Option<Box<Node<T>>> {
+    fn pop_back_node(&mut self) -> Option<Box<Node<T>, &A>> {
         // This method takes care not to create mutable references to whole nodes,
         // to maintain validity of aliasing pointers into `element`.
         self.tail.map(|node| unsafe {
-            let node = Box::from_raw(node.as_ptr());
+            let node = Box::from_raw_in(node.as_ptr(), &self.alloc);
             self.tail = node.prev;
 
             match self.tail {
@@ -321,7 +337,10 @@ impl<T> LinkedList<T> {
         &mut self,
         split_node: Option<NonNull<Node<T>>>,
         at: usize,
-    ) -> Self {
+    ) -> Self
+    where
+        A: Clone,
+    {
         // The split node is the new head node of the second part
         if let Some(mut split_node) = split_node {
             let first_part_head;
@@ -342,6 +361,7 @@ impl<T> LinkedList<T> {
                 head: first_part_head,
                 tail: first_part_tail,
                 len: at,
+                alloc: self.alloc.clone(),
                 marker: PhantomData,
             };
 
@@ -351,7 +371,7 @@ impl<T> LinkedList<T> {
 
             first_part
         } else {
-            mem::replace(self, LinkedList::new())
+            mem::replace(self, LinkedList::new_in(self.alloc.clone()))
         }
     }
 
@@ -360,7 +380,10 @@ impl<T> LinkedList<T> {
         &mut self,
         split_node: Option<NonNull<Node<T>>>,
         at: usize,
-    ) -> Self {
+    ) -> Self
+    where
+        A: Clone,
+    {
         // The split node is the new tail node of the first part and owns
         // the head of the second part.
         if let Some(mut split_node) = split_node {
@@ -382,6 +405,7 @@ impl<T> LinkedList<T> {
                 head: second_part_head,
                 tail: second_part_tail,
                 len: self.len - at,
+                alloc: self.alloc.clone(),
                 marker: PhantomData,
             };
 
@@ -391,7 +415,7 @@ impl<T> LinkedList<T> {
 
             second_part
         } else {
-            mem::replace(self, LinkedList::new())
+            mem::replace(self, LinkedList::new_in(self.alloc.clone()))
         }
     }
 }
@@ -420,7 +444,7 @@ impl<T> LinkedList<T> {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
     pub const fn new() -> Self {
-        LinkedList { head: None, tail: None, len: 0, marker: PhantomData }
+        LinkedList { head: None, tail: None, len: 0, alloc: Global, marker: PhantomData }
     }
 
     /// Moves all elements from `other` to the end of the list.
@@ -471,7 +495,26 @@ impl<T> LinkedList<T> {
             }
         }
     }
+}
 
+impl<T, A: Allocator> LinkedList<T, A> {
+    /// Constructs an empty `LinkedList<T, A>`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(allocator_api)]
+    ///
+    /// use std::alloc::System;
+    /// use std::collections::LinkedList;
+    ///
+    /// let list: LinkedList<u32, _> = LinkedList::new_in(System);
+    /// ```
+    #[inline]
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    pub const fn new_in(alloc: A) -> Self {
+        LinkedList { head: None, tail: None, len: 0, alloc, marker: PhantomData }
+    }
     /// Provides a forward iterator.
     ///
     /// # Examples
@@ -532,7 +575,7 @@ impl<T> LinkedList<T> {
     #[inline]
     #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
-    pub fn cursor_front(&self) -> Cursor<'_, T> {
+    pub fn cursor_front(&self) -> Cursor<'_, T, A> {
         Cursor { index: 0, current: self.head, list: self }
     }
 
@@ -542,7 +585,7 @@ impl<T> LinkedList<T> {
     #[inline]
     #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
-    pub fn cursor_front_mut(&mut self) -> CursorMut<'_, T> {
+    pub fn cursor_front_mut(&mut self) -> CursorMut<'_, T, A> {
         CursorMut { index: 0, current: self.head, list: self }
     }
 
@@ -552,7 +595,7 @@ impl<T> LinkedList<T> {
     #[inline]
     #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
-    pub fn cursor_back(&self) -> Cursor<'_, T> {
+    pub fn cursor_back(&self) -> Cursor<'_, T, A> {
         Cursor { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self }
     }
 
@@ -562,7 +605,7 @@ impl<T> LinkedList<T> {
     #[inline]
     #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
-    pub fn cursor_back_mut(&mut self) -> CursorMut<'_, T> {
+    pub fn cursor_back_mut(&mut self) -> CursorMut<'_, T, A> {
         CursorMut { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self }
     }
 
@@ -638,7 +681,15 @@ impl<T> LinkedList<T> {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn clear(&mut self) {
-        *self = Self::new();
+        // We need to drop the nodes while keeping self.alloc
+        // We can do this by moving (head, tail, len) into a new list that borrows self.alloc
+        drop(LinkedList {
+            head: self.head.take(),
+            tail: self.tail.take(),
+            len: mem::take(&mut self.len),
+            alloc: &self.alloc,
+            marker: PhantomData,
+        });
     }
 
     /// Returns `true` if the `LinkedList` contains an element equal to the
@@ -790,7 +841,12 @@ impl<T> LinkedList<T> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn push_front(&mut self, elt: T) {
-        self.push_front_node(Box::new(Node::new(elt)));
+        let node = Box::new_in(Node::new(elt), &self.alloc);
+        let node_ptr = Unique::from(Box::leak(node));
+        // SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc
+        unsafe {
+            self.push_front_node(node_ptr);
+        }
     }
 
     /// Removes the first element and returns it, or `None` if the list is
@@ -833,7 +889,12 @@ impl<T> LinkedList<T> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn push_back(&mut self, elt: T) {
-        self.push_back_node(Box::new(Node::new(elt)));
+        let node = Box::new_in(Node::new(elt), &self.alloc);
+        let node_ptr = Unique::from(Box::leak(node));
+        // SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc
+        unsafe {
+            self.push_back_node(node_ptr);
+        }
     }
 
     /// Removes the last element from a list and returns it, or `None` if
@@ -883,13 +944,16 @@ impl<T> LinkedList<T> {
     /// assert_eq!(split.pop_front(), None);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn split_off(&mut self, at: usize) -> LinkedList<T> {
+    pub fn split_off(&mut self, at: usize) -> LinkedList<T, A>
+    where
+        A: Clone,
+    {
         let len = self.len();
         assert!(at <= len, "Cannot split off at a nonexistent index");
         if at == 0 {
-            return mem::take(self);
+            return mem::replace(self, Self::new_in(self.alloc.clone()));
         } else if at == len {
-            return Self::new();
+            return Self::new_in(self.alloc.clone());
         }
 
         // Below, we iterate towards the `i-1`th node, either from the start or the end,
@@ -987,7 +1051,7 @@ impl<T> LinkedList<T> {
     /// assert_eq!(odds.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 9, 11, 13, 15]);
     /// ```
     #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
-    pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F>
+    pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>
     where
         F: FnMut(&mut T) -> bool,
     {
@@ -1000,11 +1064,11 @@ impl<T> LinkedList<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<#[may_dangle] T> Drop for LinkedList<T> {
+unsafe impl<#[may_dangle] T, A: Allocator> Drop for LinkedList<T, A> {
     fn drop(&mut self) {
-        struct DropGuard<'a, T>(&'a mut LinkedList<T>);
+        struct DropGuard<'a, T, A: Allocator>(&'a mut LinkedList<T, A>);
 
-        impl<'a, T> Drop for DropGuard<'a, T> {
+        impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> {
             fn drop(&mut self) {
                 // Continue the same loop we do below. This only runs when a destructor has
                 // panicked. If another one panics this will abort.
@@ -1012,11 +1076,10 @@ unsafe impl<#[may_dangle] T> Drop for LinkedList<T> {
             }
         }
 
-        while let Some(node) = self.pop_front_node() {
-            let guard = DropGuard(self);
-            drop(node);
-            mem::forget(guard);
-        }
+        // Wrap self so that if a destructor panics, we can try to keep looping
+        let guard = DropGuard(self);
+        while guard.0.pop_front_node().is_some() {}
+        mem::forget(guard);
     }
 }
 
@@ -1159,14 +1222,18 @@ impl<T> Default for IterMut<'_, T> {
 ///
 /// When created, cursors start at the front of the list, or the "ghost" non-element if the list is empty.
 #[unstable(feature = "linked_list_cursors", issue = "58533")]
-pub struct Cursor<'a, T: 'a> {
+pub struct Cursor<
+    'a,
+    T: 'a,
+    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+> {
     index: usize,
     current: Option<NonNull<Node<T>>>,
-    list: &'a LinkedList<T>,
+    list: &'a LinkedList<T, A>,
 }
 
 #[unstable(feature = "linked_list_cursors", issue = "58533")]
-impl<T> Clone for Cursor<'_, T> {
+impl<T, A: Allocator> Clone for Cursor<'_, T, A> {
     fn clone(&self) -> Self {
         let Cursor { index, current, list } = *self;
         Cursor { index, current, list }
@@ -1174,7 +1241,7 @@ impl<T> Clone for Cursor<'_, T> {
 }
 
 #[unstable(feature = "linked_list_cursors", issue = "58533")]
-impl<T: fmt::Debug> fmt::Debug for Cursor<'_, T> {
+impl<T: fmt::Debug, A: Allocator> fmt::Debug for Cursor<'_, T, A> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_tuple("Cursor").field(&self.list).field(&self.index()).finish()
     }
@@ -1191,20 +1258,24 @@ impl<T: fmt::Debug> fmt::Debug for Cursor<'_, T> {
 /// To accommodate this, there is a "ghost" non-element that yields `None` between the head and
 /// tail of the list.
 #[unstable(feature = "linked_list_cursors", issue = "58533")]
-pub struct CursorMut<'a, T: 'a> {
+pub struct CursorMut<
+    'a,
+    T: 'a,
+    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+> {
     index: usize,
     current: Option<NonNull<Node<T>>>,
-    list: &'a mut LinkedList<T>,
+    list: &'a mut LinkedList<T, A>,
 }
 
 #[unstable(feature = "linked_list_cursors", issue = "58533")]
-impl<T: fmt::Debug> fmt::Debug for CursorMut<'_, T> {
+impl<T: fmt::Debug, A: Allocator> fmt::Debug for CursorMut<'_, T, A> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_tuple("CursorMut").field(&self.list).field(&self.index()).finish()
     }
 }
 
-impl<'a, T> Cursor<'a, T> {
+impl<'a, T, A: Allocator> Cursor<'a, T, A> {
     /// Returns the cursor position index within the `LinkedList`.
     ///
     /// This returns `None` if the cursor is currently pointing to the
@@ -1321,7 +1392,7 @@ impl<'a, T> Cursor<'a, T> {
     }
 }
 
-impl<'a, T> CursorMut<'a, T> {
+impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
     /// Returns the cursor position index within the `LinkedList`.
     ///
     /// This returns `None` if the cursor is currently pointing to the
@@ -1426,7 +1497,7 @@ impl<'a, T> CursorMut<'a, T> {
     /// `CursorMut` is frozen for the lifetime of the `Cursor`.
     #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
-    pub fn as_cursor(&self) -> Cursor<'_, T> {
+    pub fn as_cursor(&self) -> Cursor<'_, T, A> {
         Cursor { list: self.list, current: self.current, index: self.index }
     }
 }
@@ -1434,6 +1505,51 @@ impl<'a, T> CursorMut<'a, T> {
 // Now the list editing operations
 
 impl<'a, T> CursorMut<'a, T> {
+    /// Inserts the elements from the given `LinkedList` after the current one.
+    ///
+    /// If the cursor is pointing at the "ghost" non-element then the new elements are
+    /// inserted at the start of the `LinkedList`.
+    #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    pub fn splice_after(&mut self, list: LinkedList<T>) {
+        unsafe {
+            let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() {
+                Some(parts) => parts,
+                _ => return,
+            };
+            let node_next = match self.current {
+                None => self.list.head,
+                Some(node) => node.as_ref().next,
+            };
+            self.list.splice_nodes(self.current, node_next, splice_head, splice_tail, splice_len);
+            if self.current.is_none() {
+                // The "ghost" non-element's index has changed.
+                self.index = self.list.len;
+            }
+        }
+    }
+
+    /// Inserts the elements from the given `LinkedList` before the current one.
+    ///
+    /// If the cursor is pointing at the "ghost" non-element then the new elements are
+    /// inserted at the end of the `LinkedList`.
+    #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    pub fn splice_before(&mut self, list: LinkedList<T>) {
+        unsafe {
+            let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() {
+                Some(parts) => parts,
+                _ => return,
+            };
+            let node_prev = match self.current {
+                None => self.list.tail,
+                Some(node) => node.as_ref().prev,
+            };
+            self.list.splice_nodes(node_prev, self.current, splice_head, splice_tail, splice_len);
+            self.index += splice_len;
+        }
+    }
+}
+
+impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
     /// Inserts a new element into the `LinkedList` after the current one.
     ///
     /// If the cursor is pointing at the "ghost" non-element then the new element is
@@ -1441,7 +1557,7 @@ impl<'a, T> CursorMut<'a, T> {
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn insert_after(&mut self, item: T) {
         unsafe {
-            let spliced_node = Box::leak(Box::new(Node::new(item))).into();
+            let spliced_node = Box::leak(Box::new_in(Node::new(item), &self.list.alloc)).into();
             let node_next = match self.current {
                 None => self.list.head,
                 Some(node) => node.as_ref().next,
@@ -1461,7 +1577,7 @@ impl<'a, T> CursorMut<'a, T> {
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn insert_before(&mut self, item: T) {
         unsafe {
-            let spliced_node = Box::leak(Box::new(Node::new(item))).into();
+            let spliced_node = Box::leak(Box::new_in(Node::new(item), &self.list.alloc)).into();
             let node_prev = match self.current {
                 None => self.list.tail,
                 Some(node) => node.as_ref().prev,
@@ -1497,7 +1613,10 @@ impl<'a, T> CursorMut<'a, T> {
     /// If the cursor is currently pointing to the "ghost" non-element then no element
     /// is removed and `None` is returned.
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
-    pub fn remove_current_as_list(&mut self) -> Option<LinkedList<T>> {
+    pub fn remove_current_as_list(&mut self) -> Option<LinkedList<T, A>>
+    where
+        A: Clone,
+    {
         let mut unlinked_node = self.current?;
         unsafe {
             self.current = unlinked_node.as_ref().next;
@@ -1509,54 +1628,12 @@ impl<'a, T> CursorMut<'a, T> {
                 head: Some(unlinked_node),
                 tail: Some(unlinked_node),
                 len: 1,
+                alloc: self.list.alloc.clone(),
                 marker: PhantomData,
             })
         }
     }
 
-    /// Inserts the elements from the given `LinkedList` after the current one.
-    ///
-    /// If the cursor is pointing at the "ghost" non-element then the new elements are
-    /// inserted at the start of the `LinkedList`.
-    #[unstable(feature = "linked_list_cursors", issue = "58533")]
-    pub fn splice_after(&mut self, list: LinkedList<T>) {
-        unsafe {
-            let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() {
-                Some(parts) => parts,
-                _ => return,
-            };
-            let node_next = match self.current {
-                None => self.list.head,
-                Some(node) => node.as_ref().next,
-            };
-            self.list.splice_nodes(self.current, node_next, splice_head, splice_tail, splice_len);
-            if self.current.is_none() {
-                // The "ghost" non-element's index has changed.
-                self.index = self.list.len;
-            }
-        }
-    }
-
-    /// Inserts the elements from the given `LinkedList` before the current one.
-    ///
-    /// If the cursor is pointing at the "ghost" non-element then the new elements are
-    /// inserted at the end of the `LinkedList`.
-    #[unstable(feature = "linked_list_cursors", issue = "58533")]
-    pub fn splice_before(&mut self, list: LinkedList<T>) {
-        unsafe {
-            let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() {
-                Some(parts) => parts,
-                _ => return,
-            };
-            let node_prev = match self.current {
-                None => self.list.tail,
-                Some(node) => node.as_ref().prev,
-            };
-            self.list.splice_nodes(node_prev, self.current, splice_head, splice_tail, splice_len);
-            self.index += splice_len;
-        }
-    }
-
     /// Splits the list into two after the current element. This will return a
     /// new list consisting of everything after the cursor, with the original
     /// list retaining everything before.
@@ -1564,7 +1641,10 @@ impl<'a, T> CursorMut<'a, T> {
     /// If the cursor is pointing at the "ghost" non-element then the entire contents
     /// of the `LinkedList` are moved.
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
-    pub fn split_after(&mut self) -> LinkedList<T> {
+    pub fn split_after(&mut self) -> LinkedList<T, A>
+    where
+        A: Clone,
+    {
         let split_off_idx = if self.index == self.list.len { 0 } else { self.index + 1 };
         if self.index == self.list.len {
             // The "ghost" non-element's index has changed to 0.
@@ -1580,7 +1660,10 @@ impl<'a, T> CursorMut<'a, T> {
     /// If the cursor is pointing at the "ghost" non-element then the entire contents
     /// of the `LinkedList` are moved.
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
-    pub fn split_before(&mut self) -> LinkedList<T> {
+    pub fn split_before(&mut self) -> LinkedList<T, A>
+    where
+        A: Clone,
+    {
         let split_off_idx = self.index;
         self.index = 0;
         unsafe { self.list.split_off_before_node(self.current, split_off_idx) }
@@ -1722,11 +1805,15 @@ impl<'a, T> CursorMut<'a, T> {
 
 /// An iterator produced by calling `drain_filter` on LinkedList.
 #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
-pub struct DrainFilter<'a, T: 'a, F: 'a>
-where
+pub struct DrainFilter<
+    'a,
+    T: 'a,
+    F: 'a,
+    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+> where
     F: FnMut(&mut T) -> bool,
 {
-    list: &'a mut LinkedList<T>,
+    list: &'a mut LinkedList<T, A>,
     it: Option<NonNull<Node<T>>>,
     pred: F,
     idx: usize,
@@ -1734,7 +1821,7 @@ where
 }
 
 #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
-impl<T, F> Iterator for DrainFilter<'_, T, F>
+impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A>
 where
     F: FnMut(&mut T) -> bool,
 {
@@ -1763,16 +1850,16 @@ where
 }
 
 #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
-impl<T, F> Drop for DrainFilter<'_, T, F>
+impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A>
 where
     F: FnMut(&mut T) -> bool,
 {
     fn drop(&mut self) {
-        struct DropGuard<'r, 'a, T, F>(&'r mut DrainFilter<'a, T, F>)
+        struct DropGuard<'r, 'a, T, F, A: Allocator>(&'r mut DrainFilter<'a, T, F, A>)
         where
             F: FnMut(&mut T) -> bool;
 
-        impl<'r, 'a, T, F> Drop for DropGuard<'r, 'a, T, F>
+        impl<'r, 'a, T, F, A: Allocator> Drop for DropGuard<'r, 'a, T, F, A>
         where
             F: FnMut(&mut T) -> bool,
         {
@@ -1800,7 +1887,7 @@ where
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Iterator for IntoIter<T> {
+impl<T, A: Allocator> Iterator for IntoIter<T, A> {
     type Item = T;
 
     #[inline]
@@ -1815,7 +1902,7 @@ impl<T> Iterator for IntoIter<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T> DoubleEndedIterator for IntoIter<T> {
+impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
     #[inline]
     fn next_back(&mut self) -> Option<T> {
         self.list.pop_back()
@@ -1823,10 +1910,10 @@ impl<T> DoubleEndedIterator for IntoIter<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ExactSizeIterator for IntoIter<T> {}
+impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {}
 
 #[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for IntoIter<T> {}
+impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {}
 
 #[stable(feature = "default_iters", since = "CURRENT_RUSTC_VERSION")]
 impl<T> Default for IntoIter<T> {
@@ -1852,19 +1939,19 @@ impl<T> FromIterator<T> for LinkedList<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T> IntoIterator for LinkedList<T> {
+impl<T, A: Allocator> IntoIterator for LinkedList<T, A> {
     type Item = T;
-    type IntoIter = IntoIter<T>;
+    type IntoIter = IntoIter<T, A>;
 
     /// Consumes the list into an iterator yielding elements by value.
     #[inline]
-    fn into_iter(self) -> IntoIter<T> {
+    fn into_iter(self) -> IntoIter<T, A> {
         IntoIter { list: self }
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> IntoIterator for &'a LinkedList<T> {
+impl<'a, T, A: Allocator> IntoIterator for &'a LinkedList<T, A> {
     type Item = &'a T;
     type IntoIter = Iter<'a, T>;
 
@@ -1874,7 +1961,7 @@ impl<'a, T> IntoIterator for &'a LinkedList<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> IntoIterator for &'a mut LinkedList<T> {
+impl<'a, T, A: Allocator> IntoIterator for &'a mut LinkedList<T, A> {
     type Item = &'a mut T;
     type IntoIter = IterMut<'a, T>;
 
@@ -1884,7 +1971,7 @@ impl<'a, T> IntoIterator for &'a mut LinkedList<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Extend<T> for LinkedList<T> {
+impl<T, A: Allocator> Extend<T> for LinkedList<T, A> {
     fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
         <Self as SpecExtend<I>>::spec_extend(self, iter);
     }
@@ -1895,7 +1982,7 @@ impl<T> Extend<T> for LinkedList<T> {
     }
 }
 
-impl<I: IntoIterator> SpecExtend<I> for LinkedList<I::Item> {
+impl<I: IntoIterator, A: Allocator> SpecExtend<I> for LinkedList<I::Item, A> {
     default fn spec_extend(&mut self, iter: I) {
         iter.into_iter().for_each(move |elt| self.push_back(elt));
     }
@@ -1908,7 +1995,7 @@ impl<T> SpecExtend<LinkedList<T>> for LinkedList<T> {
 }
 
 #[stable(feature = "extend_ref", since = "1.2.0")]
-impl<'a, T: 'a + Copy> Extend<&'a T> for LinkedList<T> {
+impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for LinkedList<T, A> {
     fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
         self.extend(iter.into_iter().cloned());
     }
@@ -1920,7 +2007,7 @@ impl<'a, T: 'a + Copy> Extend<&'a T> for LinkedList<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: PartialEq> PartialEq for LinkedList<T> {
+impl<T: PartialEq, A: Allocator> PartialEq for LinkedList<T, A> {
     fn eq(&self, other: &Self) -> bool {
         self.len() == other.len() && self.iter().eq(other)
     }
@@ -1931,17 +2018,17 @@ impl<T: PartialEq> PartialEq for LinkedList<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Eq> Eq for LinkedList<T> {}
+impl<T: Eq, A: Allocator> Eq for LinkedList<T, A> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: PartialOrd> PartialOrd for LinkedList<T> {
+impl<T: PartialOrd, A: Allocator> PartialOrd for LinkedList<T, A> {
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
         self.iter().partial_cmp(other)
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Ord> Ord for LinkedList<T> {
+impl<T: Ord, A: Allocator> Ord for LinkedList<T, A> {
     #[inline]
     fn cmp(&self, other: &Self) -> Ordering {
         self.iter().cmp(other)
@@ -1949,9 +2036,11 @@ impl<T: Ord> Ord for LinkedList<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Clone> Clone for LinkedList<T> {
+impl<T: Clone, A: Allocator + Clone> Clone for LinkedList<T, A> {
     fn clone(&self) -> Self {
-        self.iter().cloned().collect()
+        let mut list = Self::new_in(self.alloc.clone());
+        list.extend(self.iter().cloned());
+        list
     }
 
     fn clone_from(&mut self, other: &Self) {
@@ -1969,14 +2058,14 @@ impl<T: Clone> Clone for LinkedList<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: fmt::Debug> fmt::Debug for LinkedList<T> {
+impl<T: fmt::Debug, A: Allocator> fmt::Debug for LinkedList<T, A> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_list().entries(self).finish()
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Hash> Hash for LinkedList<T> {
+impl<T: Hash, A: Allocator> Hash for LinkedList<T, A> {
     fn hash<H: Hasher>(&self, state: &mut H) {
         state.write_length_prefix(self.len());
         for elt in self {
@@ -2016,10 +2105,10 @@ fn assert_covariance() {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Send> Send for LinkedList<T> {}
+unsafe impl<T: Send, A: Allocator + Send> Send for LinkedList<T, A> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Sync> Sync for LinkedList<T> {}
+unsafe impl<T: Sync, A: Allocator + Sync> Sync for LinkedList<T, A> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<T: Sync> Send for Iter<'_, T> {}
@@ -2034,13 +2123,13 @@ unsafe impl<T: Send> Send for IterMut<'_, T> {}
 unsafe impl<T: Sync> Sync for IterMut<'_, T> {}
 
 #[unstable(feature = "linked_list_cursors", issue = "58533")]
-unsafe impl<T: Sync> Send for Cursor<'_, T> {}
+unsafe impl<T: Sync, A: Allocator + Sync> Send for Cursor<'_, T, A> {}
 
 #[unstable(feature = "linked_list_cursors", issue = "58533")]
-unsafe impl<T: Sync> Sync for Cursor<'_, T> {}
+unsafe impl<T: Sync, A: Allocator + Sync> Sync for Cursor<'_, T, A> {}
 
 #[unstable(feature = "linked_list_cursors", issue = "58533")]
-unsafe impl<T: Send> Send for CursorMut<'_, T> {}
+unsafe impl<T: Send, A: Allocator + Send> Send for CursorMut<'_, T, A> {}
 
 #[unstable(feature = "linked_list_cursors", issue = "58533")]
-unsafe impl<T: Sync> Sync for CursorMut<'_, T> {}
+unsafe impl<T: Sync, A: Allocator + Sync> Sync for CursorMut<'_, T, A> {}
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 2c6a266e2a1..a002421aeef 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -135,7 +135,6 @@
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(maybe_uninit_uninit_array_transpose)]
-#![feature(panic_internals)]
 #![feature(pattern)]
 #![feature(pointer_byte_offsets)]
 #![feature(provide_any)]
diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs
index 9d8e309a978..5d9772b878b 100644
--- a/library/alloc/src/task.rs
+++ b/library/alloc/src/task.rs
@@ -39,6 +39,7 @@ use crate::sync::Arc;
 /// use std::sync::Arc;
 /// use std::task::{Context, Poll, Wake};
 /// use std::thread::{self, Thread};
+/// use core::pin::pin;
 ///
 /// /// A waker that wakes up the current thread when called.
 /// struct ThreadWaker(Thread);
@@ -52,7 +53,7 @@ use crate::sync::Arc;
 /// /// Run a future to completion on the current thread.
 /// fn block_on<T>(fut: impl Future<Output = T>) -> T {
 ///     // Pin the future so it can be polled.
-///     let mut fut = Box::pin(fut);
+///     let mut fut = pin!(fut);
 ///
 ///     // Create a new context to be passed to the future.
 ///     let t = thread::current();
diff --git a/library/core/benches/num/flt2dec/strategy/grisu.rs b/library/core/benches/num/flt2dec/strategy/grisu.rs
index 6bea5e55d37..17d6b474ad2 100644
--- a/library/core/benches/num/flt2dec/strategy/grisu.rs
+++ b/library/core/benches/num/flt2dec/strategy/grisu.rs
@@ -81,3 +81,30 @@ fn bench_big_exact_inf(b: &mut Bencher) {
         format_exact(black_box(&decoded), &mut buf, i16::MIN);
     });
 }
+
+#[bench]
+fn bench_one_exact_inf(b: &mut Bencher) {
+    let decoded = decode_finite(1.0);
+    let mut buf = [MaybeUninit::new(0); 1024];
+    b.iter(|| {
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
+    });
+}
+
+#[bench]
+fn bench_trailing_zero_exact_inf(b: &mut Bencher) {
+    let decoded = decode_finite(250.000000000000000000000000);
+    let mut buf = [MaybeUninit::new(0); 1024];
+    b.iter(|| {
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
+    });
+}
+
+#[bench]
+fn bench_halfway_point_exact_inf(b: &mut Bencher) {
+    let decoded = decode_finite(1.00000000000000011102230246251565404236316680908203125);
+    let mut buf = [MaybeUninit::new(0); 1024];
+    b.iter(|| {
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
+    });
+}
diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs
index 44adcfa1a94..1b213f6a294 100644
--- a/library/core/src/cell/lazy.rs
+++ b/library/core/src/cell/lazy.rs
@@ -63,6 +63,34 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
         LazyCell { state: UnsafeCell::new(State::Uninit(f)) }
     }
 
+    /// Consumes this `LazyCell` returning the stored value.
+    ///
+    /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(lazy_cell)]
+    /// #![feature(lazy_cell_consume)]
+    ///
+    /// use std::cell::LazyCell;
+    ///
+    /// let hello = "Hello, World!".to_string();
+    ///
+    /// let lazy = LazyCell::new(|| hello.to_uppercase());
+    ///
+    /// assert_eq!(&*lazy, "HELLO, WORLD!");
+    /// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
+    /// ```
+    #[unstable(feature = "lazy_cell_consume", issue = "109736")]
+    pub fn into_inner(this: Self) -> Result<T, F> {
+        match this.state.into_inner() {
+            State::Init(data) => Ok(data),
+            State::Uninit(f) => Err(f),
+            State::Poisoned => panic!("LazyCell instance has previously been poisoned"),
+        }
+    }
+
     /// Forces the evaluation of this lazy value and returns a reference to
     /// the result.
     ///
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index cc3179ee780..7c93c93b4a0 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1531,6 +1531,16 @@ pub(crate) mod builtin {
         /* compiler built-in */
     }
 
+    /// Attribute macro applied to a function to register it as a handler for allocation failure.
+    ///
+    /// See also [`std::alloc::handle_alloc_error`](../../../std/alloc/fn.handle_alloc_error.html).
+    #[unstable(feature = "alloc_error_handler", issue = "51540")]
+    #[allow_internal_unstable(rustc_attrs)]
+    #[rustc_builtin_macro]
+    pub macro alloc_error_handler($item:item) {
+        /* compiler built-in */
+    }
+
     /// Keeps the item it's applied to if the passed path is accessible, and removes it otherwise.
     #[unstable(
         feature = "cfg_accessible",
diff --git a/library/core/src/num/flt2dec/strategy/grisu.rs b/library/core/src/num/flt2dec/strategy/grisu.rs
index ed3e0edaff2..b9f0d114c6a 100644
--- a/library/core/src/num/flt2dec/strategy/grisu.rs
+++ b/library/core/src/num/flt2dec/strategy/grisu.rs
@@ -487,6 +487,22 @@ pub fn format_exact_opt<'a>(
     let vint = (v.f >> e) as u32;
     let vfrac = v.f & ((1 << e) - 1);
 
+    let requested_digits = buf.len();
+
+    const POW10_UP_TO_9: [u32; 10] =
+        [1, 10, 100, 1000, 10_000, 100_000, 1_000_000, 10_000_000, 100_000_000, 1_000_000_000];
+
+    // We deviate from the original algorithm here and do some early checks to determine if we can satisfy requested_digits.
+    // If we determine that we can't, we exit early and avoid most of the heavy lifting that the algorithm otherwise does.
+    //
+    // When vfrac is zero, we can easily determine if vint can satisfy requested digits:
+    //      If requested_digits >= 11, vint is not able to exhaust the count by itself since 10^(11 -1) > u32 max value >= vint.
+    //      If vint < 10^(requested_digits - 1), vint cannot exhaust the count.
+    //      Otherwise, vint might be able to exhaust the count and we need to execute the rest of the code.
+    if (vfrac == 0) && ((requested_digits >= 11) || (vint < POW10_UP_TO_9[requested_digits - 1])) {
+        return None;
+    }
+
     // both old `v` and new `v` (scaled by `10^-k`) has an error of < 1 ulp (Theorem 5.1).
     // as we don't know the error is positive or negative, we use two approximations
     // spaced equally and have the maximal error of 2 ulps (same to the shortest case).
diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs
index 9c4c0f6ab7a..10525a16f3a 100644
--- a/library/core/src/prelude/v1.rs
+++ b/library/core/src/prelude/v1.rs
@@ -76,7 +76,9 @@ pub use crate::macros::builtin::{RustcDecodable, RustcEncodable};
 // Do not `doc(no_inline)` so that they become doc items on their own
 // (no public module for them to be re-exported from).
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-pub use crate::macros::builtin::{bench, derive, global_allocator, test, test_case};
+pub use crate::macros::builtin::{
+    alloc_error_handler, bench, derive, global_allocator, test, test_case,
+};
 
 #[unstable(feature = "derive_const", issue = "none")]
 pub use crate::macros::builtin::derive_const;
diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs
index 07fd96f9295..e6e3b55efa9 100644
--- a/library/core/src/slice/sort.rs
+++ b/library/core/src/slice/sort.rs
@@ -1456,7 +1456,6 @@ pub struct TimSortRun {
 
 /// Takes a range as denoted by start and end, that is already sorted and extends it to the right if
 /// necessary with sorts optimized for smaller ranges such as insertion sort.
-#[cfg(not(no_global_oom_handling))]
 fn provide_sorted_batch<T, F>(v: &mut [T], start: usize, mut end: usize, is_less: &mut F) -> usize
 where
     F: FnMut(&T, &T) -> bool,
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 109387b09d0..f2fda64a1ee 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -67,7 +67,7 @@ llvm-libunwind = ["unwind/llvm-libunwind"]
 system-llvm-libunwind = ["unwind/system-llvm-libunwind"]
 
 # Make panics and failed asserts immediately abort without formatting any message
-panic_immediate_abort = ["alloc/panic_immediate_abort"]
+panic_immediate_abort = ["core/panic_immediate_abort"]
 
 # Enable std_detect default features for stdarch/crates/std_detect:
 # https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs
index 448a8edc291..c5a5991cc81 100644
--- a/library/std/src/alloc.rs
+++ b/library/std/src/alloc.rs
@@ -57,8 +57,9 @@
 #![stable(feature = "alloc_module", since = "1.28.0")]
 
 use core::intrinsics;
-use core::ptr;
 use core::ptr::NonNull;
+use core::sync::atomic::{AtomicPtr, Ordering};
+use core::{mem, ptr};
 
 #[stable(feature = "alloc_module", since = "1.28.0")]
 #[doc(inline)]
@@ -285,6 +286,76 @@ unsafe impl Allocator for System {
     }
 }
 
+static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
+
+/// Registers a custom allocation error hook, replacing any that was previously registered.
+///
+/// The allocation error hook is invoked when an infallible memory allocation fails, before
+/// the runtime aborts. The default hook prints a message to standard error,
+/// but this behavior can be customized with the [`set_alloc_error_hook`] and
+/// [`take_alloc_error_hook`] functions.
+///
+/// The hook is provided with a `Layout` struct which contains information
+/// about the allocation that failed.
+///
+/// The allocation error hook is a global resource.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(alloc_error_hook)]
+///
+/// use std::alloc::{Layout, set_alloc_error_hook};
+///
+/// fn custom_alloc_error_hook(layout: Layout) {
+///    panic!("memory allocation of {} bytes failed", layout.size());
+/// }
+///
+/// set_alloc_error_hook(custom_alloc_error_hook);
+/// ```
+#[unstable(feature = "alloc_error_hook", issue = "51245")]
+pub fn set_alloc_error_hook(hook: fn(Layout)) {
+    HOOK.store(hook as *mut (), Ordering::SeqCst);
+}
+
+/// Unregisters the current allocation error hook, returning it.
+///
+/// *See also the function [`set_alloc_error_hook`].*
+///
+/// If no custom hook is registered, the default hook will be returned.
+#[unstable(feature = "alloc_error_hook", issue = "51245")]
+pub fn take_alloc_error_hook() -> fn(Layout) {
+    let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
+    if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }
+}
+
+fn default_alloc_error_hook(layout: Layout) {
+    extern "Rust" {
+        // This symbol is emitted by rustc next to __rust_alloc_error_handler.
+        // Its value depends on the -Zoom={panic,abort} compiler option.
+        static __rust_alloc_error_handler_should_panic: u8;
+    }
+
+    #[allow(unused_unsafe)]
+    if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
+        panic!("memory allocation of {} bytes failed", layout.size());
+    } else {
+        rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
+    }
+}
+
+#[cfg(not(test))]
+#[doc(hidden)]
+#[alloc_error_handler]
+#[unstable(feature = "alloc_internals", issue = "none")]
+pub fn rust_oom(layout: Layout) -> ! {
+    let hook = HOOK.load(Ordering::SeqCst);
+    let hook: fn(Layout) =
+        if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } };
+    hook(layout);
+    crate::process::abort()
+}
+
 #[cfg(not(test))]
 #[doc(hidden)]
 #[allow(unused_attributes)]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 933f75d638b..318a46d1b63 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -236,6 +236,7 @@
 //
 // Language features:
 // tidy-alphabetical-start
+#![feature(alloc_error_handler)]
 #![feature(allocator_internals)]
 #![feature(allow_internal_unsafe)]
 #![feature(allow_internal_unstable)]
@@ -319,7 +320,6 @@
 #![feature(get_mut_unchecked)]
 #![feature(map_try_insert)]
 #![feature(new_uninit)]
-#![feature(panic_oom_payload)]
 #![feature(slice_concat_trait)]
 #![feature(thin_box)]
 #![feature(try_reserve_kind)]
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index ca4cf68ad54..a46a29cbad6 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -245,24 +245,19 @@ fn default_hook(info: &PanicInfo<'_>) {
 
     // The current implementation always returns `Some`.
     let location = info.location().unwrap();
+
+    let msg = match info.payload().downcast_ref::<&'static str>() {
+        Some(s) => *s,
+        None => match info.payload().downcast_ref::<String>() {
+            Some(s) => &s[..],
+            None => "Box<dyn Any>",
+        },
+    };
     let thread = thread_info::current_thread();
     let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
 
     let write = |err: &mut dyn crate::io::Write| {
-        // Use the panic message directly if available, otherwise take it from
-        // the payload.
-        if let Some(msg) = info.message() {
-            let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
-        } else {
-            let msg = if let Some(s) = info.payload().downcast_ref::<&'static str>() {
-                *s
-            } else if let Some(s) = info.payload().downcast_ref::<String>() {
-                &s[..]
-            } else {
-                "Box<dyn Any>"
-            };
-            let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
-        }
+        let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
 
         static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
 
@@ -529,8 +524,6 @@ pub fn panicking() -> bool {
 #[cfg(not(test))]
 #[panic_handler]
 pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
-    use alloc::alloc::AllocErrorPanicPayload;
-
     struct PanicPayload<'a> {
         inner: &'a fmt::Arguments<'a>,
         string: Option<String>,
@@ -557,7 +550,8 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
     unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
         fn take_box(&mut self) -> *mut (dyn Any + Send) {
             // We do two allocations here, unfortunately. But (a) they're required with the current
-            // scheme, and (b) OOM uses its own separate payload type which doesn't allocate.
+            // scheme, and (b) we don't handle panic + OOM properly anyway (see comment in
+            // begin_panic below).
             let contents = mem::take(self.fill());
             Box::into_raw(Box::new(contents))
         }
@@ -582,14 +576,7 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
     let loc = info.location().unwrap(); // The current implementation always returns Some
     let msg = info.message().unwrap(); // The current implementation always returns Some
     crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
-        if let Some(payload) = info.payload().downcast_ref::<AllocErrorPanicPayload>() {
-            rust_panic_with_hook(
-                &mut payload.internal_clone(),
-                info.message(),
-                loc,
-                info.can_unwind(),
-            );
-        } else if let Some(msg) = msg.as_str() {
+        if let Some(msg) = msg.as_str() {
             rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc, info.can_unwind());
         } else {
             rust_panic_with_hook(
@@ -636,7 +623,11 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
 
     unsafe impl<A: Send + 'static> BoxMeUp for PanicPayload<A> {
         fn take_box(&mut self) -> *mut (dyn Any + Send) {
-            // Note that this should be the only allocation performed in this code path.
+            // Note that this should be the only allocation performed in this code path. Currently
+            // this means that panic!() on OOM will invoke this code path, but then again we're not
+            // really ready for panic on OOM anyway. If we do start doing this, then we should
+            // propagate this allocation to be performed in the parent of this thread instead of the
+            // thread that's panicking.
             let data = match self.inner.take() {
                 Some(a) => Box::new(a) as Box<dyn Any + Send>,
                 None => process::abort(),
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index 4f325a70b18..2aefd7c513d 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -60,7 +60,9 @@ pub use core::prelude::v1::{RustcDecodable, RustcEncodable};
 // Do not `doc(no_inline)` so that they become doc items on their own
 // (no public module for them to be re-exported from).
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case};
+pub use core::prelude::v1::{
+    alloc_error_handler, bench, derive, global_allocator, test, test_case,
+};
 
 #[unstable(feature = "derive_const", issue = "none")]
 pub use core::prelude::v1::derive_const;
diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs
index 8e9ea293ce4..a6bc468b092 100644
--- a/library/std/src/sync/lazy_lock.rs
+++ b/library/std/src/sync/lazy_lock.rs
@@ -1,9 +1,9 @@
 use crate::cell::UnsafeCell;
-use crate::fmt;
 use crate::mem::ManuallyDrop;
 use crate::ops::Deref;
 use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::sync::Once;
+use crate::{fmt, ptr};
 
 use super::once::ExclusiveState;
 
@@ -69,6 +69,42 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
         LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) }
     }
 
+    /// Consumes this `LazyLock` returning the stored value.
+    ///
+    /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(lazy_cell)]
+    /// #![feature(lazy_cell_consume)]
+    ///
+    /// use std::sync::LazyLock;
+    ///
+    /// let hello = "Hello, World!".to_string();
+    ///
+    /// let lazy = LazyLock::new(|| hello.to_uppercase());
+    ///
+    /// assert_eq!(&*lazy, "HELLO, WORLD!");
+    /// assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
+    /// ```
+    #[unstable(feature = "lazy_cell_consume", issue = "109736")]
+    pub fn into_inner(mut this: Self) -> Result<T, F> {
+        let state = this.once.state();
+        match state {
+            ExclusiveState::Poisoned => panic!("LazyLock instance has previously been poisoned"),
+            state => {
+                let this = ManuallyDrop::new(this);
+                let data = unsafe { ptr::read(&this.data) }.into_inner();
+                match state {
+                    ExclusiveState::Incomplete => Err(ManuallyDrop::into_inner(unsafe { data.f })),
+                    ExclusiveState::Complete => Ok(ManuallyDrop::into_inner(unsafe { data.value })),
+                    ExclusiveState::Poisoned => unreachable!(),
+                }
+            }
+        }
+    }
+
     /// Forces the evaluation of this lazy value and
     /// returns a reference to result. This is equivalent
     /// to the `Deref` impl, but is explicit.
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index f95a97518c5..dd1851e29a9 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -139,6 +139,10 @@ v("musl-root-mips64", "target.mips64-unknown-linux-muslabi64.musl-root",
   "mips64-unknown-linux-muslabi64 install directory")
 v("musl-root-mips64el", "target.mips64el-unknown-linux-muslabi64.musl-root",
   "mips64el-unknown-linux-muslabi64 install directory")
+v("musl-root-riscv32gc", "target.riscv32gc-unknown-linux-musl.musl-root",
+  "riscv32gc-unknown-linux-musl install directory")
+v("musl-root-riscv64gc", "target.riscv64gc-unknown-linux-musl.musl-root",
+  "riscv64gc-unknown-linux-musl install directory")
 v("qemu-armhf-rootfs", "target.arm-unknown-linux-gnueabihf.qemu-rootfs",
   "rootfs in qemu testing, you probably don't want to use this")
 v("qemu-aarch64-rootfs", "target.aarch64-unknown-linux-gnu.qemu-rootfs",
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile
index 21dcf29b4a9..d45ef0a7d07 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile
@@ -32,6 +32,10 @@ RUN sh /scripts/sccache.sh
 # LLVM, rather than the typical src/llvm-project LLVM.
 ENV NO_DOWNLOAD_CI_LLVM 1
 
+# This is not the latest LLVM version, so some components required by tests may
+# be missing.
+ENV IS_NOT_LATEST_LLVM 1
+
 # Using llvm-link-shared due to libffi issues -- see #34486
 ENV RUST_CONFIGURE_ARGS \
       --build=x86_64-unknown-linux-gnu \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile
index cfb638e8b07..1f28b939778 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile
@@ -38,6 +38,10 @@ RUN sh /scripts/sccache.sh
 # LLVM, rather than the typical src/llvm-project LLVM.
 ENV NO_DOWNLOAD_CI_LLVM 1
 
+# This is not the latest LLVM version, so some components required by tests may
+# be missing.
+ENV IS_NOT_LATEST_LLVM 1
+
 # Using llvm-link-shared due to libffi issues -- see #34486
 ENV RUST_CONFIGURE_ARGS \
       --build=x86_64-unknown-linux-gnu \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile
index c471843b853..960683b92bd 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile
@@ -38,6 +38,10 @@ RUN sh /scripts/sccache.sh
 # LLVM, rather than the typical src/llvm-project LLVM.
 ENV NO_DOWNLOAD_CI_LLVM 1
 
+# This is not the latest LLVM version, so some components required by tests may
+# be missing.
+ENV IS_NOT_LATEST_LLVM 1
+
 # Using llvm-link-shared due to libffi issues -- see #34486
 ENV RUST_CONFIGURE_ARGS \
       --build=x86_64-unknown-linux-gnu \
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 3056d9fc054..966af3abc6f 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -143,7 +143,11 @@ if [ "$RUST_RELEASE_CHANNEL" = "nightly" ] || [ "$DIST_REQUIRE_ALL_TOOLS" = "" ]
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-missing-tools"
 fi
 
-export COMPILETEST_NEEDS_ALL_LLVM_COMPONENTS=1
+# Unless we're using an older version of LLVM, check that all LLVM components
+# used by tests are available.
+if [ "$IS_NOT_LATEST_LLVM" = "" ]; then
+  export COMPILETEST_NEEDS_ALL_LLVM_COMPONENTS=1
+fi
 
 # Print the date from the local machine and the date from an external source to
 # check for clock drifts. An HTTP URL is used instead of HTTPS since on Azure
diff --git a/src/doc/book b/src/doc/book
-Subproject c06006157b14b3d47b5c716fc392b77f3b2e21c
+Subproject 8fa6b854d515506d825390fe0d817f5ef0c8935
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject 701d1551429da4cb609082c0ac99df569e33671
+Subproject 897fcf566f16bf87bf37199bdddec1801fd0053
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject 6337ed17fb8dcd918d78b7d97d213e923530337
+Subproject 2a5eb92197e9cf8fe91164dcbf4f9b88c0d7e73
diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
index 1f52ab75010..1874baa0c38 100644
--- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
+++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
@@ -17,6 +17,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 - AVR
 - MSP430
 - M68k
+- LoongArch
 
 ## Register classes
 
@@ -45,6 +46,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | M68k         | `reg`          | `d[0-7]`, `a[0-7]`                 | `r`                  |
 | M68k         | `reg_data`     | `d[0-7]`                           | `d`                  |
 | M68k         | `reg_addr`     | `a[0-3]`                           | `a`                  |
+| LoongArch    | `reg`          | `$r1`, `$r[4-20]`, `$r[23,30]`     | `r`                  |
+| LoongArch    | `freg`         | `$f[0-31]`                         | `f`                  |
 
 > **Notes**:
 > - NVPTX doesn't have a fixed register set, so named registers are not supported.
@@ -76,6 +79,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | MSP430       | `reg`                           | None           | `i8`, `i16`                             |
 | M68k         | `reg`, `reg_addr`               | None           | `i16`, `i32`                            |
 | M68k         | `reg_data`                      | None           | `i8`, `i16`, `i32`                      |
+| LoongArch64  | `reg`                           | None           | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` |
+| LoongArch64  | `freg`                          | None           | `f32`, `f64`                            |
 
 ## Register aliases
 
@@ -97,6 +102,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | M68k         | `a5`          | `bp`      |
 | M68k         | `a6`          | `fp`      |
 | M68k         | `a7`          | `sp`, `usp`, `ssp`, `isp` |
+| LoongArch    | `$r0`         | `zero`    |
+| LoongArch    | `$r2`         | `tp`      |
+| LoongArch    | `$r3`         | `sp`      |
+| LoongArch    | `$r22`        | `fp`      |
 
 > **Notes**:
 > - TI does not mandate a frame pointer for MSP430, but toolchains are allowed
@@ -107,7 +116,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | Architecture | Unsupported register                    | Reason                                                                                                                                                                              |
 | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | All          | `sp`                                    | The stack pointer must be restored to its original value at the end of an asm code block.                                                                                           |
-| All          | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k) | The frame pointer cannot be used as an input or output.                                                                                                                             |
+| All          | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `$fp` (LoongArch) | The frame pointer cannot be used as an input or output.                                                                                                                             |
 | All          | `r19` (Hexagon)                         | This is used internally by LLVM as a "base pointer" for functions with complex stack frames.                                                                                        |
 | MIPS         | `$0` or `$zero`                         | This is a constant zero register which can't be modified.                                                                                                                           |
 | MIPS         | `$1` or `$at`                           | Reserved for assembler.                                                                                                                                                             |
@@ -118,6 +127,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | AVR          | `r0`, `r1`, `r1r0`                      | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs.  If modified, they must be restored to their original values before the end of the block. |
 |MSP430        | `r0`, `r2`, `r3`                        | These are the program counter, status register, and constant generator respectively. Neither the status register nor constant generator can be written to.                          |
 | M68k         | `a4`, `a5`                              | Used internally by LLVM for the base pointer and global base pointer. |
+| LoongArch    | `$r0` or `$zero`                        | This is a constant zero register which can't be modified.                                                                                                                           |
+| LoongArch    | `$r2` or `$tp`                          | This is reserved for TLS.                                                                                                                                                           |
+| LoongArch    | `$r21`                                  | This is reserved by the ABI.                                                                                                                                                        |
+| LoongArch    | `$r31` or `$s8`                         | This is used internally by LLVM.                                                                                                                                                    |
 
 ## Template modifiers
 
@@ -132,6 +145,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | PowerPC      | `reg`          | None     | `0`            | None          |
 | PowerPC      | `reg_nonzero`  | None     | `3`            | `b`           |
 | PowerPC      | `freg`         | None     | `0`            | None          |
+| LoongArch    | `reg`          | None     | `$r2`          | None          |
+| LoongArch    | `freg`         | None     | `$f0`          | None          |
 
 # Flags covered by `preserves_flags`
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 04379c2bca9..c992a5388d1 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -422,8 +422,8 @@ fn clean_projection<'tcx>(
         let bounds = cx
             .tcx
             .explicit_item_bounds(ty.skip_binder().def_id)
-            .iter()
-            .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, ty.skip_binder().substs))
+            .subst_iter_copied(cx.tcx, ty.skip_binder().substs)
+            .map(|(pred, _)| pred)
             .collect::<Vec<_>>();
         return clean_middle_opaque_bounds(cx, bounds);
     }
@@ -1315,10 +1315,11 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
             }
 
             if let ty::TraitContainer = assoc_item.container {
-                let bounds = tcx.explicit_item_bounds(assoc_item.def_id);
+                let bounds =
+                    tcx.explicit_item_bounds(assoc_item.def_id).subst_identity_iter_copied();
                 let predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates;
                 let predicates =
-                    tcx.arena.alloc_from_iter(bounds.into_iter().chain(predicates).copied());
+                    tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied()));
                 let mut generics = clean_ty_generics(
                     cx,
                     tcx.generics_of(assoc_item.def_id),
@@ -1845,8 +1846,8 @@ pub(crate) fn clean_middle_ty<'tcx>(
             let bounds = cx
                 .tcx
                 .explicit_item_bounds(def_id)
-                .iter()
-                .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs))
+                .subst_iter_copied(cx.tcx, substs)
+                .map(|(bound, _)| bound)
                 .collect::<Vec<_>>();
             clean_middle_opaque_bounds(cx, bounds)
         }
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject de80432f04da61d98dcbbc1572598071718ccfd
+Subproject 9e586fbd8b931494067144623b76c37d213b1ab
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index ed0bd58c770..ff838c2d56e 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -4,7 +4,7 @@ use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, AliasTy, Clause, EarlyBinder, PredicateKind};
+use rustc_middle::ty::{self, AliasTy, Clause, PredicateKind};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{sym, Span};
@@ -66,8 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
         if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() {
             let preds = cx.tcx.explicit_item_bounds(def_id);
             let mut is_future = false;
-            for &(p, _span) in preds {
-                let p = EarlyBinder(p).subst(cx.tcx, substs);
+            for (p, _span) in preds.subst_iter_copied(cx.tcx, substs) {
                 if let Some(trait_pred) = p.to_opt_poly_trait_pred() {
                     if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() {
                         is_future = true;
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 8b996c18816..cb700126c2b 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -90,7 +90,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                         return false;
                     }
 
-                    for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
+                    for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).subst_identity_iter_copied() {
                         match predicate.kind().skip_binder() {
                             // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
                             // and check substituions to find `U`.
@@ -267,7 +267,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         },
         ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)),
         ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
-            for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
+            for (predicate, _) in cx.tcx.explicit_item_bounds(def_id).skip_binder() {
                 if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() {
                     if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) {
                         return true;
@@ -743,7 +743,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option
 
     for (pred, _) in cx
         .tcx
-        .bound_explicit_item_bounds(ty.def_id)
+        .explicit_item_bounds(ty.def_id)
         .subst_iter_copied(cx.tcx, ty.substs)
     {
         match pred.kind().skip_binder() {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs
index e3e5fac98c0..f7c1e683d0d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs
@@ -382,6 +382,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
     rustc_attr!(rustc_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
     gated!(
+        alloc_error_handler, Normal, template!(Word), WarnFollowing,
+        experimental!(alloc_error_handler)
+    ),
+    gated!(
         default_lib_allocator, Normal, template!(Word), WarnFollowing, allocator_internals,
         experimental!(default_lib_allocator),
     ),
diff --git a/tests/assembly/asm/loongarch-type.rs b/tests/assembly/asm/loongarch-type.rs
new file mode 100644
index 00000000000..4e296f3ade5
--- /dev/null
+++ b/tests/assembly/asm/loongarch-type.rs
@@ -0,0 +1,196 @@
+// min-llvm-version: 16.0
+// assembly-output: emit-asm
+// compile-flags: --target loongarch64-unknown-linux-gnu
+// needs-llvm-components: loongarch
+
+#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)]
+#![crate_type = "rlib"]
+#![no_core]
+#![allow(asm_sub_register, non_camel_case_types)]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+    () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! concat {
+    () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! stringify {
+    () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+type ptr = *const i32;
+
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for i64 {}
+impl Copy for f32 {}
+impl Copy for f64 {}
+impl Copy for ptr {}
+extern "C" {
+    fn extern_func();
+    static extern_static: u8;
+}
+
+// Hack to avoid function merging
+extern "Rust" {
+   fn dont_merge(s: &str);
+}
+
+// CHECK-LABEL: sym_fn:
+// CHECK: #APP
+// CHECK: pcalau12i $t0, %got_pc_hi20(extern_func)
+// CHECK: ld.d $t0, $t0, %got_pc_lo12(extern_func)
+// CHECK: #NO_APP
+#[no_mangle]
+pub unsafe fn sym_fn() {
+    asm!("la.got $r12, {}", sym extern_func);
+}
+
+// CHECK-LABEL: sym_static:
+// CHECK: #APP
+// CHECK: pcalau12i $t0, %got_pc_hi20(extern_static)
+// CHECK: ld.d $t0, $t0, %got_pc_lo12(extern_static)
+// CHECK: #NO_APP
+#[no_mangle]
+pub unsafe fn sym_static() {
+    asm!("la.got $r12, {}", sym extern_static);
+}
+
+macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => {
+    #[no_mangle]
+    pub unsafe fn $func(x: $ty) -> $ty {
+        dont_merge(stringify!($func));
+
+        let y;
+        asm!(concat!($mov," {}, {}"), out($class) y, in($class) x);
+        y
+    }
+};}
+
+macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => {
+    #[no_mangle]
+    pub unsafe fn $func(x: $ty) -> $ty {
+        dont_merge(stringify!($func));
+
+        let y;
+        asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x);
+        y
+    }
+};}
+
+// CHECK-LABEL: reg_i8:
+// CHECK: #APP
+// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}}
+// CHECK: #NO_APP
+check!(reg_i8, i8, reg, "move");
+
+// CHECK-LABEL: reg_i16:
+// CHECK: #APP
+// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}}
+// CHECK: #NO_APP
+check!(reg_i16, i16, reg, "move");
+
+// CHECK-LABEL: reg_i32:
+// CHECK: #APP
+// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}}
+// CHECK: #NO_APP
+check!(reg_i32, i32, reg, "move");
+
+// CHECK-LABEL: reg_f32:
+// CHECK: #APP
+// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}}
+// CHECK: #NO_APP
+check!(reg_f32, f32, reg, "move");
+
+// CHECK-LABEL: reg_i64:
+// CHECK: #APP
+// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}}
+// CHECK: #NO_APP
+check!(reg_i64, i64, reg, "move");
+
+// CHECK-LABEL: reg_f64:
+// CHECK: #APP
+// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}}
+// CHECK: #NO_APP
+check!(reg_f64, f64, reg, "move");
+
+// CHECK-LABEL: reg_ptr:
+// CHECK: #APP
+// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}}
+// CHECK: #NO_APP
+check!(reg_ptr, ptr, reg, "move");
+
+// CHECK-LABEL: freg_f32:
+// CHECK: #APP
+// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}}
+// CHECK: #NO_APP
+check!(freg_f32, f32, freg, "fmov.s");
+
+// CHECK-LABEL: freg_f64:
+// CHECK: #APP
+// CHECK: fmov.d $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}}
+// CHECK: #NO_APP
+check!(freg_f64, f64, freg, "fmov.d");
+
+// CHECK-LABEL: r4_i8:
+// CHECK: #APP
+// CHECK: move $a0, $a0
+// CHECK: #NO_APP
+check_reg!(r4_i8, i8, "$r4", "move");
+
+// CHECK-LABEL: r4_i16:
+// CHECK: #APP
+// CHECK: move $a0, $a0
+// CHECK: #NO_APP
+check_reg!(r4_i16, i16, "$r4", "move");
+
+// CHECK-LABEL: r4_i32:
+// CHECK: #APP
+// CHECK: move $a0, $a0
+// CHECK: #NO_APP
+check_reg!(r4_i32, i32, "$r4", "move");
+
+// CHECK-LABEL: r4_f32:
+// CHECK: #APP
+// CHECK: move $a0, $a0
+// CHECK: #NO_APP
+check_reg!(r4_f32, f32, "$r4", "move");
+
+// CHECK-LABEL: r4_i64:
+// CHECK: #APP
+// CHECK: move $a0, $a0
+// CHECK: #NO_APP
+check_reg!(r4_i64, i64, "$r4", "move");
+
+// CHECK-LABEL: r4_f64:
+// CHECK: #APP
+// CHECK: move $a0, $a0
+// CHECK: #NO_APP
+check_reg!(r4_f64, f64, "$r4", "move");
+
+// CHECK-LABEL: r4_ptr:
+// CHECK: #APP
+// CHECK: move $a0, $a0
+// CHECK: #NO_APP
+check_reg!(r4_ptr, ptr, "$r4", "move");
+
+// CHECK-LABEL: f0_f32:
+// CHECK: #APP
+// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}}
+// CHECK: #NO_APP
+check_reg!(f0_f32, f32, "$f0", "fmov.s");
+
+// CHECK-LABEL: f0_f64:
+// CHECK: #APP
+// CHECK: fmov.d $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}}
+// CHECK: #NO_APP
+check_reg!(f0_f64, f64, "$f0", "fmov.d");
diff --git a/tests/debuginfo/pretty-std.rs b/tests/debuginfo/pretty-std.rs
index 7bb2810c2b2..c7df7dc3cb3 100644
--- a/tests/debuginfo/pretty-std.rs
+++ b/tests/debuginfo/pretty-std.rs
@@ -130,8 +130,8 @@
 // cdb-check:    [+0x000] __0              : "IAMA optional string!" [Type: alloc::string::String]
 
 // cdb-command: dx linkedlist
-// cdb-check:linkedlist       : { len=0x2 } [Type: alloc::collections::linked_list::LinkedList<i32>]
-// cdb-check:    [<Raw View>]     [Type: alloc::collections::linked_list::LinkedList<i32>]
+// cdb-check:linkedlist       : { len=0x2 } [Type: alloc::collections::linked_list::LinkedList<i32,alloc::alloc::Global>]
+// cdb-check:    [<Raw View>]     [Type: alloc::collections::linked_list::LinkedList<i32,alloc::alloc::Global>]
 // cdb-check:    [0x0]            : 128 [Type: int]
 // cdb-check:    [0x1]            : 42 [Type: int]
 
diff --git a/tests/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir b/tests/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir
index 6cd6d8b7795..be5baf6ee39 100644
--- a/tests/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir
+++ b/tests/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir
@@ -1,39 +1,39 @@
 // MIR for `use_x` 0 nll
 
 | Free Region Mapping
-| '_#0r | Global | ['_#2r, '_#1r, '_#0r, '_#4r, '_#3r]
-| '_#1r | Local | ['_#1r, '_#4r]
-| '_#2r | Local | ['_#2r, '_#1r, '_#4r]
-| '_#3r | Local | ['_#4r, '_#3r]
-| '_#4r | Local | ['_#4r]
+| '?0 | Global | ['?2, '?1, '?0, '?4, '?3]
+| '?1 | Local | ['?1, '?4]
+| '?2 | Local | ['?2, '?1, '?4]
+| '?3 | Local | ['?4, '?3]
+| '?4 | Local | ['?4]
 |
 | Inferred Region Values
-| '_#0r | U0 | {bb0[0..=1], '_#0r, '_#1r, '_#2r, '_#3r, '_#4r}
-| '_#1r | U0 | {bb0[0..=1], '_#1r}
-| '_#2r | U0 | {bb0[0..=1], '_#2r}
-| '_#3r | U0 | {bb0[0..=1], '_#3r}
-| '_#4r | U0 | {bb0[0..=1], '_#4r}
-| '_#5r | U0 | {bb0[0..=1], '_#1r}
-| '_#6r | U0 | {bb0[0..=1], '_#2r}
-| '_#7r | U0 | {bb0[0..=1], '_#1r}
-| '_#8r | U0 | {bb0[0..=1], '_#3r}
+| '?0 | U0 | {bb0[0..=1], '?0, '?1, '?2, '?3, '?4}
+| '?1 | U0 | {bb0[0..=1], '?1}
+| '?2 | U0 | {bb0[0..=1], '?2}
+| '?3 | U0 | {bb0[0..=1], '?3}
+| '?4 | U0 | {bb0[0..=1], '?4}
+| '?5 | U0 | {bb0[0..=1], '?1}
+| '?6 | U0 | {bb0[0..=1], '?2}
+| '?7 | U0 | {bb0[0..=1], '?1}
+| '?8 | U0 | {bb0[0..=1], '?3}
 |
 | Inference Constraints
-| '_#0r live at {bb0[0..=1]}
-| '_#1r live at {bb0[0..=1]}
-| '_#2r live at {bb0[0..=1]}
-| '_#3r live at {bb0[0..=1]}
-| '_#4r live at {bb0[0..=1]}
-| '_#1r: '_#5r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:26: 12:27) ($DIR/named_lifetimes_basic.rs:12:26: 12:27 (#0)
-| '_#1r: '_#7r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:54: 12:55) ($DIR/named_lifetimes_basic.rs:12:54: 12:55 (#0)
-| '_#2r: '_#6r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:42: 12:43) ($DIR/named_lifetimes_basic.rs:12:42: 12:43 (#0)
-| '_#3r: '_#8r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:66: 12:67) ($DIR/named_lifetimes_basic.rs:12:66: 12:67 (#0)
-| '_#5r: '_#1r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:26: 12:27) ($DIR/named_lifetimes_basic.rs:12:26: 12:27 (#0)
-| '_#6r: '_#2r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:42: 12:43) ($DIR/named_lifetimes_basic.rs:12:42: 12:43 (#0)
-| '_#7r: '_#1r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:54: 12:55) ($DIR/named_lifetimes_basic.rs:12:54: 12:55 (#0)
-| '_#8r: '_#3r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:66: 12:67) ($DIR/named_lifetimes_basic.rs:12:66: 12:67 (#0)
+| '?0 live at {bb0[0..=1]}
+| '?1 live at {bb0[0..=1]}
+| '?2 live at {bb0[0..=1]}
+| '?3 live at {bb0[0..=1]}
+| '?4 live at {bb0[0..=1]}
+| '?1: '?5 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:26: 12:27) ($DIR/named_lifetimes_basic.rs:12:26: 12:27 (#0)
+| '?1: '?7 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:54: 12:55) ($DIR/named_lifetimes_basic.rs:12:54: 12:55 (#0)
+| '?2: '?6 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:42: 12:43) ($DIR/named_lifetimes_basic.rs:12:42: 12:43 (#0)
+| '?3: '?8 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:66: 12:67) ($DIR/named_lifetimes_basic.rs:12:66: 12:67 (#0)
+| '?5: '?1 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:26: 12:27) ($DIR/named_lifetimes_basic.rs:12:26: 12:27 (#0)
+| '?6: '?2 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:42: 12:43) ($DIR/named_lifetimes_basic.rs:12:42: 12:43 (#0)
+| '?7: '?1 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:54: 12:55) ($DIR/named_lifetimes_basic.rs:12:54: 12:55 (#0)
+| '?8: '?3 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:66: 12:67) ($DIR/named_lifetimes_basic.rs:12:66: 12:67 (#0)
 |
-fn use_x(_1: &'_#5r mut i32, _2: &'_#6r u32, _3: &'_#7r u32, _4: &'_#8r u32) -> bool {
+fn use_x(_1: &'?5 mut i32, _2: &'?6 u32, _3: &'?7 u32, _4: &'?8 u32) -> bool {
     debug w => _1;                       // in scope 0 at $DIR/named_lifetimes_basic.rs:+0:26: +0:27
     debug x => _2;                       // in scope 0 at $DIR/named_lifetimes_basic.rs:+0:42: +0:43
     debug y => _3;                       // in scope 0 at $DIR/named_lifetimes_basic.rs:+0:54: +0:55
diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
index 798e45df8ca..71bdfcc5c49 100644
--- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
+++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
@@ -1,24 +1,24 @@
 // MIR for `main` 0 nll
 
 | Free Region Mapping
-| '_#0r | Global | ['_#0r, '_#1r]
-| '_#1r | Local | ['_#1r]
+| '?0 | Global | ['?0, '?1]
+| '?1 | Local | ['?1]
 |
 | Inferred Region Values
-| '_#0r | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '_#0r, '_#1r}
-| '_#1r | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '_#1r}
-| '_#2r | U0 | {bb1[0..=7], bb2[0..=2]}
-| '_#3r | U0 | {bb1[1..=7], bb2[0..=2]}
-| '_#4r | U0 | {bb1[4..=7], bb2[0..=2]}
+| '?0 | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '?0, '?1}
+| '?1 | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '?1}
+| '?2 | U0 | {bb1[0..=7], bb2[0..=2]}
+| '?3 | U0 | {bb1[1..=7], bb2[0..=2]}
+| '?4 | U0 | {bb1[4..=7], bb2[0..=2]}
 |
 | Inference Constraints
-| '_#0r live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]}
-| '_#1r live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]}
-| '_#2r live at {bb1[0]}
-| '_#3r live at {bb1[1..=3]}
-| '_#4r live at {bb1[4..=7], bb2[0..=2]}
-| '_#2r: '_#3r due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:18:13: 18:18 (#0)
-| '_#3r: '_#4r due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:19:13: 19:14 (#0)
+| '?0 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]}
+| '?1 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]}
+| '?2 live at {bb1[0]}
+| '?3 live at {bb1[1..=3]}
+| '?4 live at {bb1[4..=7], bb2[0..=2]}
+| '?2: '?3 due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:18:13: 18:18 (#0)
+| '?3: '?4 due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:19:13: 19:14 (#0)
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/region_subtyping_basic.rs:+0:11: +0:11
@@ -32,10 +32,10 @@ fn main() -> () {
     let _10: bool;                       // in scope 0 at $DIR/region_subtyping_basic.rs:+7:9: +7:18
     scope 1 {
         debug v => _1;                   // in scope 1 at $DIR/region_subtyping_basic.rs:+1:9: +1:14
-        let _2: &'_#3r usize;            // in scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10
+        let _2: &'?3 usize;              // in scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10
         scope 2 {
             debug p => _2;               // in scope 2 at $DIR/region_subtyping_basic.rs:+2:9: +2:10
-            let _6: &'_#4r usize;        // in scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
+            let _6: &'?4 usize;          // in scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
             scope 3 {
                 debug q => _6;           // in scope 3 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
             }
@@ -55,7 +55,7 @@ fn main() -> () {
     }
 
     bb1: {
-        _2 = &'_#2r _1[_3];              // bb1[0]: scope 1 at $DIR/region_subtyping_basic.rs:+2:13: +2:18
+        _2 = &'?2 _1[_3];                // bb1[0]: scope 1 at $DIR/region_subtyping_basic.rs:+2:13: +2:18
         FakeRead(ForLet(None), _2);      // bb1[1]: scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10
         StorageLive(_6);                 // bb1[2]: scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
         _6 = _2;                         // bb1[3]: scope 2 at $DIR/region_subtyping_basic.rs:+3:13: +3:14
diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
index 4767bfc76ed..9fa8609b751 100644
--- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
+++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
@@ -1,24 +1,24 @@
 // MIR for `main` 0 nll
 
 | Free Region Mapping
-| '_#0r | Global | ['_#0r, '_#1r]
-| '_#1r | Local | ['_#1r]
+| '?0 | Global | ['?0, '?1]
+| '?1 | Local | ['?1]
 |
 | Inferred Region Values
-| '_#0r | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '_#0r, '_#1r}
-| '_#1r | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '_#1r}
-| '_#2r | U0 | {bb1[0..=7], bb2[0..=2]}
-| '_#3r | U0 | {bb1[1..=7], bb2[0..=2]}
-| '_#4r | U0 | {bb1[4..=7], bb2[0..=2]}
+| '?0 | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '?0, '?1}
+| '?1 | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '?1}
+| '?2 | U0 | {bb1[0..=7], bb2[0..=2]}
+| '?3 | U0 | {bb1[1..=7], bb2[0..=2]}
+| '?4 | U0 | {bb1[4..=7], bb2[0..=2]}
 |
 | Inference Constraints
-| '_#0r live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]}
-| '_#1r live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]}
-| '_#2r live at {bb1[0]}
-| '_#3r live at {bb1[1..=3]}
-| '_#4r live at {bb1[4..=7], bb2[0..=2]}
-| '_#2r: '_#3r due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:18:13: 18:18 (#0)
-| '_#3r: '_#4r due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:19:13: 19:14 (#0)
+| '?0 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]}
+| '?1 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]}
+| '?2 live at {bb1[0]}
+| '?3 live at {bb1[1..=3]}
+| '?4 live at {bb1[4..=7], bb2[0..=2]}
+| '?2: '?3 due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:18:13: 18:18 (#0)
+| '?3: '?4 due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:19:13: 19:14 (#0)
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/region_subtyping_basic.rs:+0:11: +0:11
@@ -32,10 +32,10 @@ fn main() -> () {
     let _10: bool;                       // in scope 0 at $DIR/region_subtyping_basic.rs:+7:9: +7:18
     scope 1 {
         debug v => _1;                   // in scope 1 at $DIR/region_subtyping_basic.rs:+1:9: +1:14
-        let _2: &'_#3r usize;            // in scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10
+        let _2: &'?3 usize;              // in scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10
         scope 2 {
             debug p => _2;               // in scope 2 at $DIR/region_subtyping_basic.rs:+2:9: +2:10
-            let _6: &'_#4r usize;        // in scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
+            let _6: &'?4 usize;          // in scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
             scope 3 {
                 debug q => _6;           // in scope 3 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
             }
@@ -55,7 +55,7 @@ fn main() -> () {
     }
 
     bb1: {
-        _2 = &'_#2r _1[_3];              // bb1[0]: scope 1 at $DIR/region_subtyping_basic.rs:+2:13: +2:18
+        _2 = &'?2 _1[_3];                // bb1[0]: scope 1 at $DIR/region_subtyping_basic.rs:+2:13: +2:18
         FakeRead(ForLet(None), _2);      // bb1[1]: scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10
         StorageLive(_6);                 // bb1[2]: scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
         _6 = _2;                         // bb1[3]: scope 2 at $DIR/region_subtyping_basic.rs:+3:13: +3:14
diff --git a/tests/mir-opt/storage_ranges.main.nll.0.mir b/tests/mir-opt/storage_ranges.main.nll.0.mir
index 8e10e70f192..5bb1a7bf0c9 100644
--- a/tests/mir-opt/storage_ranges.main.nll.0.mir
+++ b/tests/mir-opt/storage_ranges.main.nll.0.mir
@@ -1,21 +1,21 @@
 // MIR for `main` 0 nll
 
 | Free Region Mapping
-| '_#0r | Global | ['_#0r, '_#1r]
-| '_#1r | Local | ['_#1r]
+| '?0 | Global | ['?0, '?1]
+| '?1 | Local | ['?1]
 |
 | Inferred Region Values
-| '_#0r | U0 | {bb0[0..=22], '_#0r, '_#1r}
-| '_#1r | U0 | {bb0[0..=22], '_#1r}
-| '_#2r | U0 | {bb0[10..=11]}
-| '_#3r | U0 | {bb0[11]}
+| '?0 | U0 | {bb0[0..=22], '?0, '?1}
+| '?1 | U0 | {bb0[0..=22], '?1}
+| '?2 | U0 | {bb0[10..=11]}
+| '?3 | U0 | {bb0[11]}
 |
 | Inference Constraints
-| '_#0r live at {bb0[0..=22]}
-| '_#1r live at {bb0[0..=22]}
-| '_#2r live at {bb0[10]}
-| '_#3r live at {bb0[11]}
-| '_#2r: '_#3r due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:6:17: 6:25 (#0)
+| '?0 live at {bb0[0..=22]}
+| '?1 live at {bb0[0..=22]}
+| '?2 live at {bb0[10]}
+| '?3 live at {bb0[11]}
+| '?2: '?3 due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:6:17: 6:25 (#0)
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/storage_ranges.rs:+0:11: +0:11
diff --git a/tests/run-make/coverage-reports/expected_show_coverage.issue-84561.txt b/tests/run-make/coverage-reports/expected_show_coverage.issue-84561.txt
index 9c3192c008c..4a60432c14c 100644
--- a/tests/run-make/coverage-reports/expected_show_coverage.issue-84561.txt
+++ b/tests/run-make/coverage-reports/expected_show_coverage.issue-84561.txt
@@ -136,10 +136,10 @@
   134|       |
   135|       |impl std::fmt::Debug for Foo {
   136|       |    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
-  137|      9|        write!(f, "try and succeed")?;
+  137|      7|        write!(f, "try and succeed")?;
                                                   ^0
-  138|      9|        Ok(())
-  139|      9|    }
+  138|      7|        Ok(())
+  139|      7|    }
   140|       |}
   141|       |
   142|       |static mut DEBUG_LEVEL_ENABLED: bool = false;
diff --git a/tests/run-make/issue-51671/Makefile b/tests/run-make/issue-51671/Makefile
index 00cf9134662..c9364536992 100644
--- a/tests/run-make/issue-51671/Makefile
+++ b/tests/run-make/issue-51671/Makefile
@@ -6,3 +6,4 @@ all:
 	$(RUSTC) --emit=obj app.rs
 	nm $(TMPDIR)/app.o | $(CGREP) rust_begin_unwind
 	nm $(TMPDIR)/app.o | $(CGREP) rust_eh_personality
+	nm $(TMPDIR)/app.o | $(CGREP) __rg_oom
diff --git a/tests/run-make/issue-51671/app.rs b/tests/run-make/issue-51671/app.rs
index a9d3457bf90..e9dc1e9744f 100644
--- a/tests/run-make/issue-51671/app.rs
+++ b/tests/run-make/issue-51671/app.rs
@@ -1,5 +1,5 @@
 #![crate_type = "bin"]
-#![feature(lang_items)]
+#![feature(lang_items, alloc_error_handler)]
 #![no_main]
 #![no_std]
 
@@ -13,3 +13,8 @@ fn panic(_: &PanicInfo) -> ! {
 
 #[lang = "eh_personality"]
 fn eh() {}
+
+#[alloc_error_handler]
+fn oom(_: Layout) -> ! {
+    loop {}
+}
diff --git a/tests/run-make/issue-69368/Makefile b/tests/run-make/issue-69368/Makefile
new file mode 100644
index 00000000000..b1229d1b07f
--- /dev/null
+++ b/tests/run-make/issue-69368/Makefile
@@ -0,0 +1,19 @@
+# ignore-cross-compile
+include ../tools.mk
+
+# Test that previously triggered a linker failure with root cause
+# similar to one found in the issue #69368.
+#
+# The crate that provides oom lang item is missing some other lang
+# items. Necessary to prevent the use of start-group / end-group.
+#
+# The weak lang items are defined in a separate compilation units,
+# so that linker could omit them if not used.
+#
+# The crates that need those weak lang items are dependencies of
+# crates that provide them.
+
+all:
+	$(RUSTC) a.rs
+	$(RUSTC) b.rs
+	$(RUSTC) c.rs
diff --git a/tests/run-make/issue-69368/a.rs b/tests/run-make/issue-69368/a.rs
new file mode 100644
index 00000000000..a54f429550e
--- /dev/null
+++ b/tests/run-make/issue-69368/a.rs
@@ -0,0 +1,26 @@
+#![crate_type = "rlib"]
+#![feature(lang_items)]
+#![feature(panic_unwind)]
+#![no_std]
+
+extern crate panic_unwind;
+
+#[panic_handler]
+pub fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+#[no_mangle]
+extern "C" fn __rust_drop_panic() -> ! {
+    loop {}
+}
+
+#[no_mangle]
+extern "C" fn __rust_foreign_exception() -> ! {
+    loop {}
+}
+
+#[lang = "eh_personality"]
+fn eh_personality() {
+    loop {}
+}
diff --git a/tests/run-make/issue-69368/b.rs b/tests/run-make/issue-69368/b.rs
new file mode 100644
index 00000000000..4d6af026656
--- /dev/null
+++ b/tests/run-make/issue-69368/b.rs
@@ -0,0 +1,8 @@
+#![crate_type = "rlib"]
+#![feature(alloc_error_handler)]
+#![no_std]
+
+#[alloc_error_handler]
+pub fn error_handler(_: core::alloc::Layout) -> ! {
+    panic!();
+}
diff --git a/tests/run-make/issue-69368/c.rs b/tests/run-make/issue-69368/c.rs
new file mode 100644
index 00000000000..729c4249a05
--- /dev/null
+++ b/tests/run-make/issue-69368/c.rs
@@ -0,0 +1,34 @@
+#![crate_type = "bin"]
+#![feature(start)]
+#![no_std]
+
+extern crate alloc;
+extern crate a;
+extern crate b;
+
+use alloc::vec::Vec;
+use core::alloc::*;
+
+struct Allocator;
+
+unsafe impl GlobalAlloc for Allocator {
+    unsafe fn alloc(&self, _: Layout) -> *mut u8 {
+        loop {}
+    }
+
+    unsafe fn dealloc(&self, _: *mut u8, _: Layout) {
+        loop {}
+    }
+}
+
+#[global_allocator]
+static ALLOCATOR: Allocator = Allocator;
+
+#[start]
+fn main(argc: isize, _argv: *const *const u8) -> isize {
+    let mut v = Vec::new();
+    for i in 0..argc {
+        v.push(i);
+    }
+    v.iter().sum()
+}
diff --git a/tests/run-make/wasm-symbols-not-exported/bar.rs b/tests/run-make/wasm-symbols-not-exported/bar.rs
index eb768446b4b..6ffbd3ec690 100644
--- a/tests/run-make/wasm-symbols-not-exported/bar.rs
+++ b/tests/run-make/wasm-symbols-not-exported/bar.rs
@@ -1,4 +1,4 @@
-#![feature(panic_handler)]
+#![feature(panic_handler, alloc_error_handler)]
 #![crate_type = "cdylib"]
 #![no_std]
 
@@ -24,6 +24,11 @@ pub extern fn foo(a: u32) -> u32 {
     a * 2
 }
 
+#[alloc_error_handler]
+fn a(_: core::alloc::Layout) -> ! {
+    loop {}
+}
+
 #[panic_handler]
 fn b(_: &core::panic::PanicInfo) -> ! {
     loop {}
diff --git a/tests/ui/alloc-error/alloc-error-handler-bad-signature-1.rs b/tests/ui/alloc-error/alloc-error-handler-bad-signature-1.rs
new file mode 100644
index 00000000000..cd06423e3a5
--- /dev/null
+++ b/tests/ui/alloc-error/alloc-error-handler-bad-signature-1.rs
@@ -0,0 +1,18 @@
+// compile-flags:-C panic=abort
+
+#![feature(alloc_error_handler)]
+#![no_std]
+#![no_main]
+
+use core::alloc::Layout;
+
+#[alloc_error_handler]
+fn oom(
+    info: &Layout, //~^ ERROR mismatched types
+) -> () //~^^ ERROR mismatched types
+{
+    loop {}
+}
+
+#[panic_handler]
+fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
diff --git a/tests/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr b/tests/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr
new file mode 100644
index 00000000000..de92841d7f1
--- /dev/null
+++ b/tests/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr
@@ -0,0 +1,44 @@
+error[E0308]: mismatched types
+  --> $DIR/alloc-error-handler-bad-signature-1.rs:10:1
+   |
+LL |    #[alloc_error_handler]
+   |    ---------------------- in this procedural macro expansion
+LL | // fn oom(
+LL | ||     info: &Layout,
+LL | || ) -> ()
+   | ||_______- arguments to this function are incorrect
+LL | |  {
+LL | |      loop {}
+LL | |  }
+   | |__^ expected `&Layout`, found `Layout`
+   |
+note: function defined here
+  --> $DIR/alloc-error-handler-bad-signature-1.rs:10:4
+   |
+LL | fn oom(
+   |    ^^^
+LL |     info: &Layout,
+   |     -------------
+   = note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> $DIR/alloc-error-handler-bad-signature-1.rs:10:1
+   |
+LL |    #[alloc_error_handler]
+   |    ---------------------- in this procedural macro expansion
+LL | // fn oom(
+LL | ||     info: &Layout,
+LL | || ) -> ()
+   | ||_______^ expected `!`, found `()`
+LL | |  {
+LL | |      loop {}
+LL | |  }
+   | |__- expected `!` because of return type
+   |
+   = note:   expected type `!`
+           found unit type `()`
+   = note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/alloc-error/alloc-error-handler-bad-signature-2.rs b/tests/ui/alloc-error/alloc-error-handler-bad-signature-2.rs
new file mode 100644
index 00000000000..4f76257fc72
--- /dev/null
+++ b/tests/ui/alloc-error/alloc-error-handler-bad-signature-2.rs
@@ -0,0 +1,17 @@
+// compile-flags:-C panic=abort
+
+#![feature(alloc_error_handler)]
+#![no_std]
+#![no_main]
+
+struct Layout;
+
+#[alloc_error_handler]
+fn oom(
+    info: Layout, //~^ ERROR mismatched types
+) { //~^^ ERROR mismatched types
+    loop {}
+}
+
+#[panic_handler]
+fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
diff --git a/tests/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr b/tests/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr
new file mode 100644
index 00000000000..7a495380f2b
--- /dev/null
+++ b/tests/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr
@@ -0,0 +1,50 @@
+error[E0308]: mismatched types
+  --> $DIR/alloc-error-handler-bad-signature-2.rs:10:1
+   |
+LL |    #[alloc_error_handler]
+   |    ---------------------- in this procedural macro expansion
+LL | // fn oom(
+LL | ||     info: Layout,
+LL | || ) {
+   | ||_- arguments to this function are incorrect
+LL | |      loop {}
+LL | |  }
+   | |__^ expected `Layout`, found `core::alloc::Layout`
+   |
+   = note: `core::alloc::Layout` and `Layout` have similar names, but are actually distinct types
+note: `core::alloc::Layout` is defined in crate `core`
+  --> $SRC_DIR/core/src/alloc/layout.rs:LL:COL
+note: `Layout` is defined in the current crate
+  --> $DIR/alloc-error-handler-bad-signature-2.rs:7:1
+   |
+LL | struct Layout;
+   | ^^^^^^^^^^^^^
+note: function defined here
+  --> $DIR/alloc-error-handler-bad-signature-2.rs:10:4
+   |
+LL | fn oom(
+   |    ^^^
+LL |     info: Layout,
+   |     ------------
+   = note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> $DIR/alloc-error-handler-bad-signature-2.rs:10:1
+   |
+LL |    #[alloc_error_handler]
+   |    ---------------------- in this procedural macro expansion
+LL | // fn oom(
+LL | ||     info: Layout,
+LL | || ) {
+   | ||_^ expected `!`, found `()`
+LL | |      loop {}
+LL | |  }
+   | |__- expected `!` because of return type
+   |
+   = note:   expected type `!`
+           found unit type `()`
+   = note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/alloc-error/alloc-error-handler-bad-signature-3.rs b/tests/ui/alloc-error/alloc-error-handler-bad-signature-3.rs
new file mode 100644
index 00000000000..ea9ad39a70d
--- /dev/null
+++ b/tests/ui/alloc-error/alloc-error-handler-bad-signature-3.rs
@@ -0,0 +1,15 @@
+// compile-flags:-C panic=abort
+
+#![feature(alloc_error_handler)]
+#![no_std]
+#![no_main]
+
+struct Layout;
+
+#[alloc_error_handler]
+fn oom() -> ! { //~ ERROR function takes 0 arguments but 1 argument was supplied
+    loop {}
+}
+
+#[panic_handler]
+fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
diff --git a/tests/ui/alloc-error/alloc-error-handler-bad-signature-3.stderr b/tests/ui/alloc-error/alloc-error-handler-bad-signature-3.stderr
new file mode 100644
index 00000000000..eb739b149a1
--- /dev/null
+++ b/tests/ui/alloc-error/alloc-error-handler-bad-signature-3.stderr
@@ -0,0 +1,21 @@
+error[E0061]: this function takes 0 arguments but 1 argument was supplied
+  --> $DIR/alloc-error-handler-bad-signature-3.rs:10:1
+   |
+LL |   #[alloc_error_handler]
+   |   ---------------------- in this procedural macro expansion
+LL |   fn oom() -> ! {
+   |  _-^^^^^^^^^^^^
+LL | |     loop {}
+LL | | }
+   | |_- unexpected argument of type `core::alloc::Layout`
+   |
+note: function defined here
+  --> $DIR/alloc-error-handler-bad-signature-3.rs:10:4
+   |
+LL | fn oom() -> ! {
+   |    ^^^
+   = note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0061`.
diff --git a/tests/ui/alloc-error/default-alloc-error-hook.rs b/tests/ui/alloc-error/default-alloc-error-hook.rs
index 919d4b714a1..8be09500f4e 100644
--- a/tests/ui/alloc-error/default-alloc-error-hook.rs
+++ b/tests/ui/alloc-error/default-alloc-error-hook.rs
@@ -2,7 +2,7 @@
 // ignore-emscripten no processes
 // ignore-sgx no processes
 
-use std::alloc::{handle_alloc_error, Layout};
+use std::alloc::{Layout, handle_alloc_error};
 use std::env;
 use std::process::Command;
 use std::str;
@@ -24,5 +24,5 @@ fn main() {
         .strip_suffix("qemu: uncaught target signal 6 (Aborted) - core dumped\n")
         .unwrap_or(stderr);
 
-    assert!(stderr.contains("memory allocation of 42 bytes failed"));
+    assert_eq!(stderr, "memory allocation of 42 bytes failed\n");
 }
diff --git a/tests/ui/allocator/no_std-alloc-error-handler-custom.rs b/tests/ui/allocator/no_std-alloc-error-handler-custom.rs
new file mode 100644
index 00000000000..28926243390
--- /dev/null
+++ b/tests/ui/allocator/no_std-alloc-error-handler-custom.rs
@@ -0,0 +1,84 @@
+// run-pass
+// ignore-android no libc
+// ignore-emscripten no libc
+// ignore-sgx no libc
+// ignore-wasm32 no libc
+// only-linux
+// compile-flags:-C panic=abort
+// aux-build:helper.rs
+
+#![feature(rustc_private, lang_items)]
+#![feature(alloc_error_handler)]
+#![no_std]
+#![no_main]
+
+extern crate alloc;
+extern crate libc;
+
+// ARM targets need these symbols
+#[no_mangle]
+pub fn __aeabi_unwind_cpp_pr0() {}
+
+#[no_mangle]
+pub fn __aeabi_unwind_cpp_pr1() {}
+
+use alloc::boxed::Box;
+use alloc::string::ToString;
+use core::alloc::{GlobalAlloc, Layout};
+use core::ptr::null_mut;
+
+extern crate helper;
+
+struct MyAllocator;
+
+#[alloc_error_handler]
+fn my_oom(layout: Layout) -> ! {
+    use alloc::fmt::write;
+    unsafe {
+        let size = layout.size();
+        let mut s = alloc::string::String::new();
+        write(&mut s, format_args!("My OOM: failed to allocate {} bytes!\n", size)).unwrap();
+        libc::write(libc::STDERR_FILENO, s.as_ptr() as *const _, s.len());
+        libc::exit(0)
+    }
+}
+
+unsafe impl GlobalAlloc for MyAllocator {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        if layout.size() < 4096 { libc::malloc(layout.size()) as _ } else { null_mut() }
+    }
+    unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
+}
+
+#[global_allocator]
+static A: MyAllocator = MyAllocator;
+
+#[panic_handler]
+fn panic(panic_info: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        let s = panic_info.to_string();
+        const PSTR: &str = "panic occurred: ";
+        const CR: &str = "\n";
+        libc::write(libc::STDERR_FILENO, PSTR.as_ptr() as *const _, PSTR.len());
+        libc::write(libc::STDERR_FILENO, s.as_ptr() as *const _, s.len());
+        libc::write(libc::STDERR_FILENO, CR.as_ptr() as *const _, CR.len());
+        libc::exit(1)
+    }
+}
+
+// Because we are compiling this code with `-C panic=abort`, this wouldn't normally be needed.
+// However, `core` and `alloc` are both compiled with `-C panic=unwind`, which means that functions
+// in these libraries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't
+// unwind. So, for this test case we will define the symbol.
+#[lang = "eh_personality"]
+extern "C" fn rust_eh_personality() {}
+
+#[derive(Default, Debug)]
+struct Page(#[allow(unused_tuple_struct_fields)] [[u64; 32]; 16]);
+
+#[no_mangle]
+fn main(_argc: i32, _argv: *const *const u8) -> isize {
+    let zero = Box::<Page>::new(Default::default());
+    helper::work_with(&zero);
+    1
+}
diff --git a/tests/ui/associated-types/substs-ppaux.verbose.stderr b/tests/ui/associated-types/substs-ppaux.verbose.stderr
index e4f6ba573ca..ad67899e6da 100644
--- a/tests/ui/associated-types/substs-ppaux.verbose.stderr
+++ b/tests/ui/associated-types/substs-ppaux.verbose.stderr
@@ -77,7 +77,7 @@ LL |     <str as Foo<u8>>::bar;
    |     ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `str`
-note: required for `str` to implement `Foo<'_#0r, '_#1r, u8>`
+note: required for `str` to implement `Foo<'?0, '?1, u8>`
   --> $DIR/substs-ppaux.rs:11:17
    |
 LL | impl<'a,'b,T,S> Foo<'a, 'b, S> for T {}
diff --git a/tests/ui/closures/binder/nested-closures-regions.stderr b/tests/ui/closures/binder/nested-closures-regions.stderr
index b385e0ed6e0..381aadb1564 100644
--- a/tests/ui/closures/binder/nested-closures-regions.stderr
+++ b/tests/ui/closures/binder/nested-closures-regions.stderr
@@ -9,11 +9,11 @@ LL |     for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; };
                extern "rust-call" fn((&(),)),
                (),
            ]
-   = note: late-bound region is '_#4r
-   = note: late-bound region is '_#2r
+   = note: late-bound region is '?4
+   = note: late-bound region is '?2
    = note: number of external vids: 3
-   = note: where '_#1r: '_#2r
-   = note: where '_#2r: '_#1r
+   = note: where '?1: '?2
+   = note: where '?2: '?1
 
 note: no external requirements
   --> $DIR/nested-closures-regions.rs:8:5
@@ -26,7 +26,7 @@ LL |     for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; };
                extern "rust-call" fn(()),
                (),
            ]
-   = note: late-bound region is '_#2r
+   = note: late-bound region is '?2
 
 note: no external requirements
   --> $DIR/nested-closures-regions.rs:7:1
diff --git a/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr
index ff89dd34034..381bb0c084a 100644
--- a/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr
+++ b/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr
@@ -9,7 +9,7 @@ LL |         let c1 : () = c;
    |                  expected due to this
    |
    = note: expected unit type `()`
-                found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#16t, extern "rust-call" fn(()), _#15t]]`
+                found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, ?16t, extern "rust-call" fn(()), ?15t]]`
 help: use parentheses to call this closure
    |
 LL |         let c1 : () = c();
diff --git a/tests/ui/closures/print/closure-print-generic-verbose-1.stderr b/tests/ui/closures/print/closure-print-generic-verbose-1.stderr
index 3ab7c66d11f..9a1f18fa855 100644
--- a/tests/ui/closures/print/closure-print-generic-verbose-1.stderr
+++ b/tests/ui/closures/print/closure-print-generic-verbose-1.stderr
@@ -2,7 +2,7 @@ error[E0382]: use of moved value: `c`
   --> $DIR/closure-print-generic-verbose-1.rs:17:5
    |
 LL |     let c = to_fn_once(move|| {
-   |         - move occurs because `c` has type `[f<T>::{closure#0} closure_kind_ty=i32 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=(Foo<&'_#9r str>, T)]`, which does not implement the `Copy` trait
+   |         - move occurs because `c` has type `[f<T>::{closure#0} closure_kind_ty=i32 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=(Foo<&'?9 str>, T)]`, which does not implement the `Copy` trait
 ...
 LL |     c();
    |     --- `c` moved due to this call
diff --git a/tests/ui/closures/print/closure-print-generic-verbose-2.stderr b/tests/ui/closures/print/closure-print-generic-verbose-2.stderr
index 5bbf84f963d..2a4d16c48dc 100644
--- a/tests/ui/closures/print/closure-print-generic-verbose-2.stderr
+++ b/tests/ui/closures/print/closure-print-generic-verbose-2.stderr
@@ -9,7 +9,7 @@ LL |         let c1 : () = c;
    |                  expected due to this
    |
    = note: expected unit type `()`
-                found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#16t, extern "rust-call" fn(()), _#15t]]`
+                found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, ?16t, extern "rust-call" fn(()), ?15t]]`
 help: use parentheses to call this closure
    |
 LL |         let c1 : () = c();
diff --git a/tests/ui/closures/print/closure-print-verbose.stderr b/tests/ui/closures/print/closure-print-verbose.stderr
index 083717b3334..9e219435e5c 100644
--- a/tests/ui/closures/print/closure-print-verbose.stderr
+++ b/tests/ui/closures/print/closure-print-verbose.stderr
@@ -7,7 +7,7 @@ LL |     let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
    |              expected due to this
    |
    = note: expected fn pointer `fn(u8) -> u8`
-                 found closure `[main::{closure#0} closure_substs=(unavailable) substs=[i8, extern "rust-call" fn((u8,)) -> u8, _#6t]]`
+                 found closure `[main::{closure#0} closure_substs=(unavailable) substs=[i8, extern "rust-call" fn((u8,)) -> u8, ?6t]]`
 note: closures can only be coerced to `fn` types if they do not capture any variables
   --> $DIR/closure-print-verbose.rs:10:39
    |
diff --git a/tests/ui/const-generics/occurs-check/unused-substs-2.rs b/tests/ui/const-generics/occurs-check/unused-substs-2.rs
index 9b1212694f5..84e24d1a3f5 100644
--- a/tests/ui/const-generics/occurs-check/unused-substs-2.rs
+++ b/tests/ui/const-generics/occurs-check/unused-substs-2.rs
@@ -1,9 +1,9 @@
 #![feature(generic_const_exprs)]
 #![allow(incomplete_features)]
 
-// The goal is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(_#1t)` subst.
+// The goal is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(?1t)` subst.
 //
-// If we are then able to infer `ty::Infer(TyVar(_#1t) := Ty<ct>` we introduced an
+// If we are then able to infer `ty::Infer(TyVar(?1t) := Ty<ct>` we introduced an
 // artificial inference cycle.
 struct Foo<const N: usize>;
 
@@ -20,8 +20,8 @@ impl<T> Bind<T> for Foo<{ 6 + 1 }> {
 
 fn main() {
     let (mut t, foo) = Foo::bind();
-    // `t` is `ty::Infer(TyVar(_#1t))`
-    // `foo` contains `ty::Infer(TyVar(_#1t))` in its substs
+    // `t` is `ty::Infer(TyVar(?1t))`
+    // `foo` contains `ty::Infer(TyVar(?1t))` in its substs
     t = foo;
     //~^ ERROR mismatched types
     //~| NOTE cyclic type
diff --git a/tests/ui/const-generics/occurs-check/unused-substs-3.rs b/tests/ui/const-generics/occurs-check/unused-substs-3.rs
index d5aeab47e62..6db18d587d3 100644
--- a/tests/ui/const-generics/occurs-check/unused-substs-3.rs
+++ b/tests/ui/const-generics/occurs-check/unused-substs-3.rs
@@ -1,9 +1,9 @@
 #![feature(generic_const_exprs)]
 #![allow(incomplete_features)]
 
-// The goal is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(_#1t)` subst.
+// The goal is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(?1t)` subst.
 //
-// If we are then able to infer `ty::Infer(TyVar(_#1t) := Ty<ct>` we introduced an
+// If we are then able to infer `ty::Infer(TyVar(?1t) := Ty<ct>` we introduced an
 // artificial inference cycle.
 fn bind<T>() -> (T, [u8; 6 + 1]) {
     todo!()
@@ -11,8 +11,8 @@ fn bind<T>() -> (T, [u8; 6 + 1]) {
 
 fn main() {
     let (mut t, foo) = bind();
-    // `t` is `ty::Infer(TyVar(_#1t))`
-    // `foo` contains `ty::Infer(TyVar(_#1t))` in its substs
+    // `t` is `ty::Infer(TyVar(?1t))`
+    // `foo` contains `ty::Infer(TyVar(?1t))` in its substs
     t = foo;
     //~^ ERROR mismatched types
     //~| NOTE cyclic type
diff --git a/tests/ui/feature-gates/feature-gate-alloc-error-handler.rs b/tests/ui/feature-gates/feature-gate-alloc-error-handler.rs
new file mode 100644
index 00000000000..78d189d20b6
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-alloc-error-handler.rs
@@ -0,0 +1,16 @@
+// compile-flags:-C panic=abort
+
+#![no_std]
+#![no_main]
+
+use core::alloc::Layout;
+
+#[alloc_error_handler] //~ ERROR use of unstable library feature 'alloc_error_handler'
+fn oom(info: Layout) -> ! {
+    loop {}
+}
+
+#[panic_handler]
+fn panic(_: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
diff --git a/tests/ui/feature-gates/feature-gate-alloc-error-handler.stderr b/tests/ui/feature-gates/feature-gate-alloc-error-handler.stderr
new file mode 100644
index 00000000000..f414eb463df
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-alloc-error-handler.stderr
@@ -0,0 +1,12 @@
+error[E0658]: use of unstable library feature 'alloc_error_handler'
+  --> $DIR/feature-gate-alloc-error-handler.rs:8:3
+   |
+LL | #[alloc_error_handler]
+   |   ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #51540 <https://github.com/rust-lang/rust/issues/51540> for more information
+   = help: add `#![feature(alloc_error_handler)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/generator/issue-57084.rs b/tests/ui/generator/issue-57084.rs
index 2a5c3dd0570..fbed78ff280 100644
--- a/tests/ui/generator/issue-57084.rs
+++ b/tests/ui/generator/issue-57084.rs
@@ -1,5 +1,5 @@
 // This issue reproduces an ICE on compile (E.g. fails on 2018-12-19 nightly).
-// "cannot relate bound region: ReLateBound(DebruijnIndex(1), BrAnon(1)) <= '_#1r"
+// "cannot relate bound region: ReLateBound(DebruijnIndex(1), BrAnon(1)) <= '?1"
 // run-pass
 // edition:2018
 #![feature(generators,generator_trait)]
diff --git a/tests/ui/impl-trait/wf-eval-order.rs b/tests/ui/impl-trait/wf-eval-order.rs
index c7d6bb87096..8638fc2e775 100644
--- a/tests/ui/impl-trait/wf-eval-order.rs
+++ b/tests/ui/impl-trait/wf-eval-order.rs
@@ -31,9 +31,9 @@ fn main() {
     //
     // - `wf(typeof(x))` because we use a projection candidate.
     // - `<i32 as B>::V: Clone` because that's a bound on the trait.
-    // - `<i32 as B>::V` normalizes to `_#1` where `<i32 as A>::U == _#1`
+    // - `<i32 as B>::V` normalizes to `?1t` where `<i32 as A>::U == ?1t`
     //
-    // This all works if we evaluate `<i32 as A>::U == _#1` before
+    // This all works if we evaluate `<i32 as A>::U == ?1t` before
     // `<i32 as B>::V`, but we previously had the opposite order.
     let x = hide(X(0));
 }
diff --git a/tests/ui/missing/missing-allocator.rs b/tests/ui/missing/missing-allocator.rs
index e06e603e3bf..2dc509f2c63 100644
--- a/tests/ui/missing/missing-allocator.rs
+++ b/tests/ui/missing/missing-allocator.rs
@@ -3,10 +3,16 @@
 
 #![no_std]
 #![crate_type = "staticlib"]
+#![feature(alloc_error_handler)]
 
 #[panic_handler]
 fn panic(_: &core::panic::PanicInfo) -> ! {
     loop {}
 }
 
+#[alloc_error_handler]
+fn oom(_: core::alloc::Layout) -> ! {
+    loop {}
+}
+
 extern crate alloc;
diff --git a/tests/ui/nll/closure-requirements/escape-argument-callee.stderr b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr
index c0d95ddaa07..61233fd8407 100644
--- a/tests/ui/nll/closure-requirements/escape-argument-callee.stderr
+++ b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr
@@ -17,7 +17,7 @@ LL |         let mut closure = expect_sig(|p, y| *p = y);
    |                                       -  -  ^^^^^^ assignment requires that `'1` must outlive `'2`
    |                                       |  |
    |                                       |  has type `&'1 i32`
-   |                                       has type `&'_#2r mut &'2 i32`
+   |                                       has type `&'?2 mut &'2 i32`
 
 note: no external requirements
   --> $DIR/escape-argument-callee.rs:20:1
diff --git a/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr b/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr
index 4fbd5eb19a5..c00a31ef8e1 100644
--- a/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr
+++ b/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr
@@ -7,10 +7,10 @@ LL |             let mut closure1 = || p = &y;
    = note: defining type: test::{closure#0}::{closure#0} with closure substs [
                i16,
                extern "rust-call" fn(()),
-               (&'_#1r mut &'_#2r i32, &'_#3r i32),
+               (&'?1 mut &'?2 i32, &'?3 i32),
            ]
    = note: number of external vids: 4
-   = note: where '_#3r: '_#2r
+   = note: where '?3: '?2
 
 note: external requirements
   --> $DIR/escape-upvar-nested.rs:20:27
@@ -21,10 +21,10 @@ LL |         let mut closure = || {
    = note: defining type: test::{closure#0} with closure substs [
                i16,
                extern "rust-call" fn(()),
-               (&'_#1r mut &'_#2r i32, &'_#3r i32),
+               (&'?1 mut &'?2 i32, &'?3 i32),
            ]
    = note: number of external vids: 4
-   = note: where '_#3r: '_#2r
+   = note: where '?3: '?2
 
 note: no external requirements
   --> $DIR/escape-upvar-nested.rs:13:1
diff --git a/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr b/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr
index bc1ceac5bf0..2d67e6e7d72 100644
--- a/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr
+++ b/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr
@@ -7,10 +7,10 @@ LL |         let mut closure = || p = &y;
    = note: defining type: test::{closure#0} with closure substs [
                i16,
                extern "rust-call" fn(()),
-               (&'_#1r mut &'_#2r i32, &'_#3r i32),
+               (&'?1 mut &'?2 i32, &'?3 i32),
            ]
    = note: number of external vids: 4
-   = note: where '_#3r: '_#2r
+   = note: where '?3: '?2
 
 note: no external requirements
   --> $DIR/escape-upvar-ref.rs:17:1
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
index 5a7b12732df..ba42576d403 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
@@ -6,20 +6,20 @@ LL |         |_outlives1, _outlives2, _outlives3, x, y| {
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)),
+               for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'?1 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&'?2 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'?3 u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)),
                (),
            ]
-   = note: late-bound region is '_#4r
-   = note: late-bound region is '_#5r
-   = note: late-bound region is '_#6r
+   = note: late-bound region is '?4
+   = note: late-bound region is '?5
+   = note: late-bound region is '?6
 
 error: lifetime may not live long enough
   --> $DIR/propagate-approximated-fail-no-postdom.rs:46:13
    |
 LL |         |_outlives1, _outlives2, _outlives3, x, y| {
-   |          ----------              ---------- has type `Cell<&'2 &'_#3r u32>`
+   |          ----------              ---------- has type `Cell<&'2 &'?3 u32>`
    |          |
-   |          has type `Cell<&'_#1r &'1 u32>`
+   |          has type `Cell<&'?1 &'1 u32>`
 ...
 LL |             demand_y(x, y, p)
    |             ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr
index db2ecc779ef..9dd6e02081f 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr
@@ -6,13 +6,13 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>)),
+               for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&'?1 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) &'?2 u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>)),
                (),
            ]
-   = note: late-bound region is '_#3r
-   = note: late-bound region is '_#4r
+   = note: late-bound region is '?3
+   = note: late-bound region is '?4
    = note: number of external vids: 5
-   = note: where '_#1r: '_#2r
+   = note: where '?1: '?2
 
 note: no external requirements
   --> $DIR/propagate-approximated-ref.rs:42:1
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
index 1d9dafbe55f..e2f5576d395 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -6,7 +6,7 @@ LL |     foo(cell, |cell_a, cell_x| {
    |
    = note: defining type: case1::{closure#0} with closure substs [
                i32,
-               for<Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>)),
+               for<Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'?1 u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>)),
                (),
            ]
 
@@ -36,11 +36,11 @@ LL |     foo(cell, |cell_a, cell_x| {
    |
    = note: defining type: case2::{closure#0} with closure substs [
                i32,
-               for<Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>)),
+               for<Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'?1 u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>)),
                (),
            ]
    = note: number of external vids: 2
-   = note: where '_#1r: '_#0r
+   = note: where '?1: '?0
 
 note: no external requirements
   --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:28:1
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
index 85f7fe35c0a..383fb471ad3 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
@@ -6,13 +6,13 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) u32>)),
+               for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&'?1 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) u32>)),
                (),
            ]
-   = note: late-bound region is '_#2r
-   = note: late-bound region is '_#3r
+   = note: late-bound region is '?2
+   = note: late-bound region is '?3
    = note: number of external vids: 4
-   = note: where '_#1r: '_#0r
+   = note: where '?1: '?0
 
 note: no external requirements
   --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:31:1
@@ -40,7 +40,7 @@ LL | |     });
    | |______`cell_a` escapes the function body here
    |        argument requires that `'a` must outlive `'static`
    |
-   = note: requirement occurs because of the type `Cell<&'_#9r u32>`, which makes the generic argument `&'_#9r u32` invariant
+   = note: requirement occurs because of the type `Cell<&'?9 u32>`, which makes the generic argument `&'?9 u32` invariant
    = note: the struct `Cell<T>` is invariant over the parameter `T`
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
index 7194843e203..ac346c0b110 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
@@ -6,13 +6,13 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>)),
+               for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&'?1 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&'?2 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>)),
                (),
            ]
-   = note: late-bound region is '_#3r
-   = note: late-bound region is '_#4r
+   = note: late-bound region is '?3
+   = note: late-bound region is '?4
    = note: number of external vids: 5
-   = note: where '_#1r: '_#0r
+   = note: where '?1: '?0
 
 note: no external requirements
   --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:34:1
@@ -40,7 +40,7 @@ LL | |     });
    | |______`cell_a` escapes the function body here
    |        argument requires that `'a` must outlive `'static`
    |
-   = note: requirement occurs because of the type `Cell<&'_#10r u32>`, which makes the generic argument `&'_#10r u32` invariant
+   = note: requirement occurs because of the type `Cell<&'?10 u32>`, which makes the generic argument `&'?10 u32` invariant
    = note: the struct `Cell<T>` is invariant over the parameter `T`
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr
index 71f8a1c67c6..b217ae19773 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr
@@ -6,13 +6,13 @@ LL |     establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
-               for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)),
+               for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'?1 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'?2 u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)),
                (),
            ]
-   = note: late-bound region is '_#3r
-   = note: late-bound region is '_#4r
+   = note: late-bound region is '?3
+   = note: late-bound region is '?4
    = note: number of external vids: 5
-   = note: where '_#1r: '_#2r
+   = note: where '?1: '?2
 
 note: no external requirements
   --> $DIR/propagate-approximated-val.rs:35:1
diff --git a/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
index e1cb97b1c7d..f31478b6d1c 100644
--- a/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
@@ -6,12 +6,12 @@ LL |         |_outlives1, _outlives2, x, y| {
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)),
+               for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'?1 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'?2 u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)),
                (),
            ]
-   = note: late-bound region is '_#3r
+   = note: late-bound region is '?3
    = note: number of external vids: 4
-   = note: where '_#1r: '_#2r
+   = note: where '?1: '?2
 
 note: no external requirements
   --> $DIR/propagate-despite-same-free-region.rs:39:1
diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
index b66e8391c01..1509ade87fa 100644
--- a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
@@ -6,19 +6,19 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)),
+               for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'?1 u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)),
                (),
            ]
-   = note: late-bound region is '_#2r
-   = note: late-bound region is '_#3r
+   = note: late-bound region is '?2
+   = note: late-bound region is '?3
 
 error: lifetime may not live long enough
   --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:37:9
    |
 LL |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
-   |                                                ---------  - has type `&'_#7r Cell<&'1 u32>`
+   |                                                ---------  - has type `&'?7 Cell<&'1 u32>`
    |                                                |
-   |                                                has type `&'_#5r Cell<&'2 &'_#1r u32>`
+   |                                                has type `&'?5 Cell<&'2 &'?1 u32>`
 LL |         // Only works if 'x: 'y:
 LL |         demand_y(x, y, x.get())
    |         ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
index 49641fd06fd..c85a9872e21 100644
--- a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
@@ -6,19 +6,19 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>)),
+               for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'?1 u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) &'?2 u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>)),
                (),
            ]
-   = note: late-bound region is '_#3r
-   = note: late-bound region is '_#4r
+   = note: late-bound region is '?3
+   = note: late-bound region is '?4
 
 error: lifetime may not live long enough
   --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:41:9
    |
 LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
-   |                                                ----------  ---------- has type `&'_#8r Cell<&'2 &'_#2r u32>`
+   |                                                ----------  ---------- has type `&'?8 Cell<&'2 &'?2 u32>`
    |                                                |
-   |                                                has type `&'_#6r Cell<&'1 &'_#1r u32>`
+   |                                                has type `&'?6 Cell<&'1 &'?1 u32>`
 LL |         // Only works if 'x: 'y:
 LL |         demand_y(x, y, x.get())
    |         ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
diff --git a/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr
index 038a5e11f88..05e274ab220 100644
--- a/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr
@@ -4,13 +4,13 @@ note: external requirements
 LL |     establish_relationships(value, |value| {
    |                                    ^^^^^^^
    |
-   = note: defining type: supply::<'_#1r, T>::{closure#0} with closure substs [
+   = note: defining type: supply::<'?1, T>::{closure#0} with closure substs [
                i32,
                extern "rust-call" fn((T,)),
                (),
            ]
    = note: number of external vids: 2
-   = note: where T: '_#1r
+   = note: where T: '?1
 
 note: no external requirements
   --> $DIR/propagate-from-trait-match.rs:28:1
@@ -20,7 +20,7 @@ LL | | where
 LL | |     T: Trait<'a>,
    | |_________________^
    |
-   = note: defining type: supply::<'_#1r, T>
+   = note: defining type: supply::<'?1, T>
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/propagate-from-trait-match.rs:43:9
diff --git a/tests/ui/nll/member-constraints/min-choice.rs b/tests/ui/nll/member-constraints/min-choice.rs
index 14b4dae7abf..f4aca69e19f 100644
--- a/tests/ui/nll/member-constraints/min-choice.rs
+++ b/tests/ui/nll/member-constraints/min-choice.rs
@@ -1,5 +1,5 @@
-// Assuming that the hidden type in these tests is `&'_#15r u8`,
-// we have a member constraint: `'_#15r member ['static, 'a, 'b, 'c]`.
+// Assuming that the hidden type in these tests is `&'?15 u8`,
+// we have a member constraint: `'?15 member ['static, 'a, 'b, 'c]`.
 //
 // Make sure we pick up the minimum non-ambiguous region among them.
 // We will have to exclude `['b, 'c]` because they're incomparable,
diff --git a/tests/ui/nll/member-constraints/nested-impl-trait-fail.rs b/tests/ui/nll/member-constraints/nested-impl-trait-fail.rs
index 66ff828a84f..ceb417f84f3 100644
--- a/tests/ui/nll/member-constraints/nested-impl-trait-fail.rs
+++ b/tests/ui/nll/member-constraints/nested-impl-trait-fail.rs
@@ -5,9 +5,9 @@
 trait Cap<'a> {}
 impl<T> Cap<'_> for T {}
 
-// Assuming the hidden type is `[&'_#15r u8; 1]`, we have two distinct member constraints:
-// - '_#15r member ['static, 'a, 'b] // from outer impl-trait
-// - '_#15r member ['static, 'a, 'b] // from inner impl-trait
+// Assuming the hidden type is `[&'?15 u8; 1]`, we have two distinct member constraints:
+// - '?15 member ['static, 'a, 'b] // from outer impl-trait
+// - '?15 member ['static, 'a, 'b] // from inner impl-trait
 // To satisfy both we can choose 'a or 'b, so it's a failure due to ambiguity.
 fn fail_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>>
 where
diff --git a/tests/ui/nll/member-constraints/nested-impl-trait-pass.rs b/tests/ui/nll/member-constraints/nested-impl-trait-pass.rs
index 15540cb460e..4be0f02acf2 100644
--- a/tests/ui/nll/member-constraints/nested-impl-trait-pass.rs
+++ b/tests/ui/nll/member-constraints/nested-impl-trait-pass.rs
@@ -5,9 +5,9 @@
 trait Cap<'a> {}
 impl<T> Cap<'_> for T {}
 
-// Assuming the hidden type is `[&'_#15r u8; 1]`, we have two distinct member constraints:
-// - '_#15r member ['static, 'a, 'b] // from outer impl-trait
-// - '_#15r member ['static, 'a]     // from inner impl-trait
+// Assuming the hidden type is `[&'?15 u8; 1]`, we have two distinct member constraints:
+// - '?15 member ['static, 'a, 'b] // from outer impl-trait
+// - '?15 member ['static, 'a]     // from inner impl-trait
 // To satisfy both we can only choose 'a.
 fn pass_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl Cap<'a>> + Cap<'b>
 where
diff --git a/tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr
index 4933b934868..4eefb180ee5 100644
--- a/tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr
+++ b/tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr
@@ -4,13 +4,13 @@ note: external requirements
 LL |     with_signature(x, |mut y| Box::new(y.next()))
    |                       ^^^^^^^
    |
-   = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [
+   = note: defining type: no_region::<'?1, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>,
+               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '?2)>,
                (),
            ]
    = note: number of external vids: 3
-   = note: where <T as std::iter::Iterator>::Item: '_#2r
+   = note: where <T as std::iter::Iterator>::Item: '?2
 
 note: no external requirements
   --> $DIR/projection-no-regions-closure.rs:21:1
@@ -20,7 +20,7 @@ LL | | where
 LL | |     T: Iterator,
    | |________________^
    |
-   = note: defining type: no_region::<'_#1r, T>
+   = note: defining type: no_region::<'?1, T>
 
 error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
   --> $DIR/projection-no-regions-closure.rs:25:31
@@ -37,13 +37,13 @@ note: external requirements
 LL |     with_signature(x, |mut y| Box::new(y.next()))
    |                       ^^^^^^^
    |
-   = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [
+   = note: defining type: correct_region::<'?1, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>,
+               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '?2)>,
                (),
            ]
    = note: number of external vids: 3
-   = note: where <T as std::iter::Iterator>::Item: '_#2r
+   = note: where <T as std::iter::Iterator>::Item: '?2
 
 note: no external requirements
   --> $DIR/projection-no-regions-closure.rs:30:1
@@ -53,7 +53,7 @@ LL | | where
 LL | |     T: 'a + Iterator,
    | |_____________________^
    |
-   = note: defining type: correct_region::<'_#1r, T>
+   = note: defining type: correct_region::<'?1, T>
 
 note: external requirements
   --> $DIR/projection-no-regions-closure.rs:42:23
@@ -61,13 +61,13 @@ note: external requirements
 LL |     with_signature(x, |mut y| Box::new(y.next()))
    |                       ^^^^^^^
    |
-   = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+   = note: defining type: wrong_region::<'?1, '?2, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>,
+               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '?3)>,
                (),
            ]
    = note: number of external vids: 4
-   = note: where <T as std::iter::Iterator>::Item: '_#3r
+   = note: where <T as std::iter::Iterator>::Item: '?3
 
 note: no external requirements
   --> $DIR/projection-no-regions-closure.rs:38:1
@@ -77,7 +77,7 @@ LL | | where
 LL | |     T: 'b + Iterator,
    | |_____________________^
    |
-   = note: defining type: wrong_region::<'_#1r, '_#2r, T>
+   = note: defining type: wrong_region::<'?1, '?2, T>
 
 error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
   --> $DIR/projection-no-regions-closure.rs:42:31
@@ -94,13 +94,13 @@ note: external requirements
 LL |     with_signature(x, |mut y| Box::new(y.next()))
    |                       ^^^^^^^
    |
-   = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+   = note: defining type: outlives_region::<'?1, '?2, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>,
+               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '?3)>,
                (),
            ]
    = note: number of external vids: 4
-   = note: where <T as std::iter::Iterator>::Item: '_#3r
+   = note: where <T as std::iter::Iterator>::Item: '?3
 
 note: no external requirements
   --> $DIR/projection-no-regions-closure.rs:47:1
@@ -111,7 +111,7 @@ LL | |     T: 'b + Iterator,
 LL | |     'b: 'a,
    | |___________^
    |
-   = note: defining type: outlives_region::<'_#1r, '_#2r, T>
+   = note: defining type: outlives_region::<'?1, '?2, T>
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr b/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr
index 11ada59c066..986c2bd2182 100644
--- a/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr
+++ b/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr
@@ -4,15 +4,15 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [
+   = note: defining type: no_relationships_late::<'?1, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)),
                (),
            ]
-   = note: late-bound region is '_#3r
+   = note: late-bound region is '?3
    = note: number of external vids: 4
-   = note: where T: '_#2r
-   = note: where '_#1r: '_#2r
+   = note: where T: '?2
+   = note: where '?1: '?2
 
 note: no external requirements
   --> $DIR/projection-one-region-closure.rs:41:1
@@ -22,7 +22,7 @@ LL | | where
 LL | |     T: Anything<'b>,
    | |____________________^
    |
-   = note: defining type: no_relationships_late::<'_#1r, T>
+   = note: defining type: no_relationships_late::<'?1, T>
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/projection-one-region-closure.rs:45:39
@@ -54,14 +54,14 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+   = note: defining type: no_relationships_early::<'?1, '?2, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)),
                (),
            ]
    = note: number of external vids: 4
-   = note: where T: '_#3r
-   = note: where '_#2r: '_#3r
+   = note: where T: '?3
+   = note: where '?2: '?3
 
 note: no external requirements
   --> $DIR/projection-one-region-closure.rs:51:1
@@ -72,7 +72,7 @@ LL | |     T: Anything<'b>,
 LL | |     'a: 'a,
    | |___________^
    |
-   = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>
+   = note: defining type: no_relationships_early::<'?1, '?2, T>
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/projection-one-region-closure.rs:56:39
@@ -104,13 +104,13 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+   = note: defining type: projection_outlives::<'?1, '?2, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)),
                (),
            ]
    = note: number of external vids: 4
-   = note: where <T as Anything<'_#2r>>::AssocType: '_#3r
+   = note: where <T as Anything<'?2>>::AssocType: '?3
 
 note: no external requirements
   --> $DIR/projection-one-region-closure.rs:62:1
@@ -121,7 +121,7 @@ LL | |     T: Anything<'b>,
 LL | |     T::AssocType: 'a,
    | |_____________________^
    |
-   = note: defining type: projection_outlives::<'_#1r, '_#2r, T>
+   = note: defining type: projection_outlives::<'?1, '?2, T>
 
 note: external requirements
   --> $DIR/projection-one-region-closure.rs:80:29
@@ -129,14 +129,14 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+   = note: defining type: elements_outlive::<'?1, '?2, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)),
                (),
            ]
    = note: number of external vids: 4
-   = note: where T: '_#3r
-   = note: where '_#2r: '_#3r
+   = note: where T: '?3
+   = note: where '?2: '?3
 
 note: no external requirements
   --> $DIR/projection-one-region-closure.rs:74:1
@@ -148,7 +148,7 @@ LL | |     T: 'a,
 LL | |     'b: 'a,
    | |___________^
    |
-   = note: defining type: elements_outlive::<'_#1r, '_#2r, T>
+   = note: defining type: elements_outlive::<'?1, '?2, T>
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
index 47d4f2e46c6..25cc60d8141 100644
--- a/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
+++ b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
@@ -4,14 +4,14 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [
+   = note: defining type: no_relationships_late::<'?1, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)),
                (),
            ]
-   = note: late-bound region is '_#3r
+   = note: late-bound region is '?3
    = note: number of external vids: 4
-   = note: where '_#1r: '_#2r
+   = note: where '?1: '?2
 
 note: no external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:33:1
@@ -21,7 +21,7 @@ LL | | where
 LL | |     T: Anything<'b>,
    | |____________________^
    |
-   = note: defining type: no_relationships_late::<'_#1r, T>
+   = note: defining type: no_relationships_late::<'?1, T>
 
 error: lifetime may not live long enough
   --> $DIR/projection-one-region-trait-bound-closure.rs:37:39
@@ -42,13 +42,13 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+   = note: defining type: no_relationships_early::<'?1, '?2, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)),
                (),
            ]
    = note: number of external vids: 4
-   = note: where '_#2r: '_#3r
+   = note: where '?2: '?3
 
 note: no external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:42:1
@@ -59,7 +59,7 @@ LL | |     T: Anything<'b>,
 LL | |     'a: 'a,
    | |___________^
    |
-   = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>
+   = note: defining type: no_relationships_early::<'?1, '?2, T>
 
 error: lifetime may not live long enough
   --> $DIR/projection-one-region-trait-bound-closure.rs:47:39
@@ -80,13 +80,13 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+   = note: defining type: projection_outlives::<'?1, '?2, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)),
                (),
            ]
    = note: number of external vids: 4
-   = note: where <T as Anything<'_#2r>>::AssocType: '_#3r
+   = note: where <T as Anything<'?2>>::AssocType: '?3
 
 note: no external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:52:1
@@ -97,7 +97,7 @@ LL | |     T: Anything<'b>,
 LL | |     T::AssocType: 'a,
    | |_____________________^
    |
-   = note: defining type: projection_outlives::<'_#1r, '_#2r, T>
+   = note: defining type: projection_outlives::<'?1, '?2, T>
 
 note: external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:69:29
@@ -105,13 +105,13 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+   = note: defining type: elements_outlive::<'?1, '?2, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)),
                (),
            ]
    = note: number of external vids: 4
-   = note: where '_#2r: '_#3r
+   = note: where '?2: '?3
 
 note: no external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:64:1
@@ -122,7 +122,7 @@ LL | |     T: Anything<'b>,
 LL | |     'b: 'a,
    | |___________^
    |
-   = note: defining type: elements_outlive::<'_#1r, '_#2r, T>
+   = note: defining type: elements_outlive::<'?1, '?2, T>
 
 note: external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:81:29
@@ -130,13 +130,13 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [
+   = note: defining type: one_region::<'?1, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)),
                (),
            ]
    = note: number of external vids: 3
-   = note: where '_#1r: '_#2r
+   = note: where '?1: '?2
 
 note: no external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:73:1
@@ -146,7 +146,7 @@ LL | | where
 LL | |     T: Anything<'a>,
    | |____________________^
    |
-   = note: defining type: one_region::<'_#1r, T>
+   = note: defining type: one_region::<'?1, T>
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
index b27186b0537..5a092d7b849 100644
--- a/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
+++ b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
@@ -4,12 +4,12 @@ note: no external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [
+   = note: defining type: no_relationships_late::<'?1, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)),
                (),
            ]
-   = note: late-bound region is '_#3r
+   = note: late-bound region is '?3
 
 note: no external requirements
   --> $DIR/projection-one-region-trait-bound-static-closure.rs:32:1
@@ -19,7 +19,7 @@ LL | | where
 LL | |     T: Anything<'b>,
    | |____________________^
    |
-   = note: defining type: no_relationships_late::<'_#1r, T>
+   = note: defining type: no_relationships_late::<'?1, T>
 
 note: no external requirements
   --> $DIR/projection-one-region-trait-bound-static-closure.rs:45:29
@@ -27,9 +27,9 @@ note: no external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+   = note: defining type: no_relationships_early::<'?1, '?2, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)),
                (),
            ]
 
@@ -42,7 +42,7 @@ LL | |     T: Anything<'b>,
 LL | |     'a: 'a,
    | |___________^
    |
-   = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>
+   = note: defining type: no_relationships_early::<'?1, '?2, T>
 
 note: no external requirements
   --> $DIR/projection-one-region-trait-bound-static-closure.rs:64:29
@@ -50,9 +50,9 @@ note: no external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+   = note: defining type: projection_outlives::<'?1, '?2, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)),
                (),
            ]
 
@@ -65,7 +65,7 @@ LL | |     T: Anything<'b>,
 LL | |     T::AssocType: 'a,
    | |_____________________^
    |
-   = note: defining type: projection_outlives::<'_#1r, '_#2r, T>
+   = note: defining type: projection_outlives::<'?1, '?2, T>
 
 note: no external requirements
   --> $DIR/projection-one-region-trait-bound-static-closure.rs:73:29
@@ -73,9 +73,9 @@ note: no external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+   = note: defining type: elements_outlive::<'?1, '?2, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)),
                (),
            ]
 
@@ -88,7 +88,7 @@ LL | |     T: Anything<'b>,
 LL | |     'b: 'a,
    | |___________^
    |
-   = note: defining type: elements_outlive::<'_#1r, '_#2r, T>
+   = note: defining type: elements_outlive::<'?1, '?2, T>
 
 note: no external requirements
   --> $DIR/projection-one-region-trait-bound-static-closure.rs:85:29
@@ -96,9 +96,9 @@ note: no external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [
+   = note: defining type: one_region::<'?1, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)),
                (),
            ]
 
@@ -110,5 +110,5 @@ LL | | where
 LL | |     T: Anything<'a>,
    | |____________________^
    |
-   = note: defining type: one_region::<'_#1r, T>
+   = note: defining type: one_region::<'?1, T>
 
diff --git a/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
index 530dd86819d..51283aa8828 100644
--- a/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
+++ b/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
@@ -4,14 +4,14 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+   = note: defining type: no_relationships_late::<'?1, '?2, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)),
                (),
            ]
-   = note: late-bound region is '_#4r
+   = note: late-bound region is '?4
    = note: number of external vids: 5
-   = note: where <T as Anything<'_#1r, '_#2r>>::AssocType: '_#3r
+   = note: where <T as Anything<'?1, '?2>>::AssocType: '?3
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:34:1
@@ -21,16 +21,16 @@ LL | | where
 LL | |     T: Anything<'b, 'c>,
    | |________________________^
    |
-   = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>
+   = note: defining type: no_relationships_late::<'?1, '?2, T>
 
-error[E0309]: the associated type `<T as Anything<'_#5r, '_#6r>>::AssocType` may not live long enough
+error[E0309]: the associated type `<T as Anything<'?5, '?6>>::AssocType` may not live long enough
   --> $DIR/projection-two-region-trait-bound-closure.rs:38:39
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                                       ^^^^^^^^^^^^^^^^
    |
-   = help: consider adding an explicit lifetime bound `<T as Anything<'_#5r, '_#6r>>::AssocType: 'a`...
-   = note: ...so that the type `<T as Anything<'_#5r, '_#6r>>::AssocType` will meet its required lifetime bounds
+   = help: consider adding an explicit lifetime bound `<T as Anything<'?5, '?6>>::AssocType: 'a`...
+   = note: ...so that the type `<T as Anything<'?5, '?6>>::AssocType` will meet its required lifetime bounds
 
 note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:48:29
@@ -38,13 +38,13 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [
+   = note: defining type: no_relationships_early::<'?1, '?2, '?3, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?4 ()>, T)),
                (),
            ]
    = note: number of external vids: 5
-   = note: where <T as Anything<'_#2r, '_#3r>>::AssocType: '_#4r
+   = note: where <T as Anything<'?2, '?3>>::AssocType: '?4
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:43:1
@@ -55,16 +55,16 @@ LL | |     T: Anything<'b, 'c>,
 LL | |     'a: 'a,
    | |___________^
    |
-   = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>
+   = note: defining type: no_relationships_early::<'?1, '?2, '?3, T>
 
-error[E0309]: the associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
+error[E0309]: the associated type `<T as Anything<'?6, '?7>>::AssocType` may not live long enough
   --> $DIR/projection-two-region-trait-bound-closure.rs:48:39
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                                       ^^^^^^^^^^^^^^^^
    |
-   = help: consider adding an explicit lifetime bound `<T as Anything<'_#6r, '_#7r>>::AssocType: 'a`...
-   = note: ...so that the type `<T as Anything<'_#6r, '_#7r>>::AssocType` will meet its required lifetime bounds
+   = help: consider adding an explicit lifetime bound `<T as Anything<'?6, '?7>>::AssocType: 'a`...
+   = note: ...so that the type `<T as Anything<'?6, '?7>>::AssocType` will meet its required lifetime bounds
 
 note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:61:29
@@ -72,13 +72,13 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [
+   = note: defining type: projection_outlives::<'?1, '?2, '?3, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?4 ()>, T)),
                (),
            ]
    = note: number of external vids: 5
-   = note: where <T as Anything<'_#2r, '_#3r>>::AssocType: '_#4r
+   = note: where <T as Anything<'?2, '?3>>::AssocType: '?4
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:53:1
@@ -89,7 +89,7 @@ LL | |     T: Anything<'b, 'c>,
 LL | |     T::AssocType: 'a,
    | |_____________________^
    |
-   = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>
+   = note: defining type: projection_outlives::<'?1, '?2, '?3, T>
 
 note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:70:29
@@ -97,13 +97,13 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [
+   = note: defining type: elements_outlive1::<'?1, '?2, '?3, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?4 ()>, T)),
                (),
            ]
    = note: number of external vids: 5
-   = note: where <T as Anything<'_#2r, '_#3r>>::AssocType: '_#4r
+   = note: where <T as Anything<'?2, '?3>>::AssocType: '?4
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:65:1
@@ -114,7 +114,7 @@ LL | |     T: Anything<'b, 'c>,
 LL | |     'b: 'a,
    | |___________^
    |
-   = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>
+   = note: defining type: elements_outlive1::<'?1, '?2, '?3, T>
 
 note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:79:29
@@ -122,13 +122,13 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [
+   = note: defining type: elements_outlive2::<'?1, '?2, '?3, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?4 ()>, T)),
                (),
            ]
    = note: number of external vids: 5
-   = note: where <T as Anything<'_#2r, '_#3r>>::AssocType: '_#4r
+   = note: where <T as Anything<'?2, '?3>>::AssocType: '?4
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:74:1
@@ -139,7 +139,7 @@ LL | |     T: Anything<'b, 'c>,
 LL | |     'c: 'a,
    | |___________^
    |
-   = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>
+   = note: defining type: elements_outlive2::<'?1, '?2, '?3, T>
 
 note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:87:29
@@ -147,14 +147,14 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: two_regions::<'_#1r, T>::{closure#0} with closure substs [
+   = note: defining type: two_regions::<'?1, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)),
                (),
            ]
-   = note: late-bound region is '_#3r
+   = note: late-bound region is '?3
    = note: number of external vids: 4
-   = note: where <T as Anything<'_#1r, '_#1r>>::AssocType: '_#2r
+   = note: where <T as Anything<'?1, '?1>>::AssocType: '?2
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:83:1
@@ -164,7 +164,7 @@ LL | | where
 LL | |     T: Anything<'b, 'b>,
    | |________________________^
    |
-   = note: defining type: two_regions::<'_#1r, T>
+   = note: defining type: two_regions::<'?1, T>
 
 error: lifetime may not live long enough
   --> $DIR/projection-two-region-trait-bound-closure.rs:87:5
@@ -178,7 +178,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
-   = note: requirement occurs because of the type `Cell<&'_#8r ()>`, which makes the generic argument `&'_#8r ()` invariant
+   = note: requirement occurs because of the type `Cell<&'?8 ()>`, which makes the generic argument `&'?8 ()` invariant
    = note: the struct `Cell<T>` is invariant over the parameter `T`
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
@@ -188,13 +188,13 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+   = note: defining type: two_regions_outlive::<'?1, '?2, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)),
                (),
            ]
    = note: number of external vids: 4
-   = note: where <T as Anything<'_#2r, '_#2r>>::AssocType: '_#3r
+   = note: where <T as Anything<'?2, '?2>>::AssocType: '?3
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:92:1
@@ -205,7 +205,7 @@ LL | |     T: Anything<'b, 'b>,
 LL | |     'b: 'a,
    | |___________^
    |
-   = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>
+   = note: defining type: two_regions_outlive::<'?1, '?2, T>
 
 note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:109:29
@@ -213,13 +213,13 @@ note: external requirements
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^
    |
-   = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [
+   = note: defining type: one_region::<'?1, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)),
                (),
            ]
    = note: number of external vids: 3
-   = note: where <T as Anything<'_#1r, '_#1r>>::AssocType: '_#2r
+   = note: where <T as Anything<'?1, '?1>>::AssocType: '?2
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:101:1
@@ -229,7 +229,7 @@ LL | | where
 LL | |     T: Anything<'a, 'a>,
    | |________________________^
    |
-   = note: defining type: one_region::<'_#1r, T>
+   = note: defining type: one_region::<'?1, T>
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
index 2c4a0597554..04616f9b702 100644
--- a/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
+++ b/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
@@ -6,11 +6,11 @@ LL |     twice(cell, value, |a, b| invoke(a, b));
    |
    = note: defining type: generic::<T>::{closure#0} with closure substs [
                i16,
-               for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) T)),
+               for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'?1 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) T)),
                (),
            ]
    = note: number of external vids: 2
-   = note: where T: '_#1r
+   = note: where T: '?1
 
 note: no external requirements
   --> $DIR/ty-param-closure-approximate-lower-bound.rs:22:1
@@ -28,12 +28,12 @@ LL |     twice(cell, value, |a, b| invoke(a, b));
    |
    = note: defining type: generic_fail::<T>::{closure#0} with closure substs [
                i16,
-               for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) T)),
+               for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'?1 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) T)),
                (),
            ]
-   = note: late-bound region is '_#2r
+   = note: late-bound region is '?2
    = note: number of external vids: 3
-   = note: where T: '_#1r
+   = note: where T: '?1
 
 note: no external requirements
   --> $DIR/ty-param-closure-approximate-lower-bound.rs:28:1
diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs
index 4343c3aee53..72b18c16732 100644
--- a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs
+++ b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs
@@ -19,8 +19,8 @@ where
     // Here, the closure winds up being required to prove that `T:
     // 'a`.  In principle, it could know that, except that it is
     // type-checked in a fully generic way, and hence it winds up with
-    // a propagated requirement that `T: '_#2`, where `'_#2` appears
-    // in the return type. The caller makes the mapping from `'_#2` to
+    // a propagated requirement that `T: '?2`, where `'?2` appears
+    // in the return type. The caller makes the mapping from `'?2` to
     // `'a` (and subsequently reports an error).
 
     with_signature(x, |y| y)
diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
index 35979c8bf51..d580774ff8c 100644
--- a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
+++ b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
@@ -4,13 +4,13 @@ note: external requirements
 LL |     with_signature(x, |y| y)
    |                       ^^^
    |
-   = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [
+   = note: defining type: no_region::<'?1, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)>,
+               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '?2)>,
                (),
            ]
    = note: number of external vids: 3
-   = note: where T: '_#2r
+   = note: where T: '?2
 
 note: no external requirements
   --> $DIR/ty-param-closure-outlives-from-return-type.rs:15:1
@@ -20,7 +20,7 @@ LL | | where
 LL | |     T: Debug,
    | |_____________^
    |
-   = note: defining type: no_region::<'_#1r, T>
+   = note: defining type: no_region::<'?1, T>
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:27
diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
index 4c97db58c6c..3d4c11a3c54 100644
--- a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
+++ b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
@@ -6,12 +6,12 @@ LL |     with_signature(a, b, |x, y| {
    |
    = note: defining type: no_region::<T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?1 ()>, T)),
                (),
            ]
-   = note: late-bound region is '_#2r
+   = note: late-bound region is '?2
    = note: number of external vids: 3
-   = note: where T: '_#1r
+   = note: where T: '?1
 
 note: no external requirements
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:26:1
@@ -38,13 +38,13 @@ note: external requirements
 LL |     with_signature(a, b, |x, y| {
    |                          ^^^^^^
    |
-   = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [
+   = note: defining type: correct_region::<'?1, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)),
                (),
            ]
    = note: number of external vids: 3
-   = note: where T: '_#2r
+   = note: where T: '?2
 
 note: no external requirements
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:1
@@ -54,7 +54,7 @@ LL | | where
 LL | |     T: 'a,
    | |__________^
    |
-   = note: defining type: correct_region::<'_#1r, T>
+   = note: defining type: correct_region::<'?1, T>
 
 note: external requirements
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:63:26
@@ -62,14 +62,14 @@ note: external requirements
 LL |     with_signature(a, b, |x, y| {
    |                          ^^^^^^
    |
-   = note: defining type: wrong_region::<'_#1r, T>::{closure#0} with closure substs [
+   = note: defining type: wrong_region::<'?1, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)),
                (),
            ]
-   = note: late-bound region is '_#3r
+   = note: late-bound region is '?3
    = note: number of external vids: 4
-   = note: where T: '_#2r
+   = note: where T: '?2
 
 note: no external requirements
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:59:1
@@ -79,7 +79,7 @@ LL | | where
 LL | |     T: 'b,
    | |__________^
    |
-   = note: defining type: wrong_region::<'_#1r, T>
+   = note: defining type: wrong_region::<'?1, T>
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:65:9
@@ -98,13 +98,13 @@ note: external requirements
 LL |     with_signature(a, b, |x, y| {
    |                          ^^^^^^
    |
-   = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
+   = note: defining type: outlives_region::<'?1, '?2, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
+               extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)),
                (),
            ]
    = note: number of external vids: 4
-   = note: where T: '_#3r
+   = note: where T: '?3
 
 note: no external requirements
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:71:1
@@ -115,7 +115,7 @@ LL | |     T: 'b,
 LL | |     'b: 'a,
    | |___________^
    |
-   = note: defining type: outlives_region::<'_#1r, '_#2r, T>
+   = note: defining type: outlives_region::<'?1, '?2, T>
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/oom_unwind.rs b/tests/ui/oom_unwind.rs
index 704d6f8b810..21a8fb2b22b 100644
--- a/tests/ui/oom_unwind.rs
+++ b/tests/ui/oom_unwind.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Z oom=unwind
+// compile-flags: -Z oom=panic
 // run-pass
 // no-prefer-dynamic
 // needs-unwind
diff --git a/tests/ui/repr/repr-transparent.stderr b/tests/ui/repr/repr-transparent.stderr
index f1c570b9523..cb1e2337776 100644
--- a/tests/ui/repr/repr-transparent.stderr
+++ b/tests/ui/repr/repr-transparent.stderr
@@ -58,7 +58,7 @@ error[E0731]: transparent enum needs exactly one variant, but has 2
 LL | enum MultipleVariants {
    | ^^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2
 LL |     Foo(String),
-   |     ---
+   |     --- variant here
 LL |     Bar,
    |     --- too many variants in `MultipleVariants`
 
diff --git a/tests/ui/repr/transparent-enum-too-many-variants.stderr b/tests/ui/repr/transparent-enum-too-many-variants.stderr
index fb44757efaf..1a500257f48 100644
--- a/tests/ui/repr/transparent-enum-too-many-variants.stderr
+++ b/tests/ui/repr/transparent-enum-too-many-variants.stderr
@@ -5,6 +5,8 @@ LL | enum Foo {
    | ^^^^^^^^ needs exactly one variant, but has 2
 LL |     A(u8), B(u8),
    |     -      - too many variants in `Foo`
+   |     |
+   |     variant here
 
 error: aborting due to previous error
 
diff --git a/tests/ui/traits/infer-from-object-issue-26952.rs b/tests/ui/traits/infer-from-object-issue-26952.rs
index ed258dbb24c..9544b4f2088 100644
--- a/tests/ui/traits/infer-from-object-issue-26952.rs
+++ b/tests/ui/traits/infer-from-object-issue-26952.rs
@@ -1,8 +1,8 @@
 // run-pass
 #![allow(dead_code)]
 #![allow(unused_variables)]
-// Test that when we match a trait reference like `Foo<A>: Foo<_#0t>`,
-// we unify with `_#0t` with `A`. In this code, if we failed to do
+// Test that when we match a trait reference like `Foo<A>: Foo<?0t>`,
+// we unify with `?0t` with `A`. In this code, if we failed to do
 // that, then you get an unconstrained type-variable in `call`.
 //
 // Also serves as a regression test for issue #26952, though the test
diff --git a/tests/ui/traits/new-solver/int-var-alias-eq.rs b/tests/ui/traits/new-solver/int-var-alias-eq.rs
index 2da387db4a9..790197e2d97 100644
--- a/tests/ui/traits/new-solver/int-var-alias-eq.rs
+++ b/tests/ui/traits/new-solver/int-var-alias-eq.rs
@@ -1,7 +1,7 @@
 // check-pass
 // compile-flags: -Ztrait-solver=next
 
-// HIR typeck ends up equating `<_#0i as Add>::Output == _#0i`.
+// HIR typeck ends up equating `<?0i as Add>::Output == ?0i`.
 // Want to make sure that we emit an alias-eq goal for this,
 // instead of treating it as a type error and bailing.
 
diff --git a/tests/ui/traits/new-solver/negative-coherence-bounds.rs b/tests/ui/traits/new-solver/negative-coherence-bounds.rs
new file mode 100644
index 00000000000..5436b02c3de
--- /dev/null
+++ b/tests/ui/traits/new-solver/negative-coherence-bounds.rs
@@ -0,0 +1,40 @@
+// check-pass
+
+// This test verifies that negative trait predicate cannot be satisfied from a
+// positive param-env candidate.
+
+// Negative coherence is one of the only places where we actually construct and
+// evaluate negative predicates. Specifically, when verifying whether the first
+// and second impls below overlap, we do not want to consider them disjoint,
+// otherwise the second impl would be missing an associated type `type Item`
+// which is provided by the first impl that it is specializing.
+
+#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
+#![feature(with_negative_coherence)]
+
+trait BoxIter {
+    type Item;
+
+    fn last(self) -> Option<Self::Item>;
+}
+
+impl<I: Iterator + ?Sized> BoxIter for Box<I> {
+    type Item = I::Item;
+
+    default fn last(self) -> Option<I::Item> {
+        todo!()
+    }
+}
+
+// When checking that this impl does/doesn't overlap the one above, we evaluate
+// a negative version of all of the where-clause predicates of the impl below.
+// For `I: !Iterator`, we should make sure that the param-env clause `I: Iterator`
+// from above doesn't satisfy this predicate.
+impl<I: Iterator> BoxIter for Box<I> {
+    fn last(self) -> Option<I::Item> {
+        (*self).last()
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/traits/new-solver/negative-coherence-bounds.stderr b/tests/ui/traits/new-solver/negative-coherence-bounds.stderr
new file mode 100644
index 00000000000..4127f51f56d
--- /dev/null
+++ b/tests/ui/traits/new-solver/negative-coherence-bounds.stderr
@@ -0,0 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/negative-coherence-bounds.rs:12:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.rs b/tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.rs
index cde2059ca9b..3c7fc0d813d 100644
--- a/tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.rs
+++ b/tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.rs
@@ -1,7 +1,7 @@
 // compile-flags: -Ztrait-solver=next
 
 // When we're solving `<T as Foo>::Assoc = i32`, we actually first solve
-// `<T as Foo>::Assoc = _#1t`, then unify `_#1t` with `i32`. That goal
+// `<T as Foo>::Assoc = ?1t`, then unify `?1t` with `i32`. That goal
 // with the inference variable is ambiguous when there are >1 param-env
 // candidates.
 
diff --git a/tests/ui/type-alias-impl-trait/closure_parent_substs.rs b/tests/ui/type-alias-impl-trait/closure_parent_substs.rs
index 475f4724ff2..3ff20d99ad8 100644
--- a/tests/ui/type-alias-impl-trait/closure_parent_substs.rs
+++ b/tests/ui/type-alias-impl-trait/closure_parent_substs.rs
@@ -12,7 +12,7 @@
 
 // Basic test
 mod test1 {
-    // Hidden type = Closure['_#0r]
+    // Hidden type = Closure['?0]
     type Opaque = impl Sized;
 
     fn define<'a: 'a>() -> Opaque {
@@ -24,8 +24,8 @@ mod test1 {
 mod test2 {
     trait Trait {}
 
-    // Hidden type = Closure['a, '_#0r, '_#1r]
-    // Constraints = [('_#0r: 'a), ('a: '_#1r)]
+    // Hidden type = Closure['a, '?0, '?1]
+    // Constraints = [('?0: 'a), ('a: '?1)]
     type Opaque<'a>
     where
         &'a (): Trait,
@@ -45,8 +45,8 @@ mod test2 {
 mod test3 {
     trait Trait {}
 
-    // Hidden type = Closure['a, 'b, '_#0r]
-    // Constraints = [('_#0r: 'a), ('_#0r: 'b)]
+    // Hidden type = Closure['a, 'b, '?0]
+    // Constraints = [('?0: 'a), ('?0: 'b)]
     type Opaque<'a, 'b>
     where
         (&'a (), &'b ()): Trait,