about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--compiler/rustc/src/main.rs3
-rw-r--r--compiler/rustc_ast/src/ast.rs12
-rw-r--r--compiler/rustc_ast_lowering/messages.ftl12
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs21
-rw-r--r--compiler/rustc_ast_lowering/src/delegation.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs7
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs3
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs4
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs4
-rw-r--r--compiler/rustc_attr/messages.ftl3
-rw-r--r--compiler/rustc_attr/src/builtin.rs19
-rw-r--r--compiler/rustc_borrowck/messages.ftl21
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs64
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs7
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs3
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs1
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/common.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs61
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs33
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/mod.rs17
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/constant.rs39
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs19
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/consts.rs1
-rw-r--r--compiler/rustc_const_eval/messages.ftl5
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs8
-rw-r--r--compiler/rustc_data_structures/src/transitive_relation.rs6
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs55
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs1
-rw-r--r--compiler/rustc_errors/src/emitter.rs29
-rw-r--r--compiler/rustc_errors/src/lib.rs10
-rw-r--r--compiler/rustc_expand/messages.ftl3
-rw-r--r--compiler/rustc_expand/src/base.rs10
-rw-r--r--compiler/rustc_expand/src/expand.rs5
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/unstable.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs21
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs43
-rw-r--r--compiler/rustc_interface/src/util.rs1
-rw-r--r--compiler/rustc_lint/src/builtin.rs21
-rw-r--r--compiler/rustc_lint/src/levels.rs2
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs4
-rw-r--r--compiler/rustc_lint/src/types.rs9
-rw-r--r--compiler/rustc_lint/src/unused.rs10
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp12
-rw-r--r--compiler/rustc_metadata/messages.ftl9
-rw-r--r--compiler/rustc_metadata/src/creader.rs1
-rw-r--r--compiler/rustc_metadata/src/dependency_format.rs55
-rw-r--r--compiler/rustc_metadata/src/errors.rs6
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs16
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs18
-rw-r--r--compiler/rustc_middle/src/lib.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/assoc.rs9
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs12
-rw-r--r--compiler/rustc_mir_build/src/build/matches/match_pair.rs13
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs12
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs4
-rw-r--r--compiler/rustc_mir_transform/src/early_otherwise_branch.rs6
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_box_derefs.rs17
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs6
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs14
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs6
-rw-r--r--compiler/rustc_parse/src/parser/item.rs5
-rw-r--r--compiler/rustc_parse/src/parser/path.rs3
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs6
-rw-r--r--compiler/rustc_passes/messages.ftl6
-rw-r--r--compiler/rustc_passes/src/check_attr.rs10
-rw-r--r--compiler/rustc_passes/src/debugger_visualizer.rs4
-rw-r--r--compiler/rustc_passes/src/entry.rs1
-rw-r--r--compiler/rustc_pattern_analysis/src/lib.rs2
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs139
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc/print.rs268
-rw-r--r--compiler/rustc_pattern_analysis/src/usefulness.rs19
-rw-r--r--compiler/rustc_pattern_analysis/tests/common/mod.rs4
-rw-r--r--compiler/rustc_query_system/src/dep_graph/debug.rs11
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs8
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs6
-rw-r--r--compiler/rustc_resolve/src/imports.rs5
-rw-r--r--compiler/rustc_resolve/src/late.rs20
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs13
-rw-r--r--compiler/rustc_resolve/src/lib.rs12
-rw-r--r--compiler/rustc_resolve/src/macros.rs10
-rw-r--r--compiler/rustc_session/src/options.rs13
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/lib.rs2
-rw-r--r--compiler/rustc_target/src/spec/mod.rs9
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs3
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs42
-rw-r--r--compiler/rustc_transmute/src/layout/nfa.rs1
-rw-r--r--compiler/rustc_type_ir/src/fold.rs2
-rw-r--r--library/alloc/src/collections/vec_deque/into_iter.rs2
-rw-r--r--library/alloc/src/raw_vec.rs569
-rw-r--r--library/alloc/src/raw_vec/tests.rs27
-rw-r--r--library/alloc/src/slice.rs96
-rw-r--r--library/core/src/array/mod.rs1
-rw-r--r--library/core/src/ascii/ascii_char.rs32
-rw-r--r--library/core/src/intrinsics.rs10
-rw-r--r--library/core/src/lib.rs2
-rw-r--r--library/core/src/mem/mod.rs5
-rw-r--r--library/core/src/slice/mod.rs98
-rw-r--r--library/core/src/slice/sort/shared/smallsort.rs22
-rw-r--r--library/core/src/slice/sort/unstable/mod.rs2
-rw-r--r--library/core/src/task/wake.rs8
-rw-r--r--library/core/tests/ascii_char.rs28
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/std/src/lib.rs2
-rw-r--r--library/std/src/panic.rs26
-rw-r--r--src/bootstrap/src/bin/main.rs10
-rw-r--r--src/bootstrap/src/bin/rustc.rs22
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs2
-rw-r--r--src/bootstrap/src/core/builder.rs16
-rw-r--r--src/bootstrap/src/core/builder/tests.rs5
-rw-r--r--src/bootstrap/src/core/config/config.rs7
-rw-r--r--src/bootstrap/src/core/config/flags.rs24
-rw-r--r--src/bootstrap/src/core/config/mod.rs2
-rw-r--r--src/bootstrap/src/core/config/tests.rs19
-rw-r--r--src/bootstrap/src/lib.rs2
-rw-r--r--src/bootstrap/src/utils/helpers/tests.rs8
-rw-r--r--src/doc/rustc/src/command-line-arguments.md4
-rw-r--r--src/doc/rustc/src/platform-support.md2
-rw-r--r--src/doc/rustc/src/platform-support/apple-darwin.md3
-rw-r--r--src/doc/unstable-book/src/language-features/rustc-private.md11
-rw-r--r--src/etc/gdb_providers.py17
-rw-r--r--src/etc/lldb_providers.py8
-rw-r--r--src/etc/natvis/liballoc.natvis18
-rw-r--r--src/etc/natvis/libstd.natvis6
-rw-r--r--src/librustdoc/clean/types.rs4
-rw-r--r--src/librustdoc/html/format.rs5
-rw-r--r--src/librustdoc/html/markdown.rs3
-rw-r--r--src/librustdoc/html/render/mod.rs37
-rw-r--r--src/librustdoc/html/static/css/noscript.css8
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css54
-rw-r--r--src/librustdoc/html/static/js/main.js8
m---------src/llvm-project0
-rw-r--r--src/rustdoc-json-types/lib.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs1
-rw-r--r--src/tools/clippy/src/main.rs3
-rw-r--r--src/tools/clippy/tests/compile-test.rs3
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs3
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr6
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.fixed2
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.rs2
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.stderr4
-rw-r--r--src/tools/compiletest/src/runtest.rs8
-rw-r--r--src/tools/miri/README.md1
-rwxr-xr-xsrc/tools/miri/ci/ci.sh2
-rw-r--r--src/tools/miri/src/eval.rs1
-rw-r--r--src/tools/miri/tests/pass/async-fn.rs1
-rw-r--r--src/tools/miri/tests/pass/enums.rs1
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/vec_unique.rs2
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs1
-rw-r--r--src/tools/rustdoc/main.rs3
-rw-r--r--src/tools/rustfmt/src/git-rustfmt/main.rs4
-rw-r--r--tests/codegen-units/item-collection/auxiliary/cgu_extern_closures.rs2
-rw-r--r--tests/codegen-units/item-collection/cross-crate-closures.rs21
-rw-r--r--tests/codegen-units/item-collection/non-generic-closures.rs30
-rw-r--r--tests/codegen-units/partitioning/methods-are-with-self-type.rs42
-rw-r--r--tests/codegen/array-from_fn.rs13
-rw-r--r--tests/codegen/call-metadata.rs1
-rw-r--r--tests/codegen/cast-optimized.rs2
-rw-r--r--tests/codegen/common_prim_int_ptr.rs4
-rw-r--r--tests/codegen/const-vector.rs107
-rw-r--r--tests/codegen/enum/enum-match.rs2
-rw-r--r--tests/codegen/function-arguments.rs6
-rw-r--r--tests/codegen/intrinsics/nontemporal.rs30
-rw-r--r--tests/codegen/issues/issue-68667-unwrap-combinators.rs2
-rw-r--r--tests/codegen/range-attribute.rs68
-rw-r--r--tests/codegen/repr/transparent.rs2
-rw-r--r--tests/debuginfo/pretty-std.rs12
-rw-r--r--tests/debuginfo/strings-and-strs.rs2
-rw-r--r--tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir10
-rw-r--r--tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir15
-rw-r--r--tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir17
-rw-r--r--tests/mir-opt/elaborate_box_deref_in_debuginfo.pointee.ElaborateBoxDerefs.diff13
-rw-r--r--tests/mir-opt/elaborate_box_deref_in_debuginfo.rs20
-rw-r--r--tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir94
-rw-r--r--tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir94
-rw-r--r--tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-abort.diff16
-rw-r--r--tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-unwind.diff16
-rw-r--r--tests/mir-opt/unreachable.rs10
-rw-r--r--tests/mir-opt/unreachable_enum_branching.rs2
-rw-r--r--tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff24
-rw-r--r--tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff24
-rw-r--r--tests/run-make/dump-ice-to-disk/rmake.rs286
-rw-r--r--tests/run-make/fmt-write-bloat/main.rs2
-rw-r--r--tests/run-make/fmt-write-bloat/rmake.rs7
-rw-r--r--tests/rustdoc-gui/code-example-buttons.goml75
-rw-r--r--tests/rustdoc-gui/copy-code.goml4
-rw-r--r--tests/rustdoc-gui/run-on-hover.goml54
-rw-r--r--tests/rustdoc/negative-impl-no-items.rs26
-rw-r--r--tests/rustdoc/playground-arg.rs2
-rw-r--r--tests/rustdoc/playground-syntax-error.rs2
-rw-r--r--tests/rustdoc/playground.rs6
-rw-r--r--tests/ui/async-await/async-closures/box-deref-in-debuginfo.rs35
-rw-r--r--tests/ui/async-await/in-trait/generics-mismatch.rs2
-rw-r--r--tests/ui/async-await/in-trait/generics-mismatch.stderr2
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/multivariant.rs3
-rw-r--r--tests/ui/codemap_tests/huge_multispan_highlight.svg2
-rw-r--r--tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs10
-rw-r--r--tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr10
-rw-r--r--tests/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs4
-rw-r--r--tests/ui/coroutine/gen_block.none.stderr2
-rw-r--r--tests/ui/delegation/not-supported.rs2
-rw-r--r--tests/ui/delegation/not-supported.stderr6
-rw-r--r--tests/ui/enum-discriminant/issue-61696.rs1
-rw-r--r--tests/ui/enum-discriminant/niche.rs1
-rw-r--r--tests/ui/error-codes/E0049.stderr4
-rw-r--r--tests/ui/error-codes/E0195.rs4
-rw-r--r--tests/ui/error-codes/E0195.stderr6
-rw-r--r--tests/ui/feature-gates/feature-gate-coroutines.none.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-exhaustive-patterns.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr10
-rw-r--r--tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs2
-rw-r--r--tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr2
-rw-r--r--tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr2
-rw-r--r--tests/ui/never_type/never-result.rs5
-rw-r--r--tests/ui/pattern/usefulness/always-inhabited-union-ref.exhaustive_patterns.stderr6
-rw-r--r--tests/ui/pattern/usefulness/always-inhabited-union-ref.normal.stderr (renamed from tests/ui/pattern/usefulness/always-inhabited-union-ref.min_exhaustive_patterns.stderr)6
-rw-r--r--tests/ui/pattern/usefulness/always-inhabited-union-ref.rs3
-rw-r--r--tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr6
-rw-r--r--tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr7
-rw-r--r--tests/ui/pattern/usefulness/empty-match-check-notes.rs6
-rw-r--r--tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr93
-rw-r--r--tests/ui/pattern/usefulness/empty-match.normal.stderr93
-rw-r--r--tests/ui/pattern/usefulness/empty-match.rs7
-rw-r--r--tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr100
-rw-r--r--tests/ui/pattern/usefulness/empty-types.never_pats.stderr357
-rw-r--r--tests/ui/pattern/usefulness/empty-types.normal.stderr355
-rw-r--r--tests/ui/pattern/usefulness/empty-types.rs92
-rw-r--r--tests/ui/pattern/usefulness/explain-unreachable-pats.rs1
-rw-r--r--tests/ui/pattern/usefulness/explain-unreachable-pats.stderr24
-rw-r--r--tests/ui/pattern/usefulness/impl-trait.rs1
-rw-r--r--tests/ui/pattern/usefulness/impl-trait.stderr32
-rw-r--r--tests/ui/pattern/usefulness/match-privately-empty.exhaustive_patterns.stderr2
-rw-r--r--tests/ui/pattern/usefulness/match-privately-empty.normal.stderr21
-rw-r--r--tests/ui/pattern/usefulness/match-privately-empty.rs3
-rw-r--r--tests/ui/pattern/usefulness/slice_of_empty.exhaustive_patterns.stderr2
-rw-r--r--tests/ui/pattern/usefulness/slice_of_empty.normal.stderr30
-rw-r--r--tests/ui/pattern/usefulness/slice_of_empty.rs7
-rw-r--r--tests/ui/pattern/usefulness/uninhabited.rs1
-rw-r--r--tests/ui/reachable/unreachable-loop-patterns.rs2
-rw-r--r--tests/ui/reachable/unreachable-loop-patterns.stderr4
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/check.rs8
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/check.stderr22
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/typeck.fail.stderr16
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs1
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr14
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/unreachable.normal.stderr44
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs15
-rw-r--r--tests/ui/rfcs/rfc-0000-never_patterns/unreachable.stderr55
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs11
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr79
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs1
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr8
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs1
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs7
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr64
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs1
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr8
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs1
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs1
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs1
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr10
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr6
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr2
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr8
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr8
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr4
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/auxiliary/edition-lint-infer-outlives-macro.rs (renamed from tests/ui/rust-2018/auxiliary/edition-lint-infer-outlives-macro.rs)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.fixed (renamed from tests/ui/rust-2018/edition-lint-infer-outlives-macro.fixed)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.rs (renamed from tests/ui/rust-2018/edition-lint-infer-outlives-macro.rs)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.stderr (renamed from tests/ui/rust-2018/edition-lint-infer-outlives-macro.stderr)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-multispan.rs (renamed from tests/ui/rust-2018/edition-lint-infer-outlives-multispan.rs)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-multispan.stderr (renamed from tests/ui/rust-2018/edition-lint-infer-outlives-multispan.stderr)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.fixed (renamed from tests/ui/rust-2018/edition-lint-infer-outlives.fixed)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.rs (renamed from tests/ui/rust-2018/edition-lint-infer-outlives.rs)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.stderr (renamed from tests/ui/rust-2018/edition-lint-infer-outlives.stderr)0
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/explicit-outlives-recursive-119228.fixed41
-rw-r--r--tests/ui/rust-2018/edition-lint-inter-outlives/explicit-outlives-recursive-119228.rs41
-rw-r--r--tests/ui/specialization/const_trait_impl.stderr10
-rw-r--r--tests/ui/try-trait/try-operator-custom.rs3
-rw-r--r--tests/ui/typeck/issue-36708.stderr2
-rw-r--r--tests/ui/uninhabited/exhaustive-wo-nevertype-issue-51221.rs2
-rw-r--r--tests/ui/uninhabited/uninhabited-irrefutable.exhaustive_patterns.stderr4
-rw-r--r--tests/ui/uninhabited/uninhabited-irrefutable.normal.stderr26
-rw-r--r--tests/ui/uninhabited/uninhabited-irrefutable.rs3
-rw-r--r--tests/ui/uninhabited/uninhabited-matches-feature-gated.rs7
-rw-r--r--tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr66
-rw-r--r--tests/ui/uninhabited/uninhabited-patterns.rs1
-rw-r--r--tests/ui/uninhabited/uninhabited-patterns.stderr8
314 files changed, 3625 insertions, 2406 deletions
diff --git a/.gitignore b/.gitignore
index f2cdd8762f2..a36cb51de33 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,6 +20,8 @@ Session.vim
 .vscode
 .project
 .vim/
+.helix/
+.zed/
 .favorites.json
 .settings/
 .vs/
diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs
index 29766fc9d87..e9a7397557e 100644
--- a/compiler/rustc/src/main.rs
+++ b/compiler/rustc/src/main.rs
@@ -1,3 +1,6 @@
+// We need this feature as it changes `dylib` linking behavior and allows us to link to `rustc_driver`.
+#![feature(rustc_private)]
+
 // A note about jemalloc: rustc uses jemalloc when built for CI and
 // distribution. The obvious way to do this is with the `#[global_allocator]`
 // mechanism. However, for complicated reasons (see
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index fc1af3fc3dd..a44ed828504 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -585,7 +585,9 @@ impl Pat {
             }
             // A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array,
             // when `P` can be reparsed as a type `T`.
-            PatKind::Slice(pats) if pats.len() == 1 => pats[0].to_ty().map(TyKind::Slice)?,
+            PatKind::Slice(pats) if let [pat] = pats.as_slice() => {
+                pat.to_ty().map(TyKind::Slice)?
+            }
             // A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)`
             // assuming `T0` to `Tn` are all syntactically valid as types.
             PatKind::Tuple(pats) => {
@@ -1187,8 +1189,8 @@ impl Expr {
     /// Does not ensure that the path resolves to a const param, the caller should check this.
     pub fn is_potential_trivial_const_arg(&self) -> bool {
         let this = if let ExprKind::Block(block, None) = &self.kind
-            && block.stmts.len() == 1
-            && let StmtKind::Expr(expr) = &block.stmts[0].kind
+            && let [stmt] = block.stmts.as_slice()
+            && let StmtKind::Expr(expr) = &stmt.kind
         {
             expr
         } else {
@@ -1248,7 +1250,9 @@ impl Expr {
                 expr.to_ty().map(|ty| TyKind::Array(ty, expr_len.clone()))?
             }
 
-            ExprKind::Array(exprs) if exprs.len() == 1 => exprs[0].to_ty().map(TyKind::Slice)?,
+            ExprKind::Array(exprs) if let [expr] = exprs.as_slice() => {
+                expr.to_ty().map(TyKind::Slice)?
+            }
 
             ExprKind::Tup(exprs) => {
                 let tys = exprs.iter().map(|expr| expr.to_ty()).collect::<Option<ThinVec<_>>>()?;
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index 9ed93d481e7..0a7f75039f6 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -167,11 +167,23 @@ ast_lowering_template_modifier = template modifier
 
 ast_lowering_this_not_async = this is not `async`
 
+ast_lowering_underscore_array_length_unstable =
+    using `_` for array lengths is unstable
+
 ast_lowering_underscore_expr_lhs_assign =
     in expressions, `_` can only be used on the left-hand side of an assignment
     .label = `_` not allowed here
 
+ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture
+ast_lowering_unstable_inline_assembly_const_operands =
+    const operands for inline assembly are unstable
+ast_lowering_unstable_inline_assembly_label_operands =
+    label operands for inline assembly are unstable
+ast_lowering_unstable_may_unwind = the `may_unwind` option is unstable
+
 ast_lowering_use_angle_brackets = use angle brackets instead
+
+ast_lowering_yield = yield syntax is experimental
 ast_lowering_yield_in_closure =
     `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
     .suggestion = use `#[coroutine]` to make this closure a coroutine
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index ea7b8c114f4..8acca78379b 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -19,10 +19,12 @@ use super::errors::{
     InvalidRegisterClass, RegisterClassOnlyClobber, RegisterConflict,
 };
 use super::LoweringContext;
-use crate::{ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt};
+use crate::{
+    fluent_generated as fluent, ImplTraitContext, ImplTraitPosition, ParamMode,
+    ResolverAstLoweringExt,
+};
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     pub(crate) fn lower_inline_asm(
         &mut self,
         sp: Span,
@@ -52,7 +54,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     &self.tcx.sess,
                     sym::asm_experimental_arch,
                     sp,
-                    "inline assembly is not stable yet on this architecture",
+                    fluent::ast_lowering_unstable_inline_assembly,
                 )
                 .emit();
             }
@@ -64,8 +66,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             self.dcx().emit_err(AttSyntaxOnlyX86 { span: sp });
         }
         if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind {
-            feature_err(&self.tcx.sess, sym::asm_unwind, sp, "the `may_unwind` option is unstable")
-                .emit();
+            feature_err(
+                &self.tcx.sess,
+                sym::asm_unwind,
+                sp,
+                fluent::ast_lowering_unstable_may_unwind,
+            )
+            .emit();
         }
 
         let mut clobber_abis = FxIndexMap::default();
@@ -182,7 +189,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                 sess,
                                 sym::asm_const,
                                 *op_sp,
-                                "const operands for inline assembly are unstable",
+                                fluent::ast_lowering_unstable_inline_assembly_const_operands,
                             )
                             .emit();
                         }
@@ -246,7 +253,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                 sess,
                                 sym::asm_goto,
                                 *op_sp,
-                                "label operands for inline assembly are unstable",
+                                fluent::ast_lowering_unstable_inline_assembly_label_operands,
                             )
                             .emit();
                         }
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index 6e8ff72cf87..300bfa101c6 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -275,8 +275,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
     // FIXME(fn_delegation): Alternatives for target expression lowering:
     // https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600.
     fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> {
-        if block.stmts.len() == 1
-            && let StmtKind::Expr(expr) = &block.stmts[0].kind
+        if let [stmt] = block.stmts.as_slice()
+            && let StmtKind::Expr(expr) = &stmt.kind
         {
             return self.lower_expr_mut(expr);
         }
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 124fe6bd380..b5d8a547a8f 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -23,7 +23,7 @@ use super::{
     ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs, ResolverAstLoweringExt,
 };
 use crate::errors::YieldInClosure;
-use crate::{FnDeclKind, ImplTraitPosition};
+use crate::{fluent_generated, FnDeclKind, ImplTraitPosition};
 
 impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
@@ -1540,7 +1540,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
         }
     }
 
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
         let yielded =
             opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span));
@@ -1575,7 +1574,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         &self.tcx.sess,
                         sym::coroutines,
                         span,
-                        "yield syntax is experimental",
+                        fluent_generated::ast_lowering_yield,
                     )
                     .emit();
                 }
@@ -1587,7 +1586,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         &self.tcx.sess,
                         sym::coroutines,
                         span,
-                        "yield syntax is experimental",
+                        fluent_generated::ast_lowering_yield,
                     )
                     .emit();
                 }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 224787c335b..81d17a9dec2 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -2326,7 +2326,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.expr_block(block)
     }
 
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen<'hir> {
         match c.value.kind {
             ExprKind::Underscore => {
@@ -2340,7 +2339,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         &self.tcx.sess,
                         sym::generic_arg_infer,
                         c.value.span,
-                        "using `_` for array lengths is unstable",
+                        fluent_generated::ast_lowering_underscore_array_length_unstable,
                     )
                     .stash(c.value.span, StashKey::UnderscoreForArrayLengths);
                     hir::ArrayLen::Body(self.lower_anon_const_to_const_arg(c))
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index ee4514758c2..c7ff39d23ed 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -502,8 +502,8 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
                 if !self.is_beginning_of_line() {
                     self.word(" ");
                 }
-                if cmnt.lines.len() == 1 {
-                    self.word(cmnt.lines[0].clone());
+                if let [line] = cmnt.lines.as_slice() {
+                    self.word(line.clone());
                     self.hardbreak()
                 } else {
                     self.visual_align();
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 56204d8835a..85a0b3b2022 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -783,8 +783,8 @@ impl<'a> State<'a> {
                 }
                 if items.is_empty() {
                     self.word("{}");
-                } else if items.len() == 1 {
-                    self.print_use_tree(&items[0].0);
+                } else if let [(item, _)] = items.as_slice() {
+                    self.print_use_tree(item);
                 } else {
                     self.cbox(INDENT_UNIT);
                     self.word("{");
diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl
index eb51e568f81..5d9ac23ec49 100644
--- a/compiler/rustc_attr/messages.ftl
+++ b/compiler/rustc_attr/messages.ftl
@@ -104,6 +104,9 @@ attr_unknown_meta_item =
 attr_unknown_version_literal =
     unknown version literal format, assuming it refers to a future version
 
+attr_unstable_cfg_target_compact =
+    compact `cfg(target(..))` is experimental and subject to change
+
 attr_unsupported_literal_cfg_string =
     literal in `cfg` predicate value must be a string
 attr_unsupported_literal_deprecated_kv_pair =
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 12a19ae5c3d..d057dcfdf9d 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -20,6 +20,7 @@ use rustc_span::hygiene::Transparency;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 
+use crate::fluent_generated;
 use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
 
 /// The version placeholder that recently stabilized features contain inside the
@@ -521,7 +522,6 @@ pub struct Condition {
 }
 
 /// Tests if a cfg-pattern matches the cfg set
-#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
 pub fn cfg_matches(
     cfg: &ast::MetaItem,
     sess: &Session,
@@ -593,7 +593,6 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
 
 /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
 /// evaluate individual items.
-#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
 pub fn eval_condition(
     cfg: &ast::MetaItem,
     sess: &Session,
@@ -665,12 +664,12 @@ pub fn eval_condition(
                         res & eval_condition(mi.meta_item().unwrap(), sess, features, eval)
                     }),
                 sym::not => {
-                    if mis.len() != 1 {
+                    let [mi] = mis.as_slice() else {
                         dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
                         return false;
-                    }
+                    };
 
-                    !eval_condition(mis[0].meta_item().unwrap(), sess, features, eval)
+                    !eval_condition(mi.meta_item().unwrap(), sess, features, eval)
                 }
                 sym::target => {
                     if let Some(features) = features
@@ -680,7 +679,7 @@ pub fn eval_condition(
                             sess,
                             sym::cfg_target_compact,
                             cfg.span,
-                            "compact `cfg(target(..))` is experimental and subject to change",
+                            fluent_generated::attr_unstable_cfg_target_compact,
                         )
                         .emit();
                     }
@@ -1051,10 +1050,10 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                     MetaItemKind::List(nested_items) => {
                         if meta_item.has_name(sym::align) {
                             recognised = true;
-                            if nested_items.len() == 1 {
+                            if let [nested_item] = nested_items.as_slice() {
                                 sess.dcx().emit_err(
                                     session_diagnostics::IncorrectReprFormatExpectInteger {
-                                        span: nested_items[0].span(),
+                                        span: nested_item.span(),
                                     },
                                 );
                             } else {
@@ -1066,10 +1065,10 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                             }
                         } else if meta_item.has_name(sym::packed) {
                             recognised = true;
-                            if nested_items.len() == 1 {
+                            if let [nested_item] = nested_items.as_slice() {
                                 sess.dcx().emit_err(
                                     session_diagnostics::IncorrectReprFormatPackedExpectInteger {
-                                        span: nested_items[0].span(),
+                                        span: nested_item.span(),
                                     },
                                 );
                             } else {
diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl
index c14a617eb91..edb25e12864 100644
--- a/compiler/rustc_borrowck/messages.ftl
+++ b/compiler/rustc_borrowck/messages.ftl
@@ -62,6 +62,9 @@ borrowck_could_not_normalize =
 borrowck_could_not_prove =
     could not prove `{$predicate}`
 
+borrowck_dereference_suggestion =
+    dereference the return value
+
 borrowck_func_take_self_moved_place =
     `{$func}` takes ownership of the receiver `self`, which moves {$place_name}
 
@@ -74,9 +77,24 @@ borrowck_higher_ranked_lifetime_error =
 borrowck_higher_ranked_subtype_error =
     higher-ranked subtype error
 
+borrowck_implicit_static =
+    this has an implicit `'static` lifetime requirement
+
+borrowck_implicit_static_introduced =
+    calling this method introduces the `impl`'s `'static` requirement
+
+borrowck_implicit_static_relax =
+    consider relaxing the implicit `'static` requirement
+
 borrowck_lifetime_constraints_error =
     lifetime may not live long enough
 
+borrowck_limitations_implies_static =
+    due to current limitations in the borrow checker, this implies a `'static` lifetime
+
+borrowck_move_closure_suggestion =
+    consider adding 'move' keyword before the nested closure
+
 borrowck_move_out_place_here =
     {$place} is moved here
 
@@ -163,6 +181,9 @@ borrowck_partial_var_move_by_use_in_coroutine =
         *[false] moved
     } due to use in coroutine
 
+borrowck_restrict_to_static =
+    consider restricting the type parameter to the `'static` lifetime
+
 borrowck_returned_async_block_escaped =
     returns an `async` block that contains a reference to a captured variable, which then escapes the closure body
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index 9356c24d018..de0df347429 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -206,8 +206,8 @@ impl OutlivesSuggestionBuilder {
 
         // If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a
         // list of diagnostics.
-        let mut diag = if suggested.len() == 1 {
-            mbcx.dcx().struct_help(match suggested.last().unwrap() {
+        let mut diag = if let [constraint] = suggested.as_slice() {
+            mbcx.dcx().struct_help(match constraint {
                 SuggestedConstraint::Outlives(a, bs) => {
                     let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect();
                     format!("add bound `{a}: {}`", bs.join(" + "))
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 82df9760d8e..451e8bcb16d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -35,7 +35,7 @@ use crate::session_diagnostics::{
     LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote,
 };
 use crate::universal_regions::DefiningTy;
-use crate::{borrowck_errors, MirBorrowckCtxt};
+use crate::{borrowck_errors, fluent_generated as fluent, MirBorrowckCtxt};
 
 impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
     fn description(&self) -> &'static str {
@@ -198,7 +198,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
     // from higher-ranked trait bounds (HRTB). Try to locate span of the trait
     // and the span which bounded to the trait for adding 'static lifetime suggestion
     #[allow(rustc::diagnostic_outside_of_impl)]
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn suggest_static_lifetime_for_gat_from_hrtb(
         &self,
         diag: &mut Diag<'_>,
@@ -251,23 +250,28 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
         debug!(?hrtb_bounds);
 
         hrtb_bounds.iter().for_each(|bound| {
-            let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else { return; };
-            diag.span_note(
-                *trait_span,
-                "due to current limitations in the borrow checker, this implies a `'static` lifetime"
-            );
-            let Some(generics_fn) = hir.get_generics(self.body.source.def_id().expect_local()) else { return; };
-            let Def(_, trait_res_defid) = trait_ref.path.res else { return; };
+            let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else {
+                return;
+            };
+            diag.span_note(*trait_span, fluent::borrowck_limitations_implies_static);
+            let Some(generics_fn) = hir.get_generics(self.body.source.def_id().expect_local())
+            else {
+                return;
+            };
+            let Def(_, trait_res_defid) = trait_ref.path.res else {
+                return;
+            };
             debug!(?generics_fn);
             generics_fn.predicates.iter().for_each(|predicate| {
-                let BoundPredicate(
-                    WhereBoundPredicate {
-                        span: bounded_span,
-                        bounded_ty,
-                        bounds,
-                        ..
-                    }
-                ) = predicate else { return; };
+                let BoundPredicate(WhereBoundPredicate {
+                    span: bounded_span,
+                    bounded_ty,
+                    bounds,
+                    ..
+                }) = predicate
+                else {
+                    return;
+                };
                 bounds.iter().for_each(|bd| {
                     if let Trait(PolyTraitRef { trait_ref: tr_ref, .. }, _) = bd
                         && let Def(_, res_defid) = tr_ref.path.res
@@ -277,16 +281,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                         && generics_fn.params
                             .iter()
                             .rfind(|param| param.def_id.to_def_id() == defid)
-                            .is_some() {
-                            suggestions.push((bounded_span.shrink_to_hi(), " + 'static".to_string()));
-                        }
+                            .is_some()
+                    {
+                        suggestions.push((bounded_span.shrink_to_hi(), " + 'static".to_string()));
+                    }
                 });
             });
         });
         if suggestions.len() > 0 {
             suggestions.dedup();
             diag.multipart_suggestion_verbose(
-                "consider restricting the type parameter to the `'static` lifetime",
+                fluent::borrowck_restrict_to_static,
                 suggestions,
                 Applicability::MaybeIncorrect,
             );
@@ -976,7 +981,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
     }
 
     #[allow(rustc::diagnostic_outside_of_impl)]
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     #[instrument(skip(self, err), level = "debug")]
     fn suggest_constrain_dyn_trait_in_impl(
         &self,
@@ -994,16 +998,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
             debug!("trait spans found: {:?}", traits);
             for span in &traits {
                 let mut multi_span: MultiSpan = vec![*span].into();
-                multi_span
-                    .push_span_label(*span, "this has an implicit `'static` lifetime requirement");
-                multi_span.push_span_label(
-                    ident.span,
-                    "calling this method introduces the `impl`'s `'static` requirement",
-                );
+                multi_span.push_span_label(*span, fluent::borrowck_implicit_static);
+                multi_span.push_span_label(ident.span, fluent::borrowck_implicit_static_introduced);
                 err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
                 err.span_suggestion_verbose(
                     span.shrink_to_hi(),
-                    "consider relaxing the implicit `'static` requirement",
+                    fluent::borrowck_implicit_static_relax,
                     " + '_",
                     Applicability::MaybeIncorrect,
                 );
@@ -1045,7 +1045,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
     }
 
     #[allow(rustc::diagnostic_outside_of_impl)]
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     /// When encountering a lifetime error caused by the return type of a closure, check the
     /// corresponding trait bound and see if dereferencing the closure return value would satisfy
     /// them. If so, we produce a structured suggestion.
@@ -1166,7 +1165,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
         if ocx.select_all_or_error().is_empty() && count > 0 {
             diag.span_suggestion_verbose(
                 tcx.hir().body(*body).value.peel_blocks().span.shrink_to_lo(),
-                "dereference the return value",
+                fluent::borrowck_dereference_suggestion,
                 "*".repeat(count),
                 Applicability::MachineApplicable,
             );
@@ -1174,7 +1173,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
     }
 
     #[allow(rustc::diagnostic_outside_of_impl)]
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn suggest_move_on_borrowing_closure(&self, diag: &mut Diag<'_>) {
         let map = self.infcx.tcx.hir();
         let body = map.body_owned_by(self.mir_def_id());
@@ -1213,7 +1211,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
         if let Some(closure_span) = closure_span {
             diag.span_suggestion_verbose(
                 closure_span,
-                "consider adding 'move' keyword before the nested closure",
+                fluent::borrowck_move_closure_suggestion,
                 "move ",
                 Applicability::MaybeIncorrect,
             );
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 17439dd3e3e..ed54c0c8662 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -745,10 +745,9 @@ fn expand_preparsed_asm(
             unused_operands.push((args.operands[idx].1, msg));
         }
     }
-    match unused_operands.len() {
-        0 => {}
-        1 => {
-            let (sp, msg) = unused_operands.into_iter().next().unwrap();
+    match unused_operands[..] {
+        [] => {}
+        [(sp, msg)] => {
             ecx.dcx()
                 .struct_span_err(sp, msg)
                 .with_span_label(sp, msg)
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index c8ab8ed681c..c90a9164886 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -378,8 +378,8 @@ impl BlockOrExpr {
                 None => cx.expr_block(cx.block(span, ThinVec::new())),
                 Some(expr) => expr,
             }
-        } else if self.0.len() == 1
-            && let ast::StmtKind::Expr(expr) = &self.0[0].kind
+        } else if let [stmt] = self.0.as_slice()
+            && let ast::StmtKind::Expr(expr) = &stmt.kind
             && self.1.is_none()
         {
             // There's only a single statement expression. Pull it out.
@@ -1273,7 +1273,7 @@ impl<'a> MethodDef<'a> {
                     }
                     FieldlessVariantsStrategy::Default => (),
                 }
-            } else if variants.len() == 1 {
+            } else if let [variant] = variants.as_slice() {
                 // If there is a single variant, we don't need an operation on
                 // the discriminant(s). Just use the most degenerate result.
                 return self.call_substructure_method(
@@ -1281,7 +1281,7 @@ impl<'a> MethodDef<'a> {
                     trait_,
                     type_ident,
                     nonselflike_args,
-                    &EnumMatching(0, &variants[0], Vec::new()),
+                    &EnumMatching(0, variant, Vec::new()),
                 );
             }
         }
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index ff82f0f2da7..f99530cad18 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -180,8 +180,8 @@ fn make_format_args(
                     Ok((mut err, suggested)) => {
                         if !suggested {
                             if let ExprKind::Block(block, None) = &efmt.kind
-                                && block.stmts.len() == 1
-                                && let StmtKind::Expr(expr) = &block.stmts[0].kind
+                                && let [stmt] = block.stmts.as_slice()
+                                && let StmtKind::Expr(expr) = &stmt.kind
                                 && let ExprKind::Path(None, path) = &expr.kind
                                 && path.is_potential_trivial_const_arg()
                             {
@@ -196,8 +196,8 @@ fn make_format_args(
                             } else {
                                 let sugg_fmt = match args.explicit_args().len() {
                                     0 => "{}".to_string(),
-                                    _ => {
-                                        format!("{}{{}}", "{} ".repeat(args.explicit_args().len()))
+                                    count => {
+                                        format!("{}{{}}", "{} ".repeat(count))
                                     }
                                 };
                                 err.span_suggestion(
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index 7d361a9ab2b..e603ac566f4 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -585,6 +585,7 @@ pub enum E2<X> {
     V4,
 }
 
+#[allow(unreachable_patterns)]
 fn check_niche_behavior() {
     if let E1::V2 { .. } = (E1::V1 { f: true }) {
         intrinsics::abort();
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index b21c559e668..29deac60730 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -725,7 +725,8 @@ fn codegen_regular_intrinsic_call<'tcx>(
 
             // Cranelift treats stores as volatile by default
             // FIXME correctly handle unaligned_volatile_store
-            // FIXME actually do nontemporal stores if requested
+            // FIXME actually do nontemporal stores if requested (but do not just emit MOVNT on x86;
+            // see the LLVM backend for details)
             let dest = CPlace::for_ptr(Pointer::new(ptr), val.layout());
             dest.write_cvalue(fx, val);
         }
diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
index 5a7ddc4cd7f..9f096e90220 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
@@ -430,6 +430,7 @@ pub enum E2<X> {
     V4,
 }
 
+#[allow(unreachable_patterns)]
 fn check_niche_behavior () {
     if let E1::V2 { .. } = (E1::V1 { f: true }) {
         intrinsics::abort();
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index a64371a3d89..47b378cc1cd 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -1127,6 +1127,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         self.llbb().add_assignment(self.location, aligned_destination, val);
         // TODO(antoyo): handle align and flags.
         // NOTE: dummy value here since it's never used. FIXME(antoyo): API should not return a value here?
+        // When adding support for NONTEMPORAL, make sure to not just emit MOVNT on x86; see the
+        // LLVM backend for details.
         self.cx.context.new_rvalue_zero(self.type_i32())
     }
 
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index 7a456e1c5d6..dca6b6494f9 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -160,6 +160,11 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         self.context.new_struct_constructor(None, struct_type.as_type(), None, values)
     }
 
+    fn const_vector(&self, values: &[RValue<'gcc>]) -> RValue<'gcc> {
+        let typ = self.type_vector(values[0].get_type(), values.len() as u64);
+        self.context.new_rvalue_from_vector(None, typ, values)
+    }
+
     fn const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option<u64> {
         // TODO(antoyo)
         None
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 1277b7898c2..5ff580e295a 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -430,9 +430,32 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
             i += 1;
             i - 1
         };
+
+        let apply_range_attr = |idx: AttributePlace, scalar: rustc_target::abi::Scalar| {
+            if cx.sess().opts.optimize != config::OptLevel::No
+                && llvm_util::get_version() >= (19, 0, 0)
+                && matches!(scalar.primitive(), Int(..))
+                // If the value is a boolean, the range is 0..2 and that ultimately
+                // become 0..0 when the type becomes i1, which would be rejected
+                // by the LLVM verifier.
+                && !scalar.is_bool()
+                // LLVM also rejects full range.
+                && !scalar.is_always_valid(cx)
+            {
+                attributes::apply_to_llfn(
+                    llfn,
+                    idx,
+                    &[llvm::CreateRangeAttr(cx.llcx, scalar.size(cx), scalar.valid_range(cx))],
+                );
+            }
+        };
+
         match &self.ret.mode {
             PassMode::Direct(attrs) => {
                 attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
+                if let abi::Abi::Scalar(scalar) = self.ret.layout.abi {
+                    apply_range_attr(llvm::AttributePlace::ReturnValue, scalar);
+                }
             }
             PassMode::Indirect { attrs, meta_attrs: _, on_stack } => {
                 assert!(!on_stack);
@@ -471,8 +494,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     );
                     attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[byval]);
                 }
-                PassMode::Direct(attrs)
-                | PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
+                PassMode::Direct(attrs) => {
+                    let i = apply(attrs);
+                    if let abi::Abi::Scalar(scalar) = arg.layout.abi {
+                        apply_range_attr(llvm::AttributePlace::Argument(i), scalar);
+                    }
+                }
+                PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
                     apply(attrs);
                 }
                 PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
@@ -481,8 +509,12 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     apply(meta_attrs);
                 }
                 PassMode::Pair(a, b) => {
-                    apply(a);
-                    apply(b);
+                    let i = apply(a);
+                    let ii = apply(b);
+                    if let abi::Abi::ScalarPair(scalar_a, scalar_b) = arg.layout.abi {
+                        apply_range_attr(llvm::AttributePlace::Argument(i), scalar_a);
+                        apply_range_attr(llvm::AttributePlace::Argument(ii), scalar_b);
+                    }
                 }
                 PassMode::Cast { cast, pad_i32 } => {
                     if *pad_i32 {
@@ -537,15 +569,18 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
             }
             _ => {}
         }
-        if let abi::Abi::Scalar(scalar) = self.ret.layout.abi {
-            // If the value is a boolean, the range is 0..2 and that ultimately
-            // become 0..0 when the type becomes i1, which would be rejected
-            // by the LLVM verifier.
-            if let Int(..) = scalar.primitive() {
-                if !scalar.is_bool() && !scalar.is_always_valid(bx) {
-                    bx.range_metadata(callsite, scalar.valid_range(bx));
-                }
-            }
+        if bx.cx.sess().opts.optimize != config::OptLevel::No
+                && llvm_util::get_version() < (19, 0, 0)
+                && let abi::Abi::Scalar(scalar) = self.ret.layout.abi
+                && matches!(scalar.primitive(), Int(..))
+                // If the value is a boolean, the range is 0..2 and that ultimately
+                // become 0..0 when the type becomes i1, which would be rejected
+                // by the LLVM verifier.
+                && !scalar.is_bool()
+                // LLVM also rejects full range.
+                && !scalar.is_always_valid(bx)
+        {
+            bx.range_metadata(callsite, scalar.valid_range(bx));
         }
         for arg in self.args.iter() {
             match &arg.mode {
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 0f44c5dba5e..cc081f29e12 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -728,13 +728,32 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                 llvm::LLVMSetVolatile(store, llvm::True);
             }
             if flags.contains(MemFlags::NONTEMPORAL) {
-                // According to LLVM [1] building a nontemporal store must
-                // *always* point to a metadata value of the integer 1.
-                //
-                // [1]: https://llvm.org/docs/LangRef.html#store-instruction
-                let one = self.cx.const_i32(1);
-                let node = llvm::LLVMMDNodeInContext(self.cx.llcx, &one, 1);
-                llvm::LLVMSetMetadata(store, llvm::MD_nontemporal as c_uint, node);
+                // Make sure that the current target architectures supports "sane" non-temporal
+                // stores, i.e., non-temporal stores that are equivalent to regular stores except
+                // for performance. LLVM doesn't seem to care about this, and will happily treat
+                // `!nontemporal` stores as-if they were normal stores (for reordering optimizations
+                // etc) even on x86, despite later lowering them to MOVNT which do *not* behave like
+                // regular stores but require special fences.
+                // So we keep a list of architectures where `!nontemporal` is known to be truly just
+                // a hint, and use regular stores everywhere else.
+                // (In the future, we could alternatively ensure that an sfence gets emitted after a sequence of movnt
+                // before any kind of synchronizing operation. But it's not clear how to do that with LLVM.)
+                // For more context, see <https://github.com/rust-lang/rust/issues/114582> and
+                // <https://github.com/llvm/llvm-project/issues/64521>.
+                const WELL_BEHAVED_NONTEMPORAL_ARCHS: &[&str] =
+                    &["aarch64", "arm", "riscv32", "riscv64"];
+
+                let use_nontemporal =
+                    WELL_BEHAVED_NONTEMPORAL_ARCHS.contains(&&*self.cx.tcx.sess.target.arch);
+                if use_nontemporal {
+                    // According to LLVM [1] building a nontemporal store must
+                    // *always* point to a metadata value of the integer 1.
+                    //
+                    // [1]: https://llvm.org/docs/LangRef.html#store-instruction
+                    let one = self.cx.const_i32(1);
+                    let node = llvm::LLVMMDNodeInContext(self.cx.llcx, &one, 1);
+                    llvm::LLVMSetMetadata(store, llvm::MD_nontemporal as c_uint, node);
+                }
             }
             store
         }
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 65f974c5689..a3997900184 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -97,11 +97,6 @@ impl<'ll> CodegenCx<'ll, '_> {
         unsafe { llvm::LLVMConstArray2(ty, elts.as_ptr(), len) }
     }
 
-    pub fn const_vector(&self, elts: &[&'ll Value]) -> &'ll Value {
-        let len = c_uint::try_from(elts.len()).expect("LLVMConstVector elements len overflow");
-        unsafe { llvm::LLVMConstVector(elts.as_ptr(), len) }
-    }
-
     pub fn const_bytes(&self, bytes: &[u8]) -> &'ll Value {
         bytes_in_context(self.llcx, bytes)
     }
@@ -221,6 +216,11 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         struct_in_context(self.llcx, elts, packed)
     }
 
+    fn const_vector(&self, elts: &[&'ll Value]) -> &'ll Value {
+        let len = c_uint::try_from(elts.len()).expect("LLVMConstVector elements len overflow");
+        unsafe { llvm::LLVMConstVector(elts.as_ptr(), len) }
+    }
+
     fn const_to_opt_uint(&self, v: &'ll Value) -> Option<u64> {
         try_as_const_integral(v).and_then(|v| unsafe {
             let mut i = 0u64;
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 80b13c0e1d4..faabbcb020d 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1575,6 +1575,12 @@ extern "C" {
     pub fn LLVMRustCreateAllocSizeAttr(C: &Context, size_arg: u32) -> &Attribute;
     pub fn LLVMRustCreateAllocKindAttr(C: &Context, size_arg: u64) -> &Attribute;
     pub fn LLVMRustCreateMemoryEffectsAttr(C: &Context, effects: MemoryEffects) -> &Attribute;
+    pub fn LLVMRustCreateRangeAttribute(
+        C: &Context,
+        num_bits: c_uint,
+        lower_words: *const u64,
+        upper_words: *const u64,
+    ) -> &Attribute;
 
     // Operations on functions
     pub fn LLVMRustGetOrInsertFunction<'a>(
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index 72691907c0d..d0db350a149 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -8,7 +8,7 @@ use std::string::FromUtf8Error;
 use libc::c_uint;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_llvm::RustString;
-use rustc_target::abi::Align;
+use rustc_target::abi::{Align, Size, WrappingRange};
 
 pub use self::AtomicRmwBinOp::*;
 pub use self::CallConv::*;
@@ -105,6 +105,21 @@ pub fn CreateAllocKindAttr(llcx: &Context, kind_arg: AllocKindFlags) -> &Attribu
     unsafe { LLVMRustCreateAllocKindAttr(llcx, kind_arg.bits()) }
 }
 
+pub fn CreateRangeAttr(llcx: &Context, size: Size, range: WrappingRange) -> &Attribute {
+    let lower = range.start;
+    let upper = range.end.wrapping_add(1);
+    let lower_words = [lower as u64, (lower >> 64) as u64];
+    let upper_words = [upper as u64, (upper >> 64) as u64];
+    unsafe {
+        LLVMRustCreateRangeAttribute(
+            llcx,
+            size.bits().try_into().unwrap(),
+            lower_words.as_ptr(),
+            upper_words.as_ptr(),
+        )
+    }
+}
+
 #[derive(Copy, Clone)]
 pub enum AttributePlace {
     ReturnValue,
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 45a92fd03d5..7bad9d33e7d 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2646,16 +2646,7 @@ fn add_native_libs_from_crate(
             NativeLibKind::Static { bundle, whole_archive } => {
                 if link_static {
                     let bundle = bundle.unwrap_or(true);
-                    let whole_archive = whole_archive == Some(true)
-                        // Backward compatibility case: this can be a rlib (so `+whole-archive`
-                        // cannot be added explicitly if necessary, see the error in `fn link_rlib`)
-                        // compiled as an executable due to `--test`. Use whole-archive implicitly,
-                        // like before the introduction of native lib modifiers.
-                        || (whole_archive == None
-                            && bundle
-                            && cnum == LOCAL_CRATE
-                            && sess.is_test_crate());
-
+                    let whole_archive = whole_archive == Some(true);
                     if bundle && cnum != LOCAL_CRATE {
                         if let Some(filename) = lib.filename {
                             // If rlib contains native libs as archives, they are unpacked to tmpdir.
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index bc3076528da..772adf13ff1 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -923,8 +923,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         // third argument must be constant. This is
                         // checked by the type-checker.
                         if i == 2 && intrinsic.name == sym::simd_shuffle {
+                            // FIXME: the simd_shuffle argument is actually an array,
+                            // not a vector, so we need this special hack to make sure
+                            // it is passed as an immediate. We should pass the
+                            // shuffle indices as a vector instead to avoid this hack.
                             if let mir::Operand::Constant(constant) = &arg.node {
-                                let (llval, ty) = self.simd_shuffle_indices(bx, constant);
+                                let (llval, ty) = self.immediate_const_vector(bx, constant);
                                 return OperandRef {
                                     val: Immediate(llval),
                                     layout: bx.layout_of(ty),
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index f4d974f7036..0aa85b82038 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -1,6 +1,6 @@
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::layout::HasTyCtxt;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, ValTree};
 use rustc_middle::{bug, mir, span_bug};
 use rustc_target::abi::Abi;
 
@@ -28,7 +28,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             .expect("erroneous constant missed by mono item collection")
     }
 
-    /// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
+    /// This is a convenience helper for `immediate_const_vector`. It has the precondition
     /// that the given `constant` is an `Const::Unevaluated` and must be convertible to
     /// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip.
     ///
@@ -59,23 +59,42 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         self.cx.tcx().const_eval_resolve_for_typeck(ty::ParamEnv::reveal_all(), uv, constant.span)
     }
 
-    /// process constant containing SIMD shuffle indices
-    pub fn simd_shuffle_indices(
+    /// process constant containing SIMD shuffle indices & constant vectors
+    pub fn immediate_const_vector(
         &mut self,
         bx: &Bx,
         constant: &mir::ConstOperand<'tcx>,
     ) -> (Bx::Value, Ty<'tcx>) {
         let ty = self.monomorphize(constant.ty());
+        let ty_is_simd = ty.is_simd();
+        // FIXME: ideally we'd assert that this is a SIMD type, but simd_shuffle
+        // in its current form relies on a regular array being passed as an
+        // immediate argument. This hack can be removed once that is fixed.
+        let field_ty = if ty_is_simd {
+            ty.simd_size_and_type(bx.tcx()).1
+        } else {
+            ty.builtin_index().unwrap()
+        };
+
         let val = self
             .eval_unevaluated_mir_constant_to_valtree(constant)
             .ok()
             .map(|x| x.ok())
             .flatten()
             .map(|val| {
-                let field_ty = ty.builtin_index().unwrap();
-                let values: Vec<_> = val
-                    .unwrap_branch()
-                    .iter()
+                // Depending on whether this is a SIMD type with an array field
+                // or a type with many fields (one for each elements), the valtree
+                // is either a single branch with N children, or a root node
+                // with exactly one child which then in turn has many children.
+                // So we look at the first child to determine whether it is a
+                // leaf or whether we have to go one more layer down.
+                let branch_or_leaf = val.unwrap_branch();
+                let first = branch_or_leaf.get(0).unwrap();
+                let field_iter = match first {
+                    ValTree::Branch(_) => first.unwrap_branch().iter(),
+                    ValTree::Leaf(_) => branch_or_leaf.iter(),
+                };
+                let values: Vec<_> = field_iter
                     .map(|field| {
                         if let Some(prim) = field.try_to_scalar() {
                             let layout = bx.layout_of(field_ty);
@@ -84,11 +103,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             };
                             bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout))
                         } else {
-                            bug!("simd shuffle field {:?}", field)
+                            bug!("field is not a scalar {:?}", field)
                         }
                     })
                     .collect();
-                bx.const_struct(&values, false)
+                if ty_is_simd { bx.const_vector(&values) } else { bx.const_struct(&values, false) }
             })
             .unwrap_or_else(|| {
                 bx.tcx().dcx().emit_err(errors::ShuffleIndicesEvaluation { span: constant.span });
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 2bc2d0f70bf..6979478fda1 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -635,7 +635,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 self.codegen_consume(bx, place.as_ref())
             }
 
-            mir::Operand::Constant(ref constant) => self.eval_mir_constant_to_operand(bx, constant),
+            mir::Operand::Constant(ref constant) => {
+                let constant_ty = self.monomorphize(constant.ty());
+                // Most SIMD vector constants should be passed as immediates.
+                // (In particular, some intrinsics really rely on this.)
+                if constant_ty.is_simd() {
+                    // However, some SIMD types do not actually use the vector ABI
+                    // (in particular, packed SIMD types do not). Ensure we exclude those.
+                    let layout = bx.layout_of(constant_ty);
+                    if let Abi::Vector { .. } = layout.abi {
+                        let (llval, ty) = self.immediate_const_vector(bx, constant);
+                        return OperandRef {
+                            val: OperandValue::Immediate(llval),
+                            layout: bx.layout_of(ty),
+                        };
+                    }
+                }
+                self.eval_mir_constant_to_operand(bx, constant)
+            }
         }
     }
 }
diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs
index d93b3e06ca6..c15f1fa8e56 100644
--- a/compiler/rustc_codegen_ssa/src/traits/consts.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs
@@ -30,6 +30,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
 
     fn const_str(&self, s: &str) -> (Self::Value, Self::Value);
     fn const_struct(&self, elts: &[Self::Value], packed: bool) -> Self::Value;
+    fn const_vector(&self, elts: &[Self::Value]) -> Self::Value;
 
     fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;
     fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option<u128>;
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index c64c73b2323..1442f1832b9 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -41,6 +41,8 @@ const_eval_const_context = {$kind ->
     *[other] {""}
 }
 
+const_eval_const_stable = const-stable functions can only call other const-stable functions
+
 const_eval_copy_nonoverlapping_overlapping =
     `copy_nonoverlapping` called on overlapping ranges
 
@@ -201,6 +203,9 @@ const_eval_invalid_vtable_pointer =
 const_eval_invalid_vtable_trait =
     using vtable for trait `{$vtable_trait}` but trait `{$expected_trait}` was expected
 
+const_eval_lazy_lock =
+    consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
+
 const_eval_live_drop =
     destructor of `{$dropped_ty}` cannot be evaluated at compile-time
     .label = the destructor for this type cannot be evaluated in {const_eval_const_context}s
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index f47a2ec8f75..c6361710ac9 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -23,7 +23,7 @@ use rustc_trait_selection::traits::SelectionContext;
 use tracing::debug;
 
 use super::ConstCx;
-use crate::errors;
+use crate::{errors, fluent_generated};
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum Status {
@@ -310,7 +310,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
         }
 
         if let ConstContext::Static(_) = ccx.const_kind() {
-            err.note("consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`");
+            err.note(fluent_generated::const_eval_lazy_lock);
         }
 
         err
@@ -334,7 +334,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
         // FIXME: make this translatable
         #[allow(rustc::untranslatable_diagnostic)]
         if ccx.is_const_stable_const_fn() {
-            err.help("const-stable functions can only call other const-stable functions");
+            err.help(fluent_generated::const_eval_const_stable);
         } else if ccx.tcx.sess.is_nightly_build() {
             if let Some(feature) = feature {
                 err.help(format!("add `#![feature({feature})]` to the crate attributes to enable"));
@@ -605,8 +605,6 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess {
             span,
             format!("referencing statics in {}s is unstable", ccx.const_kind(),),
         );
-        // FIXME: make this translatable
-        #[allow(rustc::untranslatable_diagnostic)]
         err
             .note("`static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.")
             .help("to fix this, the value can be extracted to a `const` and then used.");
diff --git a/compiler/rustc_data_structures/src/transitive_relation.rs b/compiler/rustc_data_structures/src/transitive_relation.rs
index 26b00e0af3a..e81ebb9a4be 100644
--- a/compiler/rustc_data_structures/src/transitive_relation.rs
+++ b/compiler/rustc_data_structures/src/transitive_relation.rs
@@ -203,9 +203,9 @@ impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
     /// exists). See `postdom_upper_bound` for details.
     pub fn mutual_immediate_postdominator(&self, mut mubs: Vec<T>) -> Option<T> {
         loop {
-            match mubs.len() {
-                0 => return None,
-                1 => return Some(mubs[0]),
+            match mubs[..] {
+                [] => return None,
+                [mub] => return Some(mub),
                 _ => {
                     let m = mubs.pop().unwrap();
                     let n = mubs.pop().unwrap();
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index b014fc2dc58..2b7dc040f64 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -338,12 +338,11 @@ fn run_compiler(
             config.input = input;
             true // has input: normal compilation
         }
-        Ok(None) => match matches.free.len() {
-            0 => false, // no input: we will exit early
-            1 => panic!("make_input should have provided valid inputs"),
-            _ => default_early_dcx.early_fatal(format!(
-                "multiple input filenames provided (first two filenames are `{}` and `{}`)",
-                matches.free[0], matches.free[1],
+        Ok(None) => match matches.free.as_slice() {
+            [] => false, // no input: we will exit early
+            [_] => panic!("make_input should have provided valid inputs"),
+            [fst, snd, ..] => default_early_dcx.early_fatal(format!(
+                "multiple input filenames provided (first two filenames are `{fst}` and `{snd}`)"
             )),
         },
     };
@@ -491,34 +490,30 @@ fn make_input(
     early_dcx: &EarlyDiagCtxt,
     free_matches: &[String],
 ) -> Result<Option<Input>, ErrorGuaranteed> {
-    if free_matches.len() == 1 {
-        let ifile = &free_matches[0];
-        if ifile == "-" {
-            let mut src = String::new();
-            if io::stdin().read_to_string(&mut src).is_err() {
-                // Immediately stop compilation if there was an issue reading
-                // the input (for example if the input stream is not UTF-8).
-                let reported = early_dcx
-                    .early_err("couldn't read from stdin, as it did not contain valid UTF-8");
-                return Err(reported);
-            }
-            if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") {
-                let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE").expect(
-                    "when UNSTABLE_RUSTDOC_TEST_PATH is set \
+    let [ifile] = free_matches else { return Ok(None) };
+    if ifile == "-" {
+        let mut src = String::new();
+        if io::stdin().read_to_string(&mut src).is_err() {
+            // Immediately stop compilation if there was an issue reading
+            // the input (for example if the input stream is not UTF-8).
+            let reported =
+                early_dcx.early_err("couldn't read from stdin, as it did not contain valid UTF-8");
+            return Err(reported);
+        }
+        if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") {
+            let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE").expect(
+                "when UNSTABLE_RUSTDOC_TEST_PATH is set \
                                     UNSTABLE_RUSTDOC_TEST_LINE also needs to be set",
-                );
-                let line = isize::from_str_radix(&line, 10)
-                    .expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number");
-                let file_name = FileName::doc_test_source_code(PathBuf::from(path), line);
-                Ok(Some(Input::Str { name: file_name, input: src }))
-            } else {
-                Ok(Some(Input::Str { name: FileName::anon_source_code(&src), input: src }))
-            }
+            );
+            let line = isize::from_str_radix(&line, 10)
+                .expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number");
+            let file_name = FileName::doc_test_source_code(PathBuf::from(path), line);
+            Ok(Some(Input::Str { name: file_name, input: src }))
         } else {
-            Ok(Some(Input::File(PathBuf::from(ifile))))
+            Ok(Some(Input::Str { name: FileName::anon_source_code(&src), input: src }))
         }
     } else {
-        Ok(None)
+        Ok(Some(Input::File(PathBuf::from(ifile))))
     }
 }
 
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index 3e22786a01f..9e3bc3e60b1 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -66,6 +66,7 @@ macro_rules! into_diag_arg_for_number {
             impl IntoDiagArg for $ty {
                 fn into_diag_arg(self) -> DiagArgValue {
                     // Convert to a string if it won't fit into `Number`.
+                    #[allow(irrefutable_let_patterns)]
                     if let Ok(n) = TryInto::<i32>::try_into(self) {
                         DiagArgValue::Number(n)
                     } else {
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index b8813ea4125..9ce5d77ef6c 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -226,17 +226,17 @@ pub trait Emitter: Translate {
     ) {
         if let Some((sugg, rest)) = suggestions.split_first() {
             let msg = self.translate_message(&sugg.msg, fluent_args).map_err(Report::new).unwrap();
-            if rest.is_empty() &&
+            if rest.is_empty()
                // ^ if there is only one suggestion
                // don't display multi-suggestions as labels
-               sugg.substitutions.len() == 1 &&
+               && let [substitution] = sugg.substitutions.as_slice()
                // don't display multipart suggestions as labels
-               sugg.substitutions[0].parts.len() == 1 &&
+               && let [part] = substitution.parts.as_slice()
                // don't display long messages as labels
-               msg.split_whitespace().count() < 10 &&
+               && msg.split_whitespace().count() < 10
                // don't display multiline suggestions as labels
-               !sugg.substitutions[0].parts[0].snippet.contains('\n') &&
-               ![
+               && !part.snippet.contains('\n')
+               && ![
                     // when this style is set we want the suggestion to be a message, not inline
                     SuggestionStyle::HideCodeAlways,
                     // trivial suggestion for tooling's sake, never shown
@@ -245,8 +245,8 @@ pub trait Emitter: Translate {
                     SuggestionStyle::ShowAlways,
                ].contains(&sugg.style)
             {
-                let substitution = &sugg.substitutions[0].parts[0].snippet.trim();
-                let msg = if substitution.is_empty() || sugg.style.hide_inline() {
+                let snippet = part.snippet.trim();
+                let msg = if snippet.is_empty() || sugg.style.hide_inline() {
                     // This substitution is only removal OR we explicitly don't want to show the
                     // code inline (`hide_inline`). Therefore, we don't show the substitution.
                     format!("help: {msg}")
@@ -255,19 +255,18 @@ pub trait Emitter: Translate {
                     format!(
                         "help: {}{}: `{}`",
                         msg,
-                        if self.source_map().is_some_and(|sm| is_case_difference(
-                            sm,
-                            substitution,
-                            sugg.substitutions[0].parts[0].span,
-                        )) {
+                        if self
+                            .source_map()
+                            .is_some_and(|sm| is_case_difference(sm, snippet, part.span,))
+                        {
                             " (notice the capitalization)"
                         } else {
                             ""
                         },
-                        substitution,
+                        snippet,
                     )
                 };
-                primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg);
+                primary_span.push_span_label(part.span, msg);
 
                 // We return only the modified primary_span
                 suggestions.clear();
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index ceebcd46a6f..aefbf05a1fc 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -2024,11 +2024,11 @@ pub fn a_or_an(s: &str) -> &'static str {
 ///
 /// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c"
 pub fn display_list_with_comma_and<T: std::fmt::Display>(v: &[T]) -> String {
-    match v.len() {
-        0 => "".to_string(),
-        1 => v[0].to_string(),
-        2 => format!("{} and {}", v[0], v[1]),
-        _ => format!("{}, {}", v[0], display_list_with_comma_and(&v[1..])),
+    match v {
+        [] => "".to_string(),
+        [a] => a.to_string(),
+        [a, b] => format!("{a} and {b}"),
+        [a, v @ ..] => format!("{a}, {}", display_list_with_comma_and(v)),
     }
 }
 
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 18d95a398fd..766d96e268f 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -129,6 +129,9 @@ expand_module_multiple_candidates =
 expand_must_repeat_once =
     this must repeat at least once
 
+expand_non_inline_modules_in_proc_macro_input_are_unstable =
+    non-inline modules in proc macro input are unstable
+
 expand_not_a_meta_item =
     not a meta item
 
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index c195d692588..8f9104135cd 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1306,12 +1306,12 @@ pub fn parse_macro_name_and_helper_attrs(
     // that it's of the form `#[proc_macro_derive(Foo)]` or
     // `#[proc_macro_derive(Foo, attributes(A, ..))]`
     let list = attr.meta_item_list()?;
-    if list.len() != 1 && list.len() != 2 {
+    let ([trait_attr] | [trait_attr, _]) = list.as_slice() else {
         dcx.emit_err(errors::AttrNoArguments { span: attr.span });
         return None;
-    }
-    let Some(trait_attr) = list[0].meta_item() else {
-        dcx.emit_err(errors::NotAMetaItem { span: list[0].span() });
+    };
+    let Some(trait_attr) = trait_attr.meta_item() else {
+        dcx.emit_err(errors::NotAMetaItem { span: trait_attr.span() });
         return None;
     };
     let trait_ident = match trait_attr.ident() {
@@ -1398,8 +1398,6 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) {
         };
 
         if crate_matches {
-            // FIXME: make this translatable
-            #[allow(rustc::untranslatable_diagnostic)]
             sess.dcx().emit_fatal(errors::ProcMacroBackCompat {
                 crate_name: "rental".to_string(),
                 fixed_version: "0.5.6".to_string(),
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index d8cb367e3fa..37679e17b90 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -39,6 +39,7 @@ use crate::errors::{
     RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported, UnsupportedKeyValue,
     WrongFragmentKind,
 };
+use crate::fluent_generated;
 use crate::mbe::diagnostics::annotate_err_with_kind;
 use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
 use crate::placeholders::{placeholder, PlaceholderExpander};
@@ -882,7 +883,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         }
 
         impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> {
-            #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
             fn visit_item(&mut self, item: &'ast ast::Item) {
                 match &item.kind {
                     ItemKind::Mod(_, mod_kind)
@@ -892,7 +892,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                             self.sess,
                             sym::proc_macro_hygiene,
                             item.span,
-                            "non-inline modules in proc macro input are unstable",
+                            fluent_generated::expand_non_inline_modules_in_proc_macro_input_are_unstable,
                         )
                         .emit();
                     }
@@ -1876,7 +1876,6 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
 
     // Detect use of feature-gated or invalid attributes on macro invocations
     // since they will not be detected after macro expansion.
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
         let features = self.cx.ecfg.features;
         let mut attrs = attrs.iter().peekable();
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index e42a655531b..44286cfeeef 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -267,6 +267,8 @@ declare_features! (
     (accepted, min_const_generics, "1.51.0", Some(74878)),
     /// Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions.
     (accepted, min_const_unsafe_fn, "1.33.0", Some(55607)),
+    /// Allows exhaustive pattern matching on uninhabited types when matched by value.
+    (accepted, min_exhaustive_patterns, "CURRENT_RUSTC_VERSION", Some(119612)),
     /// Allows using `Self` and associated types in struct expressions and patterns.
     (accepted, more_struct_aliases, "1.16.0", Some(37544)),
     /// Allows using the MOVBE target feature.
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 88a4b5a8382..47810bc9165 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -519,9 +519,6 @@ declare_features! (
     (unstable, macro_metavar_expr_concat, "1.81.0", Some(124225)),
     /// Allows `#[marker]` on certain traits allowing overlapping implementations.
     (unstable, marker_trait_attr, "1.30.0", Some(29864)),
-    /// Allows exhaustive pattern matching on types that contain uninhabited types in cases that are
-    /// unambiguously sound.
-    (unstable, min_exhaustive_patterns, "1.77.0", Some(119612)),
     /// A minimal, sound subset of specialization intended to be used by the
     /// standard library until the soundness issues with specialization
     /// are fixed.
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 53cde14f337..35577613800 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -1117,7 +1117,7 @@ fn check_region_bounds_on_impl_item<'tcx>(
             .dcx()
             .create_err(LifetimesOrBoundsMismatchOnTrait {
                 span,
-                item_kind: assoc_item_kind_str(&impl_m),
+                item_kind: impl_m.descr(),
                 ident: impl_m.ident(tcx),
                 generics_span,
                 bounds_span,
@@ -1294,7 +1294,7 @@ fn compare_number_of_generics<'tcx>(
         ("const", trait_own_counts.consts, impl_own_counts.consts),
     ];
 
-    let item_kind = assoc_item_kind_str(&impl_);
+    let item_kind = impl_.descr();
 
     let mut err_occurred = None;
     for (kind, trait_count, impl_count) in matchings {
@@ -1676,7 +1676,7 @@ fn compare_generic_param_kinds<'tcx>(
                 param_impl_span,
                 E0053,
                 "{} `{}` has an incompatible generic parameter for trait `{}`",
-                assoc_item_kind_str(&impl_item),
+                impl_item.descr(),
                 trait_item.name,
                 &tcx.def_path_str(tcx.parent(trait_item.def_id))
             );
@@ -2249,14 +2249,6 @@ fn param_env_with_gat_bounds<'tcx>(
     ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing)
 }
 
-fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
-    match impl_item.kind {
-        ty::AssocKind::Const => "const",
-        ty::AssocKind::Fn => "method",
-        ty::AssocKind::Type => "type",
-    }
-}
-
 /// Manually check here that `async fn foo()` wasn't matched against `fn foo()`,
 /// and extract a better error if so.
 fn try_report_async_mismatch<'tcx>(
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 47ff748547a..8c1e5e78b75 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -67,6 +67,7 @@ pub fn provide(providers: &mut Providers) {
         item_super_predicates: item_bounds::item_super_predicates,
         explicit_item_super_predicates: item_bounds::explicit_item_super_predicates,
         item_non_self_assumptions: item_bounds::item_non_self_assumptions,
+        impl_super_outlives: item_bounds::impl_super_outlives,
         generics_of: generics_of::generics_of,
         predicates_of: predicates_of::predicates_of,
         predicates_defined_on,
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 6bff99ea65f..ec48c781c0e 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -212,6 +212,8 @@ pub(super) fn item_super_predicates(
     })
 }
 
+/// This exists as an optimization to compute only the item bounds of the item
+/// that are not `Self` bounds.
 pub(super) fn item_non_self_assumptions(
     tcx: TyCtxt<'_>,
     def_id: DefId,
@@ -226,6 +228,25 @@ pub(super) fn item_non_self_assumptions(
     }
 }
 
+/// This exists as an optimization to compute only the supertraits of this impl's
+/// trait that are outlives bounds.
+pub(super) fn impl_super_outlives(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
+    tcx.impl_trait_header(def_id).expect("expected an impl of trait").trait_ref.map_bound(
+        |trait_ref| {
+            let clause: ty::Clause<'_> = trait_ref.upcast(tcx);
+            tcx.mk_clauses_from_iter(util::elaborate(tcx, [clause]).filter(|clause| {
+                matches!(
+                    clause.kind().skip_binder(),
+                    ty::ClauseKind::TypeOutlives(_) | ty::ClauseKind::RegionOutlives(_)
+                )
+            }))
+        },
+    )
+}
+
 struct AssocTyToOpaque<'tcx> {
     tcx: TyCtxt<'tcx>,
     fn_def_id: DefId,
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index d6ff0cb9462..fec6efdc0f7 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -2743,15 +2743,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         } else if let ty::RawPtr(ptr_ty, _) = expr_t.kind()
             && let ty::Adt(adt_def, _) = ptr_ty.kind()
             && let ExprKind::Field(base_expr, _) = expr.kind
-            && adt_def.variants().len() == 1
-            && adt_def
-                .variants()
-                .iter()
-                .next()
-                .unwrap()
-                .fields
-                .iter()
-                .any(|f| f.ident(self.tcx) == field)
+            && let [variant] = &adt_def.variants().raw
+            && variant.fields.iter().any(|f| f.ident(self.tcx) == field)
         {
             err.multipart_suggestion(
                 "to access the field, dereference first",
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index f14159dc35a..e0c0adac076 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -654,17 +654,17 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
             traits::upcast_choices(self.tcx, source_trait_ref, target_trait_def_id);
 
         // must be exactly one trait ref or we'd get an ambig error etc
-        if upcast_trait_refs.len() != 1 {
+        let [upcast_trait_ref] = upcast_trait_refs.as_slice() else {
             span_bug!(
                 self.span,
                 "cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
                 source_trait_ref,
                 target_trait_def_id,
                 upcast_trait_refs
-            );
-        }
+            )
+        };
 
-        upcast_trait_refs.into_iter().next().unwrap()
+        *upcast_trait_ref
     }
 
     fn instantiate_binder_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 94133357a3e..61287d98676 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -321,19 +321,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     );
                                 };
                             let suggest_for_privacy =
-                                |err: &mut Diag<'_>, mut msg: String, sugg: Vec<String>| {
-                                    if sugg.len() == 1 {
-                                        let msg = format!("\
+                                |err: &mut Diag<'_>, mut msg: String, suggs: Vec<String>| {
+                                    if let [sugg] = suggs.as_slice() {
+                                        err.help(format!("\
                                             trait `{}` provides `{item_name}` is implemented but not reachable",
-                                            sugg[0].trim()
-                                        );
-                                        err.help(msg);
+                                            sugg.trim(),
+                                        ));
                                     } else {
-                                        msg += &format!(" but {} not reachable", pluralize!("is", sugg.len()));
+                                        msg += &format!(" but {} not reachable", pluralize!("is", suggs.len()));
                                         err.span_suggestions(
                                             span,
                                             msg,
-                                            sugg,
+                                            suggs,
                                             Applicability::MaybeIncorrect,
                                         );
                                     }
@@ -2988,11 +2987,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
         if local_spans.primary_span().is_some() {
-            let msg = if local_preds.len() == 1 {
+            let msg = if let [local_pred] = local_preds.as_slice() {
                 format!(
                     "an implementation of `{}` might be missing for `{}`",
-                    local_preds[0].trait_ref.print_trait_sugared(),
-                    local_preds[0].self_ty()
+                    local_pred.trait_ref.print_trait_sugared(),
+                    local_pred.self_ty()
                 )
             } else {
                 format!(
@@ -3034,11 +3033,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
         if foreign_spans.primary_span().is_some() {
-            let msg = if foreign_preds.len() == 1 {
+            let msg = if let [foreign_pred] = foreign_preds.as_slice() {
                 format!(
                     "the foreign item type `{}` doesn't implement `{}`",
-                    foreign_preds[0].self_ty(),
-                    foreign_preds[0].trait_ref.print_trait_sugared()
+                    foreign_pred.self_ty(),
+                    foreign_pred.trait_ref.print_trait_sugared()
                 )
             } else {
                 format!(
@@ -3388,26 +3387,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
 
             self.suggest_use_candidates(candidates, |accessible_sugg, inaccessible_sugg, span| {
-                let suggest_for_access = |err: &mut Diag<'_>, mut msg: String, sugg: Vec<_>| {
+                let suggest_for_access = |err: &mut Diag<'_>, mut msg: String, suggs: Vec<_>| {
                     msg += &format!(
                         "; perhaps you want to import {one_of}",
-                        one_of = if sugg.len() == 1 { "it" } else { "one of them" },
+                        one_of = if suggs.len() == 1 { "it" } else { "one of them" },
                     );
-                    err.span_suggestions(span, msg, sugg, Applicability::MaybeIncorrect);
+                    err.span_suggestions(span, msg, suggs, Applicability::MaybeIncorrect);
                 };
-                let suggest_for_privacy = |err: &mut Diag<'_>, sugg: Vec<String>| {
+                let suggest_for_privacy = |err: &mut Diag<'_>, suggs: Vec<String>| {
                     let msg = format!(
                         "{this_trait_is} implemented but not reachable",
-                        this_trait_is = if sugg.len() == 1 {
-                            format!("trait `{}` which provides `{item_name}` is", sugg[0].trim())
+                        this_trait_is = if let [sugg] = suggs.as_slice() {
+                            format!("trait `{}` which provides `{item_name}` is", sugg.trim())
                         } else {
                             format!("the following traits which provide `{item_name}` are")
                         }
                     );
-                    if sugg.len() == 1 {
+                    if suggs.len() == 1 {
                         err.help(msg);
                     } else {
-                        err.span_suggestions(span, msg, sugg, Applicability::MaybeIncorrect);
+                        err.span_suggestions(span, msg, suggs, Applicability::MaybeIncorrect);
                     }
                 };
                 if accessible_sugg.is_empty() {
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 6f53b1c9031..761d288a7c2 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -386,7 +386,6 @@ fn get_codegen_sysroot(
     }
 }
 
-#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
 pub(crate) fn check_attr_crate_type(
     sess: &Session,
     attrs: &[ast::Attribute],
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index d8674817cb5..6b36944b208 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1924,14 +1924,13 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN
 impl ExplicitOutlivesRequirements {
     fn lifetimes_outliving_lifetime<'tcx>(
         tcx: TyCtxt<'tcx>,
-        inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)],
+        inferred_outlives: impl Iterator<Item = &'tcx (ty::Clause<'tcx>, Span)>,
         item: DefId,
         lifetime: DefId,
     ) -> Vec<ty::Region<'tcx>> {
         let item_generics = tcx.generics_of(item);
 
         inferred_outlives
-            .iter()
             .filter_map(|(clause, _)| match clause.kind().skip_binder() {
                 ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
                     ty::ReEarlyParam(ebr)
@@ -1947,11 +1946,10 @@ impl ExplicitOutlivesRequirements {
     }
 
     fn lifetimes_outliving_type<'tcx>(
-        inferred_outlives: &'tcx [(ty::Clause<'tcx>, Span)],
+        inferred_outlives: impl Iterator<Item = &'tcx (ty::Clause<'tcx>, Span)>,
         index: u32,
     ) -> Vec<ty::Region<'tcx>> {
         inferred_outlives
-            .iter()
             .filter_map(|(clause, _)| match clause.kind().skip_binder() {
                 ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
                     a.is_param(index).then_some(b)
@@ -2094,7 +2092,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                                 (
                                     Self::lifetimes_outliving_lifetime(
                                         cx.tcx,
-                                        inferred_outlives,
+                                        // don't warn if the inferred span actually came from the predicate we're looking at
+                                        // this happens if the type is recursively defined
+                                        inferred_outlives
+                                            .iter()
+                                            .filter(|(_, span)| !predicate.span.contains(*span)),
                                         item.owner_id.to_def_id(),
                                         region_def_id,
                                     ),
@@ -2116,7 +2118,14 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                                     };
                                     let index = ty_generics.param_def_id_to_index[&def_id];
                                     (
-                                        Self::lifetimes_outliving_type(inferred_outlives, index),
+                                        Self::lifetimes_outliving_type(
+                                            // don't warn if the inferred span actually came from the predicate we're looking at
+                                            // this happens if the type is recursively defined
+                                            inferred_outlives.iter().filter(|(_, span)| {
+                                                !predicate.span.contains(*span)
+                                            }),
+                                            index,
+                                        ),
                                         &predicate.bounds,
                                         predicate.span,
                                         predicate.origin == PredicateOrigin::WhereClause,
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 72920fd045f..44117e5d7a5 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -717,7 +717,6 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
         };
     }
 
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn add(&mut self, attrs: &[ast::Attribute], is_crate_node: bool, source_hir_id: Option<HirId>) {
         let sess = self.sess;
         for (attr_index, attr) in attrs.iter().enumerate() {
@@ -1039,7 +1038,6 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
             let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
             // FIXME: make this translatable
             #[allow(rustc::diagnostic_outside_of_impl)]
-            #[allow(rustc::untranslatable_diagnostic)]
             lint_level(self.sess, lint, level, src, Some(span.into()), |lint| {
                 lint.primary_message(fluent::lint_unknown_gated_lint);
                 lint.arg("name", lint_id.lint.name_lower());
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index ce7d203d8c0..d7fd41c0ad7 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -527,11 +527,11 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
         // Lint for constants that look like binding identifiers (#7526)
         if let PatKind::Path(hir::QPath::Resolved(None, path)) = p.kind {
             if let Res::Def(DefKind::Const, _) = path.res {
-                if path.segments.len() == 1 {
+                if let [segment] = path.segments {
                     NonUpperCaseGlobals::check_upper_case(
                         cx,
                         "constant in pattern",
-                        &path.segments[0].ident,
+                        &segment.ident,
                     );
                 }
             }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 5b17c0d718a..51896da893c 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -211,15 +211,12 @@ fn lint_overflowing_range_endpoint<'tcx>(
     if !is_range_literal(struct_expr) {
         return false;
     };
-    let ExprKind::Struct(_, eps, _) = &struct_expr.kind else { return false };
-    if eps.len() != 2 {
-        return false;
-    }
+    let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else { return false };
 
     // We can suggest using an inclusive range
     // (`..=`) instead only if it is the `end` that is
     // overflowing and only by 1.
-    if !(eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max) {
+    if !(end.expr.hir_id == expr.hir_id && lit_val - 1 == max) {
         return false;
     };
 
@@ -232,7 +229,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
     };
 
     let sub_sugg = if expr.span.lo() == lit_span.lo() {
-        let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) else { return false };
+        let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else { return false };
         UseInclusiveRange::WithoutParen {
             sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()),
             start,
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index e2c05129ee2..553d9db12c5 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -808,7 +808,7 @@ trait UnusedDelimLint {
             return;
         }
         let spans = match value.kind {
-            ast::ExprKind::Block(ref block, None) if block.stmts.len() == 1 => block.stmts[0]
+            ast::ExprKind::Block(ref block, None) if let [stmt] = block.stmts.as_slice() => stmt
                 .span
                 .find_ancestor_inside(value.span)
                 .map(|span| (value.span.with_hi(span.lo()), value.span.with_lo(span.hi()))),
@@ -1544,14 +1544,12 @@ impl UnusedImportBraces {
             }
 
             // Trigger the lint only if there is one nested item
-            if items.len() != 1 {
-                return;
-            }
+            let [(tree, _)] = items.as_slice() else { return };
 
             // Trigger the lint if the nested item is a non-self single item
-            let node_name = match items[0].0.kind {
+            let node_name = match tree.kind {
                 ast::UseTreeKind::Simple(rename) => {
-                    let orig_ident = items[0].0.prefix.segments.last().unwrap().ident;
+                    let orig_ident = tree.prefix.segments.last().unwrap().ident;
                     if orig_ident.name == kw::SelfLower {
                         return;
                     }
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 2ff7335a0fc..79a68b2ff0e 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -397,6 +397,18 @@ LLVMRustCreateAllocSizeAttr(LLVMContextRef C, uint32_t ElementSizeArg) {
                                               std::nullopt));
 }
 
+extern "C" LLVMAttributeRef
+LLVMRustCreateRangeAttribute(LLVMContextRef C, unsigned NumBits,
+                             const uint64_t LowerWords[],
+                             const uint64_t UpperWords[]) {
+#if LLVM_VERSION_GE(19, 0)
+  return LLVMCreateConstantRangeAttribute(C, Attribute::Range, NumBits,
+                                          LowerWords, UpperWords);
+#else
+  report_fatal_error("LLVM 19.0 is required for Range Attribute");
+#endif
+}
+
 // These values **must** match ffi::AllocKindFlags.
 // It _happens_ to match the LLVM values of llvm::AllocFnKind,
 // but that's happenstance and we do explicit conversions before
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index 415399ed06c..d80aa0cc4f4 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -41,6 +41,9 @@ metadata_crate_dep_multiple =
 metadata_crate_dep_not_static =
     `{$crate_name}` was unavailable as a static crate, preventing fully static linking
 
+metadata_crate_dep_rustc_driver =
+    `feature(rustc_private)` is needed to link to the compiler's `rustc_driver` library
+
 metadata_crate_location_unknown_type =
     extern location for {$crate_name} is of an unknown type: {$path}
 
@@ -131,12 +134,18 @@ metadata_lib_framework_apple =
 metadata_lib_required =
     crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
 
+metadata_link_arg_unstable =
+    link kind `link-arg` is unstable
+
 metadata_link_cfg_form =
     link cfg must be of the form `cfg(/* predicate */)`
 
 metadata_link_cfg_single_predicate =
     link cfg must have a single predicate argument
 
+metadata_link_cfg_unstable =
+    link cfg is unstable
+
 metadata_link_framework_apple =
     link kind `framework` is only supported on Apple targets
 
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 2fca443ffa0..14a1a7f67e5 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -949,7 +949,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         }
     }
 
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn report_unused_deps(&mut self, krate: &ast::Crate) {
         // Make a point span rather than covering the whole file
         let span = krate.spans.inner_span.shrink_to_lo();
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index 17fd260fd79..39fa23766b5 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -51,7 +51,7 @@
 //! Additionally, the algorithm is geared towards finding *any* solution rather
 //! than finding a number of solutions (there are normally quite a few).
 
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::CrateNum;
 use rustc_middle::bug;
 use rustc_middle::middle::dependency_format::{Dependencies, DependencyList, Linkage};
@@ -59,12 +59,14 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::config::CrateType;
 use rustc_session::cstore::CrateDepKind;
 use rustc_session::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic};
+use rustc_span::sym;
 use tracing::info;
 
 use crate::creader::CStore;
 use crate::errors::{
     BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired,
-    NonStaticCrateDep, RequiredPanicStrategy, RlibRequired, RustcLibRequired, TwoPanicRuntimes,
+    NonStaticCrateDep, RequiredPanicStrategy, RlibRequired, RustcDriverHelp, RustcLibRequired,
+    TwoPanicRuntimes,
 };
 
 pub(crate) fn calculate(tcx: TyCtxt<'_>) -> Dependencies {
@@ -160,25 +162,49 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
         Linkage::Dynamic | Linkage::IncludedFromDylib => {}
     }
 
+    let all_dylibs = || {
+        tcx.crates(()).iter().filter(|&&cnum| {
+            !tcx.dep_kind(cnum).macros_only() && tcx.used_crate_source(cnum).dylib.is_some()
+        })
+    };
+
+    let mut upstream_in_dylibs = FxHashSet::default();
+
+    if tcx.features().rustc_private {
+        // We need this to prevent users of `rustc_driver` from linking dynamically to `std`
+        // which does not work as `std` is also statically linked into `rustc_driver`.
+
+        // Find all libraries statically linked to upstream dylibs.
+        for &cnum in all_dylibs() {
+            let deps = tcx.dylib_dependency_formats(cnum);
+            for &(depnum, style) in deps.iter() {
+                if let RequireStatic = style {
+                    upstream_in_dylibs.insert(depnum);
+                }
+            }
+        }
+    }
+
     let mut formats = FxHashMap::default();
 
     // Sweep all crates for found dylibs. Add all dylibs, as well as their
     // dependencies, ensuring there are no conflicts. The only valid case for a
     // dependency to be relied upon twice is for both cases to rely on a dylib.
-    for &cnum in tcx.crates(()).iter() {
-        if tcx.dep_kind(cnum).macros_only() {
+    for &cnum in all_dylibs() {
+        if upstream_in_dylibs.contains(&cnum) {
+            info!("skipping dylib: {}", tcx.crate_name(cnum));
+            // If this dylib is also available statically linked to another dylib
+            // we try to use that instead.
             continue;
         }
+
         let name = tcx.crate_name(cnum);
-        let src = tcx.used_crate_source(cnum);
-        if src.dylib.is_some() {
-            info!("adding dylib: {}", name);
-            add_library(tcx, cnum, RequireDynamic, &mut formats, &mut unavailable_as_static);
-            let deps = tcx.dylib_dependency_formats(cnum);
-            for &(depnum, style) in deps.iter() {
-                info!("adding {:?}: {}", style, tcx.crate_name(depnum));
-                add_library(tcx, depnum, style, &mut formats, &mut unavailable_as_static);
-            }
+        info!("adding dylib: {}", name);
+        add_library(tcx, cnum, RequireDynamic, &mut formats, &mut unavailable_as_static);
+        let deps = tcx.dylib_dependency_formats(cnum);
+        for &(depnum, style) in deps.iter() {
+            info!("adding {:?}: {}", style, tcx.crate_name(depnum));
+            add_library(tcx, depnum, style, &mut formats, &mut unavailable_as_static);
         }
     }
 
@@ -268,12 +294,15 @@ fn add_library(
             // This error is probably a little obscure, but I imagine that it
             // can be refined over time.
             if link2 != link || link == RequireStatic {
+                let linking_to_rustc_driver = tcx.sess.psess.unstable_features.is_nightly_build()
+                    && tcx.crates(()).iter().any(|&cnum| tcx.crate_name(cnum) == sym::rustc_driver);
                 tcx.dcx().emit_err(CrateDepMultiple {
                     crate_name: tcx.crate_name(cnum),
                     non_static_deps: unavailable_as_static
                         .drain(..)
                         .map(|cnum| NonStaticCrateDep { crate_name: tcx.crate_name(cnum) })
                         .collect(),
+                    rustc_driver_help: linking_to_rustc_driver.then_some(RustcDriverHelp),
                 });
             }
         }
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index 89970dddf9f..42dec978b78 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -38,6 +38,8 @@ pub struct CrateDepMultiple {
     pub crate_name: Symbol,
     #[subdiagnostic]
     pub non_static_deps: Vec<NonStaticCrateDep>,
+    #[subdiagnostic]
+    pub rustc_driver_help: Option<RustcDriverHelp>,
 }
 
 #[derive(Subdiagnostic)]
@@ -46,6 +48,10 @@ pub struct NonStaticCrateDep {
     pub crate_name: Symbol,
 }
 
+#[derive(Subdiagnostic)]
+#[help(metadata_crate_dep_rustc_driver)]
+pub struct RustcDriverHelp;
+
 #[derive(Diagnostic)]
 #[diag(metadata_two_panic_runtimes)]
 pub struct TwoPanicRuntimes {
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index b19493d12ff..34497f5ac53 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -17,7 +17,7 @@ use rustc_span::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
-use crate::errors;
+use crate::{errors, fluent_generated};
 
 pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> PathBuf {
     let formats = if verbatim {
@@ -87,7 +87,6 @@ struct Collector<'tcx> {
 }
 
 impl<'tcx> Collector<'tcx> {
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn process_module(&mut self, module: &ForeignModule) {
         let ForeignModule { def_id, abi, ref foreign_items } = *module;
         let def_id = def_id.expect_local();
@@ -161,7 +160,7 @@ impl<'tcx> Collector<'tcx> {
                                         sess,
                                         sym::link_arg_attribute,
                                         span,
-                                        "link kind `link-arg` is unstable",
+                                        fluent_generated::metadata_link_arg_unstable,
                                     )
                                     .emit();
                                 }
@@ -201,8 +200,13 @@ impl<'tcx> Collector<'tcx> {
                             continue;
                         };
                         if !features.link_cfg {
-                            feature_err(sess, sym::link_cfg, item.span(), "link cfg is unstable")
-                                .emit();
+                            feature_err(
+                                sess,
+                                sym::link_cfg,
+                                item.span(),
+                                fluent_generated::metadata_link_cfg_unstable,
+                            )
+                            .emit();
                         }
                         cfg = Some(link_cfg.clone());
                     }
@@ -266,6 +270,8 @@ impl<'tcx> Collector<'tcx> {
 
                     macro report_unstable_modifier($feature: ident) {
                         if !features.$feature {
+                            // FIXME: make this translatable
+                            #[expect(rustc::untranslatable_diagnostic)]
                             feature_err(
                                 sess,
                                 sym::$feature,
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 4c243e6330b..edab6b5ebde 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -1165,17 +1165,23 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
         }
         Node::ImplItem(ii) => {
             let kind = match ii.kind {
-                ImplItemKind::Const(..) => "assoc const",
-                ImplItemKind::Fn(..) => "method",
-                ImplItemKind::Type(_) => "assoc type",
+                ImplItemKind::Const(..) => "associated constant",
+                ImplItemKind::Fn(fn_sig, _) => match fn_sig.decl.implicit_self {
+                    ImplicitSelfKind::None => "associated function",
+                    _ => "method",
+                },
+                ImplItemKind::Type(_) => "associated type",
             };
             format!("{id} ({kind} `{}` in {})", ii.ident, path_str(ii.owner_id.def_id))
         }
         Node::TraitItem(ti) => {
             let kind = match ti.kind {
-                TraitItemKind::Const(..) => "assoc constant",
-                TraitItemKind::Fn(..) => "trait method",
-                TraitItemKind::Type(..) => "assoc type",
+                TraitItemKind::Const(..) => "associated constant",
+                TraitItemKind::Fn(fn_sig, _) => match fn_sig.decl.implicit_self {
+                    ImplicitSelfKind::None => "associated function",
+                    _ => "trait method",
+                },
+                TraitItemKind::Type(..) => "associated type",
             };
 
             format!("{id} ({kind} `{}` in {})", ti.ident, path_str(ti.owner_id.def_id))
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index b499604df87..5bd7736a3f3 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -28,6 +28,7 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::potential_query_instability)]
 #![allow(rustc::untranslatable_diagnostic)]
+#![cfg_attr(bootstrap, feature(min_exhaustive_patterns))]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(allocator_api)]
@@ -48,7 +49,6 @@
 #![feature(iter_from_coroutine)]
 #![feature(let_chains)]
 #![feature(macro_metavar_expr)]
-#![feature(min_exhaustive_patterns)]
 #![feature(min_specialization)]
 #![feature(negative_impls)]
 #![feature(never_type)]
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 5b114c9515c..075eae02904 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -407,6 +407,10 @@ rustc_queries! {
         desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
     }
 
+    query impl_super_outlives(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
+        desc { |tcx| "elaborating supertrait outlives for trait of `{}`", tcx.def_path_str(key) }
+    }
+
     /// Look up all native libraries this crate depends on.
     /// These are assembled from the following places:
     /// - `extern` blocks (depending on their `link` attributes)
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index 0ce5c613c4c..db56e0016a2 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -98,6 +98,15 @@ impl AssocItem {
         }
     }
 
+    pub fn descr(&self) -> &'static str {
+        match self.kind {
+            ty::AssocKind::Const => "const",
+            ty::AssocKind::Fn if self.fn_has_self_parameter => "method",
+            ty::AssocKind::Fn => "associated function",
+            ty::AssocKind::Type => "type",
+        }
+    }
+
     pub fn is_impl_trait_in_trait(&self) -> bool {
         self.opt_rpitit_info.is_some()
     }
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 39c306a720f..8cb8e9af11c 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -376,7 +376,7 @@ pub struct GenericPredicates<'tcx> {
 
 impl<'tcx> GenericPredicates<'tcx> {
     pub fn instantiate(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         args: GenericArgsRef<'tcx>,
     ) -> InstantiatedPredicates<'tcx> {
@@ -386,20 +386,20 @@ impl<'tcx> GenericPredicates<'tcx> {
     }
 
     pub fn instantiate_own(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         args: GenericArgsRef<'tcx>,
     ) -> impl Iterator<Item = (Clause<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator {
         EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args)
     }
 
-    pub fn instantiate_own_identity(&self) -> impl Iterator<Item = (Clause<'tcx>, Span)> {
+    pub fn instantiate_own_identity(self) -> impl Iterator<Item = (Clause<'tcx>, Span)> {
         EarlyBinder::bind(self.predicates).iter_identity_copied()
     }
 
     #[instrument(level = "debug", skip(self, tcx))]
     fn instantiate_into(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         instantiated: &mut InstantiatedPredicates<'tcx>,
         args: GenericArgsRef<'tcx>,
@@ -413,14 +413,14 @@ impl<'tcx> GenericPredicates<'tcx> {
         instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp));
     }
 
-    pub fn instantiate_identity(&self, tcx: TyCtxt<'tcx>) -> InstantiatedPredicates<'tcx> {
+    pub fn instantiate_identity(self, tcx: TyCtxt<'tcx>) -> InstantiatedPredicates<'tcx> {
         let mut instantiated = InstantiatedPredicates::empty();
         self.instantiate_identity_into(tcx, &mut instantiated);
         instantiated
     }
 
     fn instantiate_identity_into(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         instantiated: &mut InstantiatedPredicates<'tcx>,
     ) {
diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
index 95fec154918..ab2bfcbca3a 100644
--- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
@@ -208,14 +208,11 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
                 subpairs = cx.field_match_pairs(downcast_place, subpatterns);
 
                 let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
-                    i == variant_index || {
-                        (cx.tcx.features().exhaustive_patterns
-                            || cx.tcx.features().min_exhaustive_patterns)
-                            && !v
-                                .inhabited_predicate(cx.tcx, adt_def)
-                                .instantiate(cx.tcx, args)
-                                .apply_ignore_module(cx.tcx, cx.param_env)
-                    }
+                    i == variant_index
+                        || !v
+                            .inhabited_predicate(cx.tcx, adt_def)
+                            .instantiate(cx.tcx, args)
+                            .apply_ignore_module(cx.tcx, cx.param_env)
                 }) && (adt_def.did().is_local()
                     || !adt_def.is_variant_list_non_exhaustive());
                 if irrefutable {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 64c6ff952c6..07bf222fcca 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -483,9 +483,11 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
         // Check if the match is exhaustive.
         let witnesses = report.non_exhaustiveness_witnesses;
         if !witnesses.is_empty() {
-            if source == hir::MatchSource::ForLoopDesugar && arms.len() == 2 {
+            if source == hir::MatchSource::ForLoopDesugar
+                && let [_, snd_arm] = *arms
+            {
                 // the for loop pattern is not irrefutable
-                let pat = &self.thir[arms[1]].pattern;
+                let pat = &self.thir[snd_arm].pattern;
                 // `pat` should be `Some(<pat_field>)` from a desugared for loop.
                 debug_assert_eq!(pat.span.desugaring_kind(), Some(DesugaringKind::ForLoop));
                 let PatKind::Variant { ref subpatterns, .. } = pat.kind else { bug!() };
@@ -695,9 +697,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
 
         // Emit an extra note if the first uncovered witness would be uninhabited
         // if we disregard visibility.
-        let witness_1_is_privately_uninhabited = if (self.tcx.features().exhaustive_patterns
-            || self.tcx.features().min_exhaustive_patterns)
-            && let Some(witness_1) = witnesses.get(0)
+        let witness_1_is_privately_uninhabited = if let Some(witness_1) = witnesses.get(0)
             && let ty::Adt(adt, args) = witness_1.ty().kind()
             && adt.is_enum()
             && let Constructor::Variant(variant_index) = witness_1.ctor()
@@ -1059,7 +1059,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
                 err.note("`&str` cannot be matched exhaustively, so a wildcard `_` is necessary");
             } else if cx.is_foreign_non_exhaustive_enum(ty) {
                 err.note(format!("`{ty}` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively"));
-            } else if cx.is_uninhabited(ty.inner()) && cx.tcx.features().min_exhaustive_patterns {
+            } else if cx.is_uninhabited(ty.inner()) {
                 // The type is uninhabited yet there is a witness: we must be in the `MaybeInvalid`
                 // case.
                 err.note(format!("`{ty}` is uninhabited but is not being matched by value, so a wildcard `_` is required"));
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index c3f4bbf1a65..31b20775194 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -350,8 +350,8 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera
         // An inline asm terminator can normally be chained, except when it diverges or uses asm
         // goto.
         InlineAsm { ref targets, .. } => {
-            if targets.len() == 1 {
-                CoverageSuccessors::Chainable(targets[0])
+            if let [target] = targets[..] {
+                CoverageSuccessors::Chainable(target)
             } else {
                 CoverageSuccessors::NotChainable(targets)
             }
diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index e4fec786814..49e41c35f1f 100644
--- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -309,11 +309,11 @@ fn verify_candidate_branch<'tcx>(
 ) -> bool {
     // In order for the optimization to be correct, the branch must...
     // ...have exactly one statement
-    if branch.statements.len() != 1 {
+    let [statement] = branch.statements.as_slice() else {
         return false;
-    }
+    };
     // ...assign the discriminant of `place` in that statement
-    let StatementKind::Assign(boxed) = &branch.statements[0].kind else { return false };
+    let StatementKind::Assign(boxed) = &statement.kind else { return false };
     let (discr_place, Rvalue::Discriminant(from_place)) = &**boxed else { return false };
     if *from_place != place {
         return false;
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index d955b96d06a..e5778f8a05d 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -116,29 +116,30 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
             for debug_info in body.var_debug_info.iter_mut() {
                 if let VarDebugInfoContents::Place(place) = &mut debug_info.value {
                     let mut new_projections: Option<Vec<_>> = None;
-                    let mut last_deref = 0;
 
-                    for (i, (base, elem)) in place.iter_projections().enumerate() {
+                    for (base, elem) in place.iter_projections() {
                         let base_ty = base.ty(&body.local_decls, tcx).ty;
 
                         if elem == PlaceElem::Deref && base_ty.is_box() {
-                            let new_projections = new_projections.get_or_insert_default();
+                            // Clone the projections before us, since now we need to mutate them.
+                            let new_projections =
+                                new_projections.get_or_insert_with(|| base.projection.to_vec());
 
                             let (unique_ty, nonnull_ty, ptr_ty) =
                                 build_ptr_tys(tcx, base_ty.boxed_ty(), unique_did, nonnull_did);
 
-                            new_projections.extend_from_slice(&base.projection[last_deref..]);
                             new_projections.extend_from_slice(&build_projection(
                                 unique_ty, nonnull_ty, ptr_ty,
                             ));
                             new_projections.push(PlaceElem::Deref);
-
-                            last_deref = i;
+                        } else if let Some(new_projections) = new_projections.as_mut() {
+                            // Keep building up our projections list once we've started it.
+                            new_projections.push(elem);
                         }
                     }
 
-                    if let Some(mut new_projections) = new_projections {
-                        new_projections.extend_from_slice(&place.projection[last_deref..]);
+                    // Store the mutated projections if we actually changed something.
+                    if let Some(new_projections) = new_projections {
                         place.projection = tcx.mk_place_elems(&new_projections);
                     }
                 }
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 2fc5f7e536b..1589653968c 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -264,9 +264,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
         };
 
         // It's definitely not a clone if there are multiple arguments
-        if args.len() != 1 {
-            return;
-        }
+        let [arg] = &args[..] else { return };
 
         let Some(destination_block) = *target else { return };
 
@@ -280,7 +278,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
 
         // These types are easily available from locals, so check that before
         // doing DefId lookups to figure out what we're actually calling.
-        let arg_ty = args[0].node.ty(self.local_decls, self.tcx);
+        let arg_ty = arg.node.ty(self.local_decls, self.tcx);
 
         let ty::Ref(_region, inner_ty, Mutability::Not) = *arg_ty.kind() else { return };
 
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 746d423b7a9..491ae1c0d08 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -898,8 +898,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         self.param_env,
                         adt_def.non_enum_variant().fields[field].ty(self.tcx, args),
                     );
-                    if fields.len() == 1 {
-                        let src_ty = fields.raw[0].ty(self.body, self.tcx);
+                    if let [field] = fields.raw.as_slice() {
+                        let src_ty = field.ty(self.body, self.tcx);
                         if !self.mir_assign_valid_types(src_ty, dest_ty) {
                             self.fail(location, "union field has the wrong type");
                         }
@@ -967,11 +967,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         self.fail(location, "RawPtr should be in runtime MIR only");
                     }
 
-                    if fields.len() != 2 {
-                        self.fail(location, "raw pointer aggregate must have 2 fields");
-                    } else {
-                        let data_ptr_ty = fields.raw[0].ty(self.body, self.tcx);
-                        let metadata_ty = fields.raw[1].ty(self.body, self.tcx);
+                    if let [data_ptr, metadata] = fields.raw.as_slice() {
+                        let data_ptr_ty = data_ptr.ty(self.body, self.tcx);
+                        let metadata_ty = metadata.ty(self.body, self.tcx);
                         if let ty::RawPtr(in_pointee, in_mut) = data_ptr_ty.kind() {
                             if *in_mut != mutability {
                                 self.fail(location, "input and output mutability must match");
@@ -998,6 +996,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                                 self.fail(location, "metadata for pointer-to-thin must be unit");
                             }
                         }
+                    } else {
+                        self.fail(location, "raw pointer aggregate must have 2 fields");
                     }
                 }
             },
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index ccf8dcdf0b6..cf5d65708ab 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -694,12 +694,12 @@ impl<'a> Parser<'a> {
                         // `foo: `
                         ExprKind::Path(None, ast::Path { segments, .. }),
                         token::Ident(kw::For | kw::Loop | kw::While, IdentIsRaw::No),
-                    ) if segments.len() == 1 => {
+                    ) if let [segment] = segments.as_slice() => {
                         let snapshot = self.create_snapshot_for_diagnostic();
                         let label = Label {
                             ident: Ident::from_str_and_span(
-                                &format!("'{}", segments[0].ident),
-                                segments[0].ident.span,
+                                &format!("'{}", segment.ident),
+                                segment.ident.span,
                             ),
                         };
                         match self.parse_expr_labeled(label, false) {
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index baa5eb2df63..8775d792c3d 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -471,9 +471,8 @@ impl<'a> Parser<'a> {
             Err(mut err) => {
                 // Maybe the user misspelled `macro_rules` (issue #91227)
                 if self.token.is_ident()
-                    && path.segments.len() == 1
-                    && edit_distance("macro_rules", &path.segments[0].ident.to_string(), 2)
-                        .is_some()
+                    && let [segment] = path.segments.as_slice()
+                    && edit_distance("macro_rules", &segment.ident.to_string(), 2).is_some()
                 {
                     err.span_suggestion(
                         path.span,
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 70d2c98d4f1..6f82d6b9826 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -826,7 +826,8 @@ impl<'a> Parser<'a> {
             // We can only resolve single-segment paths at the moment, because multi-segment paths
             // require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`.
             ast::ExprKind::Path(None, path)
-                if path.segments.len() == 1 && path.segments[0].args.is_none() =>
+                if let [segment] = path.segments.as_slice()
+                    && segment.args.is_none() =>
             {
                 true
             }
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index a3b782d651d..b206f134f0e 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -676,7 +676,7 @@ impl<'a> Parser<'a> {
 
                             match &expr.kind {
                                 ExprKind::Path(None, ast::Path { segments, .. })
-                                    if segments.len() == 1 =>
+                                    if let [segment] = segments.as_slice() =>
                                 {
                                     if self.token == token::Colon
                                         && self.look_ahead(1, |token| {
@@ -693,8 +693,8 @@ impl<'a> Parser<'a> {
                                         let snapshot = self.create_snapshot_for_diagnostic();
                                         let label = Label {
                                             ident: Ident::from_str_and_span(
-                                                &format!("'{}", segments[0].ident),
-                                                segments[0].ident.span,
+                                                &format!("'{}", segment.ident),
+                                                segment.ident.span,
                                             ),
                                         };
                                         match self.parse_expr_labeled(label, false) {
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 59c9d1e49f5..0318d34fb73 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -223,6 +223,9 @@ passes_doc_masked_only_extern_crate =
     .not_an_extern_crate_label = not an `extern crate` item
     .note = read <https://doc.rust-lang.org/unstable-book/language-features/doc-masked.html> for more information
 
+passes_doc_rust_logo =
+    the `#[doc(rust_logo)]` attribute is used for Rust branding
+
 passes_doc_test_literal = `#![doc(test(...)]` does not take a literal
 
 passes_doc_test_takes_list =
@@ -595,6 +598,9 @@ passes_remove_fields =
      *[other] fields
     }
 
+passes_repr_align_function =
+    `repr(align)` attributes on functions are unstable
+
 passes_repr_conflicting =
     conflicting representation hints
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index c8d4c190113..bd157d1d619 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1142,7 +1142,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     /// of one item. Read the documentation of [`check_doc_inline`] for more information.
     ///
     /// [`check_doc_inline`]: Self::check_doc_inline
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn check_doc_attrs(
         &self,
         attr: &Attribute,
@@ -1220,7 +1219,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                                     &self.tcx.sess,
                                     sym::rustdoc_internals,
                                     meta.span(),
-                                    "the `#[doc(rust_logo)]` attribute is used for Rust branding",
+                                    fluent::passes_doc_rust_logo,
                                 )
                                 .emit();
                             }
@@ -1736,7 +1735,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     }
 
     /// Checks if the `#[repr]` attributes on `item` are valid.
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn check_repr(
         &self,
         attrs: &[Attribute],
@@ -1793,7 +1791,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             &self.tcx.sess,
                             sym::fn_align,
                             hint.span(),
-                            "`repr(align)` attributes on functions are unstable",
+                            fluent::passes_repr_align_function,
                         )
                         .emit();
                     }
@@ -2213,8 +2211,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             attr.name_or_empty(),
             sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
         ) && let Some(meta) = attr.meta_item_list()
-            && meta.len() == 1
-            && let Some(item) = meta[0].meta_item()
+            && let [meta] = meta.as_slice()
+            && let Some(item) = meta.meta_item()
             && let MetaItemKind::NameValue(_) = &item.kind
             && item.path == sym::reason
         {
diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
index 0537d3a69f6..5d871bacb1d 100644
--- a/compiler/rustc_passes/src/debugger_visualizer.rs
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -19,9 +19,7 @@ impl DebuggerVisualizerCollector<'_> {
                 return;
             };
 
-            let hint = if hints.len() == 1 {
-                &hints[0]
-            } else {
+            let [hint] = hints.as_slice() else {
                 self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
                 return;
             };
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index 48f55d4c3a0..ecb345bb51a 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -106,7 +106,6 @@ fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
     }
 }
 
-#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
 fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> {
     if let Some((def_id, _)) = visitor.start_fn {
         Some((def_id.to_def_id(), EntryFnType::Start))
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index a5c0b13c90b..6c9c848bb10 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -5,6 +5,7 @@
 // tidy-alphabetical-start
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
+#![cfg_attr(feature = "rustc", feature(let_chains))]
 // tidy-alphabetical-end
 
 pub mod constructor;
@@ -54,7 +55,6 @@ pub trait PatCx: Sized + fmt::Debug {
     type PatData: Clone;
 
     fn is_exhaustive_patterns_feature_on(&self) -> bool;
-    fn is_min_exhaustive_patterns_feature_on(&self) -> bool;
 
     /// The number of fields for this constructor.
     fn ctor_arity(&self, ctor: &Constructor<Self>, ty: &Self::Ty) -> usize;
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 6290aeb2523..10b7968a1a7 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -23,6 +23,7 @@ use crate::constructor::{
 };
 use crate::lints::lint_nonexhaustive_missing_variants;
 use crate::pat_column::PatternColumn;
+use crate::rustc::print::EnumInfo;
 use crate::usefulness::{compute_match_usefulness, PlaceValidity};
 use crate::{errors, Captures, PatCx, PrivateUninhabitedField};
 
@@ -237,9 +238,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                         let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
                             let is_visible =
                                 adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
-                            let is_uninhabited = (cx.tcx.features().exhaustive_patterns
-                                || cx.tcx.features().min_exhaustive_patterns)
-                                && cx.is_uninhabited(*ty);
+                            let is_uninhabited = cx.is_uninhabited(*ty);
                             let skip = is_uninhabited && (!is_visible || is_non_exhaustive);
                             (ty, PrivateUninhabitedField(skip))
                         });
@@ -826,77 +825,64 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
     fn hoist_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> print::Pat<'tcx> {
         use print::{FieldPat, Pat, PatKind};
         let cx = self;
-        let is_wildcard = |pat: &Pat<'_>| matches!(pat.kind, PatKind::Wild);
-        let mut subpatterns = pat.iter_fields().map(|p| Box::new(cx.hoist_witness_pat(p)));
+        let hoist = |p| Box::new(cx.hoist_witness_pat(p));
         let kind = match pat.ctor() {
             Bool(b) => PatKind::Constant { value: mir::Const::from_bool(cx.tcx, *b) },
             IntRange(range) => return self.hoist_pat_range(range, *pat.ty()),
-            Struct | Variant(_) | UnionField => match pat.ty().kind() {
-                ty::Tuple(..) => PatKind::Leaf {
-                    subpatterns: subpatterns
-                        .enumerate()
-                        .map(|(i, pattern)| FieldPat { field: FieldIdx::new(i), pattern })
-                        .collect(),
-                },
-                ty::Adt(adt_def, _) if adt_def.is_box() => {
-                    // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
-                    // of `std`). So this branch is only reachable when the feature is enabled and
-                    // the pattern is a box pattern.
-                    PatKind::Deref { subpattern: subpatterns.next().unwrap() }
-                }
-                ty::Adt(adt_def, _args) => {
-                    let variant_index = RustcPatCtxt::variant_index_for_adt(&pat.ctor(), *adt_def);
-                    let subpatterns = subpatterns
-                        .enumerate()
-                        .map(|(i, pattern)| FieldPat { field: FieldIdx::new(i), pattern })
-                        .collect();
+            Struct if pat.ty().is_box() => {
+                // Outside of the `alloc` crate, the only way to create a struct pattern
+                // of type `Box` is to use a `box` pattern via #[feature(box_patterns)].
+                PatKind::Box { subpattern: hoist(&pat.fields[0]) }
+            }
+            Struct | Variant(_) | UnionField => {
+                let enum_info = match *pat.ty().kind() {
+                    ty::Adt(adt_def, _) if adt_def.is_enum() => EnumInfo::Enum {
+                        adt_def,
+                        variant_index: RustcPatCtxt::variant_index_for_adt(pat.ctor(), adt_def),
+                    },
+                    ty::Adt(..) | ty::Tuple(..) => EnumInfo::NotEnum,
+                    _ => bug!("unexpected ctor for type {:?} {:?}", pat.ctor(), *pat.ty()),
+                };
 
-                    if adt_def.is_enum() {
-                        PatKind::Variant { adt_def: *adt_def, variant_index, subpatterns }
-                    } else {
-                        PatKind::Leaf { subpatterns }
-                    }
-                }
-                _ => bug!("unexpected ctor for type {:?} {:?}", pat.ctor(), *pat.ty()),
-            },
-            // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
-            // be careful to reconstruct the correct constant pattern here. However a string
-            // literal pattern will never be reported as a non-exhaustiveness witness, so we
-            // ignore this issue.
-            Ref => PatKind::Deref { subpattern: subpatterns.next().unwrap() },
+                let subpatterns = pat
+                    .iter_fields()
+                    .enumerate()
+                    .map(|(i, pat)| FieldPat { field: FieldIdx::new(i), pattern: hoist(pat) })
+                    .collect::<Vec<_>>();
+
+                PatKind::StructLike { enum_info, subpatterns }
+            }
+            Ref => PatKind::Deref { subpattern: hoist(&pat.fields[0]) },
             Slice(slice) => {
-                match slice.kind {
-                    SliceKind::FixedLen(_) => PatKind::Slice {
-                        prefix: subpatterns.collect(),
-                        slice: None,
-                        suffix: Box::new([]),
-                    },
-                    SliceKind::VarLen(prefix, _) => {
-                        let mut subpatterns = subpatterns.peekable();
-                        let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix).collect();
-                        if slice.array_len.is_some() {
-                            // Improves diagnostics a bit: if the type is a known-size array, instead
-                            // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`.
-                            // This is incorrect if the size is not known, since `[_, ..]` captures
-                            // arrays of lengths `>= 1` whereas `[..]` captures any length.
-                            while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) {
-                                prefix.pop();
-                            }
-                            while subpatterns.peek().is_some()
-                                && is_wildcard(subpatterns.peek().unwrap())
-                            {
-                                subpatterns.next();
-                            }
-                        }
-                        let suffix: Box<[_]> = subpatterns.collect();
-                        let wild = Pat { ty: pat.ty().inner(), kind: PatKind::Wild };
-                        PatKind::Slice {
-                            prefix: prefix.into_boxed_slice(),
-                            slice: Some(Box::new(wild)),
-                            suffix,
-                        }
+                let (prefix_len, has_dot_dot) = match slice.kind {
+                    SliceKind::FixedLen(len) => (len, false),
+                    SliceKind::VarLen(prefix_len, _) => (prefix_len, true),
+                };
+
+                let (mut prefix, mut suffix) = pat.fields.split_at(prefix_len);
+
+                // If the pattern contains a `..`, but is applied to values of statically-known
+                // length (arrays), then we can slightly simplify diagnostics by merging any
+                // adjacent wildcard patterns into the `..`: `[x, _, .., _, y]` => `[x, .., y]`.
+                // (This simplification isn't allowed for slice values, because in that case
+                // `[x, .., y]` would match some slices that `[x, _, .., _, y]` would not.)
+                if has_dot_dot && slice.array_len.is_some() {
+                    while let [rest @ .., last] = prefix
+                        && would_print_as_wildcard(cx.tcx, last)
+                    {
+                        prefix = rest;
+                    }
+                    while let [first, rest @ ..] = suffix
+                        && would_print_as_wildcard(cx.tcx, first)
+                    {
+                        suffix = rest;
                     }
                 }
+
+                let prefix = prefix.iter().map(hoist).collect();
+                let suffix = suffix.iter().map(hoist).collect();
+
+                PatKind::Slice { prefix, has_dot_dot, suffix }
             }
             &Str(value) => PatKind::Constant { value },
             Never if self.tcx.features().never_patterns => PatKind::Never,
@@ -914,6 +900,22 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
     }
 }
 
+/// Returns `true` if the given pattern would be printed as a wildcard (`_`).
+fn would_print_as_wildcard(tcx: TyCtxt<'_>, p: &WitnessPat<'_, '_>) -> bool {
+    match p.ctor() {
+        Constructor::IntRange(IntRange {
+            lo: MaybeInfiniteInt::NegInfinity,
+            hi: MaybeInfiniteInt::PosInfinity,
+        })
+        | Constructor::Wildcard
+        | Constructor::NonExhaustive
+        | Constructor::Hidden
+        | Constructor::PrivateUninhabited => true,
+        Constructor::Never if !tcx.features().never_patterns => true,
+        _ => false,
+    }
+}
+
 impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
     type Ty = RevealedTy<'tcx>;
     type Error = ErrorGuaranteed;
@@ -925,9 +927,6 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
     fn is_exhaustive_patterns_feature_on(&self) -> bool {
         self.tcx.features().exhaustive_patterns
     }
-    fn is_min_exhaustive_patterns_feature_on(&self) -> bool {
-        self.tcx.features().min_exhaustive_patterns
-    }
 
     fn ctor_arity(&self, ctor: &crate::constructor::Constructor<Self>, ty: &Self::Ty) -> usize {
         self.ctor_arity(ctor, *ty)
diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs
index 4b76764e8b1..7d638714605 100644
--- a/compiler/rustc_pattern_analysis/src/rustc/print.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs
@@ -12,7 +12,7 @@
 use std::fmt;
 
 use rustc_middle::thir::PatRange;
-use rustc_middle::ty::{self, AdtDef, Ty};
+use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
 use rustc_middle::{bug, mir};
 use rustc_span::sym;
 use rustc_target::abi::{FieldIdx, VariantIdx};
@@ -33,14 +33,13 @@ pub(crate) struct Pat<'tcx> {
 pub(crate) enum PatKind<'tcx> {
     Wild,
 
-    Variant {
-        adt_def: AdtDef<'tcx>,
-        variant_index: VariantIdx,
+    StructLike {
+        enum_info: EnumInfo<'tcx>,
         subpatterns: Vec<FieldPat<'tcx>>,
     },
 
-    Leaf {
-        subpatterns: Vec<FieldPat<'tcx>>,
+    Box {
+        subpattern: Box<Pat<'tcx>>,
     },
 
     Deref {
@@ -55,7 +54,9 @@ pub(crate) enum PatKind<'tcx> {
 
     Slice {
         prefix: Box<[Box<Pat<'tcx>>]>,
-        slice: Option<Box<Pat<'tcx>>>,
+        /// True if this slice-like pattern should include a `..` between the
+        /// prefix and suffix.
+        has_dot_dot: bool,
         suffix: Box<[Box<Pat<'tcx>>]>,
     },
 
@@ -64,130 +65,155 @@ pub(crate) enum PatKind<'tcx> {
 
 impl<'tcx> fmt::Display for Pat<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // Printing lists is a chore.
-        let mut first = true;
-        let mut start_or_continue = |s| {
-            if first {
-                first = false;
-                ""
-            } else {
-                s
-            }
-        };
-        let mut start_or_comma = || start_or_continue(", ");
-
         match self.kind {
             PatKind::Wild => write!(f, "_"),
             PatKind::Never => write!(f, "!"),
-            PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
-                let variant_and_name = match self.kind {
-                    PatKind::Variant { adt_def, variant_index, .. } => ty::tls::with(|tcx| {
-                        let variant = adt_def.variant(variant_index);
-                        let adt_did = adt_def.did();
-                        let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did)
-                            || tcx.get_diagnostic_item(sym::Result) == Some(adt_did)
-                        {
-                            variant.name.to_string()
-                        } else {
-                            format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name)
-                        };
-                        Some((variant, name))
-                    }),
-                    _ => self.ty.ty_adt_def().and_then(|adt_def| {
-                        if !adt_def.is_enum() {
-                            ty::tls::with(|tcx| {
-                                Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did())))
-                            })
-                        } else {
-                            None
-                        }
-                    }),
-                };
-
-                if let Some((variant, name)) = &variant_and_name {
-                    write!(f, "{name}")?;
-
-                    // Only for Adt we can have `S {...}`,
-                    // which we handle separately here.
-                    if variant.ctor.is_none() {
-                        write!(f, " {{ ")?;
-
-                        let mut printed = 0;
-                        for p in subpatterns {
-                            if let PatKind::Wild = p.pattern.kind {
-                                continue;
-                            }
-                            let name = variant.fields[p.field].name;
-                            write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
-                            printed += 1;
-                        }
-
-                        let is_union = self.ty.ty_adt_def().is_some_and(|adt| adt.is_union());
-                        if printed < variant.fields.len() && (!is_union || printed == 0) {
-                            write!(f, "{}..", start_or_comma())?;
-                        }
-
-                        return write!(f, " }}");
-                    }
-                }
+            PatKind::Box { ref subpattern } => write!(f, "box {subpattern}"),
+            PatKind::StructLike { ref enum_info, ref subpatterns } => {
+                ty::tls::with(|tcx| write_struct_like(f, tcx, self.ty, enum_info, subpatterns))
+            }
+            PatKind::Deref { ref subpattern } => write_ref_like(f, self.ty, subpattern),
+            PatKind::Constant { value } => write!(f, "{value}"),
+            PatKind::Range(ref range) => write!(f, "{range}"),
+            PatKind::Slice { ref prefix, has_dot_dot, ref suffix } => {
+                write_slice_like(f, prefix, has_dot_dot, suffix)
+            }
+        }
+    }
+}
+
+/// Returns a closure that will return `""` when called the first time,
+/// and then return `", "` when called any subsequent times.
+/// Useful for printing comma-separated lists.
+fn start_or_comma() -> impl FnMut() -> &'static str {
+    let mut first = true;
+    move || {
+        if first {
+            first = false;
+            ""
+        } else {
+            ", "
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) enum EnumInfo<'tcx> {
+    Enum { adt_def: AdtDef<'tcx>, variant_index: VariantIdx },
+    NotEnum,
+}
+
+fn write_struct_like<'tcx>(
+    f: &mut impl fmt::Write,
+    tcx: TyCtxt<'_>,
+    ty: Ty<'tcx>,
+    enum_info: &EnumInfo<'tcx>,
+    subpatterns: &[FieldPat<'tcx>],
+) -> fmt::Result {
+    let variant_and_name = match *enum_info {
+        EnumInfo::Enum { adt_def, variant_index } => {
+            let variant = adt_def.variant(variant_index);
+            let adt_did = adt_def.did();
+            let name = if tcx.is_diagnostic_item(sym::Option, adt_did)
+                || tcx.is_diagnostic_item(sym::Result, adt_did)
+            {
+                variant.name.to_string()
+            } else {
+                format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name)
+            };
+            Some((variant, name))
+        }
+        EnumInfo::NotEnum => ty.ty_adt_def().and_then(|adt_def| {
+            Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did())))
+        }),
+    };
+
+    let mut start_or_comma = start_or_comma();
 
-                let num_fields =
-                    variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len());
-                if num_fields != 0 || variant_and_name.is_none() {
-                    write!(f, "(")?;
-                    for i in 0..num_fields {
-                        write!(f, "{}", start_or_comma())?;
-
-                        // Common case: the field is where we expect it.
-                        if let Some(p) = subpatterns.get(i) {
-                            if p.field.index() == i {
-                                write!(f, "{}", p.pattern)?;
-                                continue;
-                            }
-                        }
-
-                        // Otherwise, we have to go looking for it.
-                        if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
-                            write!(f, "{}", p.pattern)?;
-                        } else {
-                            write!(f, "_")?;
-                        }
-                    }
-                    write!(f, ")")?;
+    if let Some((variant, name)) = &variant_and_name {
+        write!(f, "{name}")?;
+
+        // Only for Adt we can have `S {...}`,
+        // which we handle separately here.
+        if variant.ctor.is_none() {
+            write!(f, " {{ ")?;
+
+            let mut printed = 0;
+            for p in subpatterns {
+                if let PatKind::Wild = p.pattern.kind {
+                    continue;
                 }
+                let name = variant.fields[p.field].name;
+                write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
+                printed += 1;
+            }
 
-                Ok(())
+            let is_union = ty.ty_adt_def().is_some_and(|adt| adt.is_union());
+            if printed < variant.fields.len() && (!is_union || printed == 0) {
+                write!(f, "{}..", start_or_comma())?;
             }
-            PatKind::Deref { ref subpattern } => {
-                match self.ty.kind() {
-                    ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
-                    ty::Ref(_, _, mutbl) => {
-                        write!(f, "&{}", mutbl.prefix_str())?;
-                    }
-                    _ => bug!("{} is a bad Deref pattern type", self.ty),
+
+            return write!(f, " }}");
+        }
+    }
+
+    let num_fields = variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len());
+    if num_fields != 0 || variant_and_name.is_none() {
+        write!(f, "(")?;
+        for i in 0..num_fields {
+            write!(f, "{}", start_or_comma())?;
+
+            // Common case: the field is where we expect it.
+            if let Some(p) = subpatterns.get(i) {
+                if p.field.index() == i {
+                    write!(f, "{}", p.pattern)?;
+                    continue;
                 }
-                write!(f, "{subpattern}")
             }
-            PatKind::Constant { value } => write!(f, "{value}"),
-            PatKind::Range(ref range) => write!(f, "{range}"),
-            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
-                write!(f, "[")?;
-                for p in prefix.iter() {
-                    write!(f, "{}{}", start_or_comma(), p)?;
-                }
-                if let Some(ref slice) = *slice {
-                    write!(f, "{}", start_or_comma())?;
-                    match slice.kind {
-                        PatKind::Wild => {}
-                        _ => write!(f, "{slice}")?,
-                    }
-                    write!(f, "..")?;
-                }
-                for p in suffix.iter() {
-                    write!(f, "{}{}", start_or_comma(), p)?;
-                }
-                write!(f, "]")
+
+            // Otherwise, we have to go looking for it.
+            if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
+                write!(f, "{}", p.pattern)?;
+            } else {
+                write!(f, "_")?;
             }
         }
+        write!(f, ")")?;
+    }
+
+    Ok(())
+}
+
+fn write_ref_like<'tcx>(
+    f: &mut impl fmt::Write,
+    ty: Ty<'tcx>,
+    subpattern: &Pat<'tcx>,
+) -> fmt::Result {
+    match ty.kind() {
+        ty::Ref(_, _, mutbl) => {
+            write!(f, "&{}", mutbl.prefix_str())?;
+        }
+        _ => bug!("{ty} is a bad ref pattern type"),
+    }
+    write!(f, "{subpattern}")
+}
+
+fn write_slice_like<'tcx>(
+    f: &mut impl fmt::Write,
+    prefix: &[Box<Pat<'tcx>>],
+    has_dot_dot: bool,
+    suffix: &[Box<Pat<'tcx>>],
+) -> fmt::Result {
+    let mut start_or_comma = start_or_comma();
+    write!(f, "[")?;
+    for p in prefix.iter() {
+        write!(f, "{}{}", start_or_comma(), p)?;
+    }
+    if has_dot_dot {
+        write!(f, "{}..", start_or_comma())?;
+    }
+    for p in suffix.iter() {
+        write!(f, "{}{}", start_or_comma(), p)?;
     }
+    write!(f, "]")
 }
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index 9710c9e1303..6535afcc398 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -543,13 +543,11 @@
 //! recurse into subpatterns. That second part is done through [`PlaceValidity`], most notably
 //! [`PlaceValidity::specialize`].
 //!
-//! Having said all that, in practice we don't fully follow what's been presented in this section.
-//! Let's call "toplevel exception" the case where the match scrutinee itself has type `!` or
-//! `EmptyEnum`. First, on stable rust, we require `_` patterns for empty types in all cases apart
-//! from the toplevel exception. The `exhaustive_patterns` and `min_exaustive_patterns` allow
-//! omitting patterns in the cases described above. There's a final detail: in the toplevel
-//! exception or with the `exhaustive_patterns` feature, we ignore place validity when checking
-//! whether a pattern is required for exhaustiveness. I (Nadrieril) hope to deprecate this behavior.
+//! Having said all that, we don't fully follow what's been presented in this section. For
+//! backwards-compatibility, we ignore place validity when checking whether a pattern is required
+//! for exhaustiveness in two cases: when the `exhaustive_patterns` feature gate is on, or when the
+//! match scrutinee itself has type `!` or `EmptyEnum`. I (Nadrieril) hope to deprecate this
+//! exception.
 //!
 //!
 //!
@@ -953,13 +951,10 @@ impl<Cx: PatCx> PlaceInfo<Cx> {
             self.is_scrutinee && matches!(ctors_for_ty, ConstructorSet::NoConstructors);
         // Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if
         // it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`).
-        let empty_arms_are_unreachable = self.validity.is_known_valid()
-            && (is_toplevel_exception
-                || cx.is_exhaustive_patterns_feature_on()
-                || cx.is_min_exhaustive_patterns_feature_on());
+        let empty_arms_are_unreachable = self.validity.is_known_valid();
         // Whether empty patterns can be omitted for exhaustiveness. We ignore place validity in the
         // toplevel exception and `exhaustive_patterns` cases for backwards compatibility.
-        let can_omit_empty_arms = empty_arms_are_unreachable
+        let can_omit_empty_arms = self.validity.is_known_valid()
             || is_toplevel_exception
             || cx.is_exhaustive_patterns_feature_on();
 
diff --git a/compiler/rustc_pattern_analysis/tests/common/mod.rs b/compiler/rustc_pattern_analysis/tests/common/mod.rs
index 01a56eaa78f..ec0bcd43ad2 100644
--- a/compiler/rustc_pattern_analysis/tests/common/mod.rs
+++ b/compiler/rustc_pattern_analysis/tests/common/mod.rs
@@ -152,10 +152,6 @@ impl PatCx for Cx {
         false
     }
 
-    fn is_min_exhaustive_patterns_feature_on(&self) -> bool {
-        true
-    }
-
     fn ctor_arity(&self, ctor: &Constructor<Self>, ty: &Self::Ty) -> usize {
         ty.sub_tys(ctor).len()
     }
diff --git a/compiler/rustc_query_system/src/dep_graph/debug.rs b/compiler/rustc_query_system/src/dep_graph/debug.rs
index 4d009d63de5..12ed5742711 100644
--- a/compiler/rustc_query_system/src/dep_graph/debug.rs
+++ b/compiler/rustc_query_system/src/dep_graph/debug.rs
@@ -46,15 +46,14 @@ pub struct EdgeFilter {
 
 impl EdgeFilter {
     pub fn new(test: &str) -> Result<EdgeFilter, Box<dyn Error>> {
-        let parts: Vec<_> = test.split("->").collect();
-        if parts.len() != 2 {
-            Err(format!("expected a filter like `a&b -> c&d`, not `{test}`").into())
-        } else {
+        if let [source, target] = *test.split("->").collect::<Vec<_>>() {
             Ok(EdgeFilter {
-                source: DepNodeFilter::new(parts[0]),
-                target: DepNodeFilter::new(parts[1]),
+                source: DepNodeFilter::new(source),
+                target: DepNodeFilter::new(target),
                 index_to_node: Lock::new(FxHashMap::default()),
             })
+        } else {
+            Err(format!("expected a filter like `a&b -> c&d`, not `{test}`").into())
         }
     }
 
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 307625bcfb1..d57dabdd78d 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -374,7 +374,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
             root_span,
             root_id,
             vis,
-            used: Default::default(),
         });
 
         self.r.indeterminate_imports.push(import);
@@ -890,8 +889,10 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
             span: item.span,
             module_path: Vec::new(),
             vis,
-            used: Cell::new(used.then_some(Used::Other)),
         });
+        if used {
+            self.r.import_use_map.insert(import, Used::Other);
+        }
         self.r.potentially_unused_imports.push(import);
         let imported_binding = self.r.import(binding, import);
         if parent == self.r.graph_root {
@@ -1091,7 +1092,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                 span,
                 module_path: Vec::new(),
                 vis: ty::Visibility::Restricted(CRATE_DEF_ID),
-                used: Default::default(),
             })
         };
 
@@ -1256,8 +1256,8 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                     span,
                     module_path: Vec::new(),
                     vis,
-                    used: Cell::new(Some(Used::Other)),
                 });
+                self.r.import_use_map.insert(import, Used::Other);
                 let import_binding = self.r.import(binding, import);
                 self.r.define(self.r.graph_root, ident, MacroNS, import_binding);
             } else {
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 75b8ecebdd9..1cee876b80f 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -381,9 +381,9 @@ impl Resolver<'_, '_> {
 
         for import in self.potentially_unused_imports.iter() {
             match import.kind {
-                _ if import.used.get().is_some()
-                    || import.vis.is_public()
-                    || import.span.is_dummy() =>
+                _ if import.vis.is_public()
+                    || import.span.is_dummy()
+                    || self.import_use_map.contains_key(import) =>
                 {
                     if let ImportKind::MacroUse { .. } = import.kind {
                         if !import.span.is_dummy() {
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 4a891d12281..42171edf757 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -176,7 +176,6 @@ pub(crate) struct ImportData<'a> {
     /// The resolution of `module_path`.
     pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>,
     pub vis: ty::Visibility,
-    pub used: Cell<Option<Used>>,
 }
 
 /// All imports are unique and allocated on a same arena,
@@ -484,7 +483,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             });
             self.record_use(target, dummy_binding, Used::Other);
         } else if import.imported_module.get().is_none() {
-            import.used.set(Some(Used::Other));
+            self.import_use_map.insert(import, Used::Other);
             if let Some(id) = import.id() {
                 self.used_imports.insert(id);
             }
@@ -1347,7 +1346,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         // module defined by a block).
         // Skip if the import is public or was used through non scope-based resolution,
         // e.g. through a module-relative path.
-        if import.used.get() == Some(Used::Other)
+        if self.import_use_map.get(&import) == Some(&Used::Other)
             || self.effective_visibilities.is_exported(self.local_def_id(id))
         {
             return false;
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index a5bd2fdd8f3..4a70fc0f308 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -445,8 +445,8 @@ impl<'a> PathSource<'a> {
                 Some(ExprKind::Call(call_expr, _)) => match &call_expr.kind {
                     // the case of `::some_crate()`
                     ExprKind::Path(_, path)
-                        if path.segments.len() == 2
-                            && path.segments[0].ident.name == kw::PathRoot =>
+                        if let [segment, _] = path.segments.as_slice()
+                            && segment.ident.name == kw::PathRoot =>
                     {
                         "external crate"
                     }
@@ -2396,15 +2396,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
     }
 
     fn future_proof_import(&mut self, use_tree: &UseTree) {
-        let segments = &use_tree.prefix.segments;
-        if !segments.is_empty() {
-            let ident = segments[0].ident;
+        if let [segment, rest @ ..] = use_tree.prefix.segments.as_slice() {
+            let ident = segment.ident;
             if ident.is_path_segment_keyword() || ident.span.is_rust_2015() {
                 return;
             }
 
             let nss = match use_tree.kind {
-                UseTreeKind::Simple(..) if segments.len() == 1 => &[TypeNS, ValueNS][..],
+                UseTreeKind::Simple(..) if rest.is_empty() => &[TypeNS, ValueNS][..],
                 _ => &[TypeNS],
             };
             let report_error = |this: &Self, ns| {
@@ -4009,16 +4008,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
 
             if this.should_report_errs() {
                 if candidates.is_empty() {
-                    if path.len() == 2 && prefix_path.len() == 1 {
+                    if path.len() == 2
+                        && let [segment] = prefix_path
+                    {
                         // Delay to check whether methond name is an associated function or not
                         // ```
                         // let foo = Foo {};
                         // foo::bar(); // possibly suggest to foo.bar();
                         //```
-                        err.stash(
-                            prefix_path[0].ident.span,
-                            rustc_errors::StashKey::CallAssocMethod,
-                        );
+                        err.stash(segment.ident.span, rustc_errors::StashKey::CallAssocMethod);
                     } else {
                         // When there is no suggested imports, we can just emit the error
                         // and suggestions immediately. Note that we bypass the usually error
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index f9896fb2196..f778b0ee3ac 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -650,14 +650,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         let typo_sugg = self
             .lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)
             .to_opt_suggestion();
-        if path.len() == 1
+        if let [segment] = path
             && !matches!(source, PathSource::Delegation)
             && self.self_type_is_available()
         {
             if let Some(candidate) =
                 self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
             {
-                let self_is_available = self.self_value_is_available(path[0].ident.span);
+                let self_is_available = self.self_value_is_available(segment.ident.span);
                 // Account for `Foo { field }` when suggesting `self.field` so we result on
                 // `Foo { field: self.field }`.
                 let pre = match source {
@@ -665,7 +665,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                         if expr
                             .fields
                             .iter()
-                            .any(|f| f.ident == path[0].ident && f.is_shorthand) =>
+                            .any(|f| f.ident == segment.ident && f.is_shorthand) =>
                     {
                         format!("{path_str}: ")
                     }
@@ -1258,8 +1258,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                             )
                         })
                         .collect();
-                if targets.len() == 1 {
-                    let target = targets[0];
+                if let [target] = targets.as_slice() {
                     return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1));
                 }
             }
@@ -2105,8 +2104,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         filter_fn: &impl Fn(Res) -> bool,
     ) -> TypoCandidate {
         let mut names = Vec::new();
-        if path.len() == 1 {
-            let mut ctxt = path.last().unwrap().ident.span.ctxt();
+        if let [segment] = path {
+            let mut ctxt = segment.ident.span.ctxt();
 
             // Search in lexical scope.
             // Walk backwards up the ribs in scope and collect candidates.
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 89ac839651f..02fdc1ae668 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1016,6 +1016,8 @@ pub struct Resolver<'a, 'tcx> {
     partial_res_map: NodeMap<PartialRes>,
     /// Resolutions for import nodes, which have multiple resolutions in different namespaces.
     import_res_map: NodeMap<PerNS<Option<Res>>>,
+    /// An import will be inserted into this map if it has been used.
+    import_use_map: FxHashMap<Import<'a>, Used>,
     /// Resolutions for labels (node IDs of their corresponding blocks or loops).
     label_res_map: NodeMap<NodeId>,
     /// Resolutions for lifetimes.
@@ -1422,6 +1424,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             pat_span_map: Default::default(),
             partial_res_map: Default::default(),
             import_res_map: Default::default(),
+            import_use_map: Default::default(),
             label_res_map: Default::default(),
             lifetimes_res_map: Default::default(),
             extra_lifetime_params_map: Default::default(),
@@ -1839,7 +1842,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     }
 
     /// Test if AmbiguityError ambi is any identical to any one inside ambiguity_errors
-    fn matches_previous_ambiguity_error(&mut self, ambi: &AmbiguityError<'_>) -> bool {
+    fn matches_previous_ambiguity_error(&self, ambi: &AmbiguityError<'_>) -> bool {
         for ambiguity_error in &self.ambiguity_errors {
             // if the span location and ident as well as its span are the same
             if ambiguity_error.kind == ambi.kind
@@ -1900,10 +1903,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     }
                 }
             }
-            let old_used = import.used.get();
-            let new_used = Some(used);
-            if new_used > old_used {
-                import.used.set(new_used);
+            let old_used = self.import_use_map.entry(import).or_insert(used);
+            if *old_used < used {
+                *old_used = used;
             }
             if let Some(id) = import.id() {
                 self.used_imports.insert(id);
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index da7278175e9..7203fbe4a0c 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -109,8 +109,8 @@ pub(crate) fn sub_namespace_match(
 // `format!("{}", path)`, because that tries to insert
 // line-breaks and is slow.
 fn fast_print_path(path: &ast::Path) -> Symbol {
-    if path.segments.len() == 1 {
-        path.segments[0].ident.name
+    if let [segment] = path.segments.as_slice() {
+        segment.ident.name
     } else {
         let mut path_str = String::with_capacity(64);
         for (i, segment) in path.segments.iter().enumerate() {
@@ -738,10 +738,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         // Possibly apply the macro helper hack
         if deleg_impl.is_none()
             && kind == Some(MacroKind::Bang)
-            && path.len() == 1
-            && path[0].ident.span.ctxt().outer_expn_data().local_inner_macros
+            && let [segment] = path.as_slice()
+            && segment.ident.span.ctxt().outer_expn_data().local_inner_macros
         {
-            let root = Ident::new(kw::DollarCrate, path[0].ident.span);
+            let root = Ident::new(kw::DollarCrate, segment.ident.span);
             path.insert(0, Segment::from_ident(root));
         }
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 4b87f5d62b2..df72e2430fd 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -912,16 +912,9 @@ mod parse {
         match v {
             None => false,
             Some(s) => {
-                let parts = s.split('=').collect::<Vec<_>>();
-                if parts.len() != 2 {
-                    return false;
-                }
-                let crate_name = parts[0].to_string();
-                let fuel = parts[1].parse::<u64>();
-                if fuel.is_err() {
-                    return false;
-                }
-                *slot = Some((crate_name, fuel.unwrap()));
+                let [crate_name, fuel] = *s.split('=').collect::<Vec<_>>() else { return false };
+                let Ok(fuel) = fuel.parse::<u64>() else { return false };
+                *slot = Some((crate_name.to_string(), fuel));
                 true
             }
         }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 32fca6733bb..9cb729ec485 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1619,6 +1619,7 @@ symbols! {
         rustc_dirty,
         rustc_do_not_const_check,
         rustc_doc_primitive,
+        rustc_driver,
         rustc_dummy,
         rustc_dump_def_parents,
         rustc_dump_item_bounds,
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index ecc91ab9a31..b2116c51216 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -9,12 +9,12 @@
 
 // tidy-alphabetical-start
 #![allow(internal_features)]
+#![cfg_attr(bootstrap, feature(min_exhaustive_patterns))]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(assert_matches)]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
-#![feature(min_exhaustive_patterns)]
 #![feature(rustc_attrs)]
 #![feature(rustdoc_internals)]
 // tidy-alphabetical-end
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 946947124c6..8ce51ba2463 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -3149,11 +3149,10 @@ impl Target {
                     if let Some(a) = o.as_array() {
                         for o in a {
                             if let Some(s) = o.as_str() {
-                                let p = s.split('=').collect::<Vec<_>>();
-                                if p.len() == 2 {
-                                    let k = p[0].to_string();
-                                    let v = p[1].to_string();
-                                    base.$key_name.to_mut().push((k.into(), v.into()));
+                                if let [k, v] = *s.split('=').collect::<Vec<_>>() {
+                                    base.$key_name
+                                        .to_mut()
+                                        .push((k.to_string().into(), v.to_string().into()))
                                 }
                             }
                         }
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs
index f37781c3f63..65f2a1e3069 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs
@@ -17,7 +17,7 @@ pub fn target() -> Target {
         llvm_target: macos_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
             description: Some("ARM64 macOS (11.0+, Big Sur+)".into()),
-            tier: Some(2),
+            tier: Some(1),
             host_tools: Some(true),
             std: Some(true),
         },
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 1cee82f04ea..95d4509c100 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -944,8 +944,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 // The current method call returns `Result<_, ()>`
                 && self.can_eq(obligation.param_env, ty, found_ty)
                 // There's a single argument in the method call and it is a closure
-                && args.len() == 1
-                && let Some(arg) = args.get(0)
+                && let [arg] = args
                 && let hir::ExprKind::Closure(closure) = arg.kind
                 // The closure has a block for its body with no tail expression
                 && let body = self.tcx.hir().body(closure.body)
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index 3a082893c5c..f656f9b0e38 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -73,10 +73,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 }
             });
 
-            let impl_def_id_and_args = if self_match_impls.len() == 1 {
-                self_match_impls[0]
-            } else if fuzzy_match_impls.len() == 1 {
-                fuzzy_match_impls[0]
+            let impl_def_id_and_args = if let [impl_] = self_match_impls[..] {
+                impl_
+            } else if let [impl_] = fuzzy_match_impls[..] {
+                impl_
             } else {
                 return None;
             };
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 0d15ef55e24..9269177eb50 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -5300,7 +5300,8 @@ impl<'v> Visitor<'v> for FindTypeParam {
         match ty.kind {
             hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {}
             hir::TyKind::Path(hir::QPath::Resolved(None, path))
-                if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
+                if let [segment] = path.segments
+                    && segment.ident.name == self.param =>
             {
                 if !self.nested {
                     debug!(?ty, "FindTypeParam::visit_ty");
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 1d9a90f0300..1b2767a6a62 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -17,7 +17,6 @@ use rustc_hir::LangItem;
 use rustc_infer::infer::relate::TypeRelation;
 use rustc_infer::infer::BoundRegionConversionTime::{self, HigherRankedType};
 use rustc_infer::infer::DefineOpaqueTypes;
-use rustc_infer::traits::util::elaborate;
 use rustc_infer::traits::TraitObligation;
 use rustc_middle::bug;
 use rustc_middle::dep_graph::{dep_kinds, DepNodeIndex};
@@ -2801,31 +2800,22 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         }
 
         // Register any outlives obligations from the trait here, cc #124336.
-        if matches!(self.tcx().def_kind(def_id), DefKind::Impl { of_trait: true })
-            && let Some(header) = self.tcx().impl_trait_header(def_id)
-        {
-            let trait_clause: ty::Clause<'tcx> =
-                header.trait_ref.instantiate(self.tcx(), args).upcast(self.tcx());
-            for clause in elaborate(self.tcx(), [trait_clause]) {
-                if matches!(
-                    clause.kind().skip_binder(),
-                    ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..)
-                ) {
-                    let clause = normalize_with_depth_to(
-                        self,
-                        param_env,
-                        cause.clone(),
-                        recursion_depth,
-                        clause,
-                        &mut obligations,
-                    );
-                    obligations.push(Obligation {
-                        cause: cause.clone(),
-                        recursion_depth,
-                        param_env,
-                        predicate: clause.as_predicate(),
-                    });
-                }
+        if matches!(tcx.def_kind(def_id), DefKind::Impl { of_trait: true }) {
+            for clause in tcx.impl_super_outlives(def_id).iter_instantiated(tcx, args) {
+                let clause = normalize_with_depth_to(
+                    self,
+                    param_env,
+                    cause.clone(),
+                    recursion_depth,
+                    clause,
+                    &mut obligations,
+                );
+                obligations.push(Obligation {
+                    cause: cause.clone(),
+                    recursion_depth,
+                    param_env,
+                    predicate: clause.as_predicate(),
+                });
             }
         }
 
diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs
index 0dd26badc88..5db5a8f222d 100644
--- a/compiler/rustc_transmute/src/layout/nfa.rs
+++ b/compiler/rustc_transmute/src/layout/nfa.rs
@@ -87,6 +87,7 @@ where
     pub(crate) fn from_tree(tree: Tree<!, R>) -> Result<Self, Uninhabited> {
         Ok(match tree {
             Tree::Byte(b) => Self::from_byte(b),
+            #[cfg(bootstrap)]
             Tree::Def(..) => unreachable!(),
             Tree::Ref(r) => Self::from_ref(r),
             Tree::Alt(alts) => {
diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs
index 16dcf76e73e..d37bacc7d35 100644
--- a/compiler/rustc_type_ir/src/fold.rs
+++ b/compiler/rustc_type_ir/src/fold.rs
@@ -91,6 +91,7 @@ pub trait TypeFoldable<I: Interner>: TypeVisitable<I> {
     fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
         match self.try_fold_with(folder) {
             Ok(t) => t,
+            #[cfg(bootstrap)]
             Err(e) => match e {},
         }
     }
@@ -115,6 +116,7 @@ pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> {
     fn super_fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
         match self.try_super_fold_with(folder) {
             Ok(t) => t,
+            #[cfg(bootstrap)]
             Err(e) => match e {},
         }
     }
diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs
index 2d283dac9a9..7be3de16b2d 100644
--- a/library/alloc/src/collections/vec_deque/into_iter.rs
+++ b/library/alloc/src/collections/vec_deque/into_iter.rs
@@ -121,6 +121,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
     {
         match self.try_fold(init, |b, item| Ok::<B, !>(f(b, item))) {
             Ok(b) => b,
+            #[cfg(bootstrap)]
             Err(e) => match e {},
         }
     }
@@ -242,6 +243,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
     {
         match self.try_rfold(init, |b, item| Ok::<B, !>(f(b, item))) {
             Ok(b) => b,
+            #[cfg(bootstrap)]
             Err(e) => match e {},
         }
     }
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index 5b84df9ecef..9c8fa7ceff4 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -1,7 +1,7 @@
 #![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")]
 
-use core::alloc::LayoutError;
-use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
+use core::marker::PhantomData;
+use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties};
 use core::ptr::{self, NonNull, Unique};
 use core::{cmp, hint};
 
@@ -40,6 +40,13 @@ struct Cap(usize);
 
 impl Cap {
     const ZERO: Cap = unsafe { Cap(0) };
+
+    /// `Cap(cap)`, except if `T` is a ZST then `Cap::ZERO`.
+    ///
+    /// # Safety: cap must be <= `isize::MAX`.
+    unsafe fn new<T>(cap: usize) -> Self {
+        if T::IS_ZST { Cap::ZERO } else { unsafe { Self(cap) } }
+    }
 }
 
 /// A low-level utility for more ergonomically allocating, reallocating, and deallocating
@@ -66,7 +73,19 @@ impl Cap {
 /// `Box<[T]>`, since `capacity()` won't yield the length.
 #[allow(missing_debug_implementations)]
 pub(crate) struct RawVec<T, A: Allocator = Global> {
-    ptr: Unique<T>,
+    inner: RawVecInner<A>,
+    _marker: PhantomData<T>,
+}
+
+/// Like a `RawVec`, but only generic over the allocator, not the type.
+///
+/// As such, all the methods need the layout passed-in as a parameter.
+///
+/// Having this separation reduces the amount of code we need to monomorphize,
+/// as most operations don't need the actual type, just its layout.
+#[allow(missing_debug_implementations)]
+struct RawVecInner<A: Allocator = Global> {
+    ptr: Unique<u8>,
     /// Never used for ZSTs; it's `capacity()`'s responsibility to return usize::MAX in that case.
     ///
     /// # Safety
@@ -90,8 +109,9 @@ impl<T> RawVec<T, Global> {
     /// `RawVec` with capacity `usize::MAX`. Useful for implementing
     /// delayed allocation.
     #[must_use]
+    #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")]
     pub const fn new() -> Self {
-        Self::new_in(Global)
+        Self { inner: RawVecInner::new::<T>(), _marker: PhantomData }
     }
 
     /// Creates a `RawVec` (on the system heap) with exactly the
@@ -113,10 +133,7 @@ impl<T> RawVec<T, Global> {
     #[must_use]
     #[inline]
     pub fn with_capacity(capacity: usize) -> Self {
-        match Self::try_allocate_in(capacity, AllocInit::Uninitialized, Global) {
-            Ok(res) => res,
-            Err(err) => handle_error(err),
-        }
+        Self { inner: RawVecInner::with_capacity(capacity, T::LAYOUT), _marker: PhantomData }
     }
 
     /// Like `with_capacity`, but guarantees the buffer is zeroed.
@@ -124,29 +141,56 @@ impl<T> RawVec<T, Global> {
     #[must_use]
     #[inline]
     pub fn with_capacity_zeroed(capacity: usize) -> Self {
-        Self::with_capacity_zeroed_in(capacity, Global)
+        Self {
+            inner: RawVecInner::with_capacity_zeroed_in(capacity, Global, T::LAYOUT),
+            _marker: PhantomData,
+        }
     }
 }
 
-impl<T, A: Allocator> RawVec<T, A> {
-    // Tiny Vecs are dumb. Skip to:
-    // - 8 if the element size is 1, because any heap allocators is likely
-    //   to round up a request of less than 8 bytes to at least 8 bytes.
-    // - 4 if elements are moderate-sized (<= 1 KiB).
-    // - 1 otherwise, to avoid wasting too much space for very short Vecs.
-    pub(crate) const MIN_NON_ZERO_CAP: usize = if mem::size_of::<T>() == 1 {
+impl RawVecInner<Global> {
+    #[must_use]
+    #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")]
+    const fn new<T>() -> Self {
+        Self::new_in(Global, core::mem::align_of::<T>())
+    }
+
+    #[cfg(not(any(no_global_oom_handling, test)))]
+    #[must_use]
+    #[inline]
+    fn with_capacity(capacity: usize, elem_layout: Layout) -> Self {
+        match Self::try_allocate_in(capacity, AllocInit::Uninitialized, Global, elem_layout) {
+            Ok(res) => res,
+            Err(err) => handle_error(err),
+        }
+    }
+}
+
+// Tiny Vecs are dumb. Skip to:
+// - 8 if the element size is 1, because any heap allocators is likely
+//   to round up a request of less than 8 bytes to at least 8 bytes.
+// - 4 if elements are moderate-sized (<= 1 KiB).
+// - 1 otherwise, to avoid wasting too much space for very short Vecs.
+const fn min_non_zero_cap(size: usize) -> usize {
+    if size == 1 {
         8
-    } else if mem::size_of::<T>() <= 1024 {
+    } else if size <= 1024 {
         4
     } else {
         1
-    };
+    }
+}
+
+impl<T, A: Allocator> RawVec<T, A> {
+    #[cfg(not(no_global_oom_handling))]
+    pub(crate) const MIN_NON_ZERO_CAP: usize = min_non_zero_cap(size_of::<T>());
 
     /// Like `new`, but parameterized over the choice of allocator for
     /// the returned `RawVec`.
+    #[inline]
+    #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")]
     pub const fn new_in(alloc: A) -> Self {
-        // `cap: 0` means "unallocated". zero-sized types are ignored.
-        Self { ptr: Unique::dangling(), cap: Cap::ZERO, alloc }
+        Self { inner: RawVecInner::new_in(alloc, align_of::<T>()), _marker: PhantomData }
     }
 
     /// Like `with_capacity`, but parameterized over the choice of
@@ -154,9 +198,9 @@ impl<T, A: Allocator> RawVec<T, A> {
     #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
-        match Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc) {
-            Ok(res) => res,
-            Err(err) => handle_error(err),
+        Self {
+            inner: RawVecInner::with_capacity_in(capacity, alloc, T::LAYOUT),
+            _marker: PhantomData,
         }
     }
 
@@ -164,7 +208,10 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// allocator for the returned `RawVec`.
     #[inline]
     pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
-        Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc)
+        match RawVecInner::try_with_capacity_in(capacity, alloc, T::LAYOUT) {
+            Ok(inner) => Ok(Self { inner, _marker: PhantomData }),
+            Err(e) => Err(e),
+        }
     }
 
     /// Like `with_capacity_zeroed`, but parameterized over the choice
@@ -172,9 +219,9 @@ impl<T, A: Allocator> RawVec<T, A> {
     #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self {
-        match Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc) {
-            Ok(res) => res,
-            Err(err) => handle_error(err),
+        Self {
+            inner: RawVecInner::with_capacity_zeroed_in(capacity, alloc, T::LAYOUT),
+            _marker: PhantomData,
         }
     }
 
@@ -200,45 +247,7 @@ impl<T, A: Allocator> RawVec<T, A> {
         let me = ManuallyDrop::new(self);
         unsafe {
             let slice = ptr::slice_from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len);
-            Box::from_raw_in(slice, ptr::read(&me.alloc))
-        }
-    }
-
-    fn try_allocate_in(
-        capacity: usize,
-        init: AllocInit,
-        alloc: A,
-    ) -> Result<Self, TryReserveError> {
-        // Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
-
-        if T::IS_ZST || capacity == 0 {
-            Ok(Self::new_in(alloc))
-        } else {
-            // We avoid `unwrap_or_else` here because it bloats the amount of
-            // LLVM IR generated.
-            let layout = match Layout::array::<T>(capacity) {
-                Ok(layout) => layout,
-                Err(_) => return Err(CapacityOverflow.into()),
-            };
-
-            if let Err(err) = alloc_guard(layout.size()) {
-                return Err(err);
-            }
-
-            let result = match init {
-                AllocInit::Uninitialized => alloc.allocate(layout),
-                #[cfg(not(no_global_oom_handling))]
-                AllocInit::Zeroed => alloc.allocate_zeroed(layout),
-            };
-            let ptr = match result {
-                Ok(ptr) => ptr,
-                Err(_) => return Err(AllocError { layout, non_exhaustive: () }.into()),
-            };
-
-            // Allocators currently return a `NonNull<[u8]>` whose length
-            // matches the size requested. If that ever changes, the capacity
-            // here should change to `ptr.len() / mem::size_of::<T>()`.
-            Ok(Self { ptr: Unique::from(ptr.cast()), cap: unsafe { Cap(capacity) }, alloc })
+            Box::from_raw_in(slice, ptr::read(&me.inner.alloc))
         }
     }
 
@@ -254,8 +263,15 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// guaranteed.
     #[inline]
     pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self {
-        let cap = if T::IS_ZST { Cap::ZERO } else { unsafe { Cap(capacity) } };
-        Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap, alloc }
+        // SAFETY: Precondition passed to the caller
+        unsafe {
+            let ptr = ptr.cast();
+            let capacity = Cap::new::<T>(capacity);
+            Self {
+                inner: RawVecInner::from_raw_parts_in(ptr, capacity, alloc),
+                _marker: PhantomData,
+            }
+        }
     }
 
     /// A convenience method for hoisting the non-null precondition out of [`RawVec::from_raw_parts_in`].
@@ -264,9 +280,13 @@ impl<T, A: Allocator> RawVec<T, A> {
     ///
     /// See [`RawVec::from_raw_parts_in`].
     #[inline]
-    pub(crate) unsafe fn from_nonnull_in(ptr: NonNull<T>, capacity: usize, alloc: A) -> Self {
-        let cap = if T::IS_ZST { Cap::ZERO } else { unsafe { Cap(capacity) } };
-        Self { ptr: Unique::from(ptr), cap, alloc }
+    pub unsafe fn from_nonnull_in(ptr: NonNull<T>, capacity: usize, alloc: A) -> Self {
+        // SAFETY: Precondition passed to the caller
+        unsafe {
+            let ptr = ptr.cast();
+            let capacity = Cap::new::<T>(capacity);
+            Self { inner: RawVecInner::from_nonnull_in(ptr, capacity, alloc), _marker: PhantomData }
+        }
     }
 
     /// Gets a raw pointer to the start of the allocation. Note that this is
@@ -274,43 +294,26 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// be careful.
     #[inline]
     pub fn ptr(&self) -> *mut T {
-        self.ptr.as_ptr()
+        self.inner.ptr()
     }
 
     #[inline]
     pub fn non_null(&self) -> NonNull<T> {
-        NonNull::from(self.ptr)
+        self.inner.non_null()
     }
 
     /// Gets the capacity of the allocation.
     ///
     /// This will always be `usize::MAX` if `T` is zero-sized.
-    #[inline(always)]
+    #[inline]
     pub fn capacity(&self) -> usize {
-        if T::IS_ZST { usize::MAX } else { self.cap.0 }
+        self.inner.capacity(size_of::<T>())
     }
 
     /// Returns a shared reference to the allocator backing this `RawVec`.
+    #[inline]
     pub fn allocator(&self) -> &A {
-        &self.alloc
-    }
-
-    fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
-        if T::IS_ZST || self.cap.0 == 0 {
-            None
-        } else {
-            // We could use Layout::array here which ensures the absence of isize and usize overflows
-            // and could hypothetically handle differences between stride and size, but this memory
-            // has already been allocated so we know it can't overflow and currently Rust does not
-            // support such types. So we can do better by skipping some checks and avoid an unwrap.
-            const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
-            unsafe {
-                let align = mem::align_of::<T>();
-                let size = mem::size_of::<T>().unchecked_mul(self.cap.0);
-                let layout = Layout::from_size_align_unchecked(size, align);
-                Some((self.ptr.cast().into(), layout))
-            }
-        }
+        self.inner.allocator()
     }
 
     /// Ensures that the buffer contains at least enough space to hold `len +
@@ -335,24 +338,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn reserve(&mut self, len: usize, additional: usize) {
-        // Callers expect this function to be very cheap when there is already sufficient capacity.
-        // Therefore, we move all the resizing and error-handling logic from grow_amortized and
-        // handle_reserve behind a call, while making sure that this function is likely to be
-        // inlined as just a comparison and a call if the comparison fails.
-        #[cold]
-        fn do_reserve_and_handle<T, A: Allocator>(
-            slf: &mut RawVec<T, A>,
-            len: usize,
-            additional: usize,
-        ) {
-            if let Err(err) = slf.grow_amortized(len, additional) {
-                handle_error(err);
-            }
-        }
-
-        if self.needs_to_grow(len, additional) {
-            do_reserve_and_handle(self, len, additional);
-        }
+        self.inner.reserve(len, additional, T::LAYOUT)
     }
 
     /// A specialized version of `self.reserve(len, 1)` which requires the
@@ -360,21 +346,12 @@ impl<T, A: Allocator> RawVec<T, A> {
     #[cfg(not(no_global_oom_handling))]
     #[inline(never)]
     pub fn grow_one(&mut self) {
-        if let Err(err) = self.grow_amortized(self.cap.0, 1) {
-            handle_error(err);
-        }
+        self.inner.grow_one(T::LAYOUT)
     }
 
     /// The same as `reserve`, but returns on errors instead of panicking or aborting.
     pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
-        if self.needs_to_grow(len, additional) {
-            self.grow_amortized(len, additional)?;
-        }
-        unsafe {
-            // Inform the optimizer that the reservation has succeeded or wasn't needed
-            hint::assert_unchecked(!self.needs_to_grow(len, additional));
-        }
-        Ok(())
+        self.inner.try_reserve(len, additional, T::LAYOUT)
     }
 
     /// Ensures that the buffer contains at least enough space to hold `len +
@@ -396,9 +373,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// Aborts on OOM.
     #[cfg(not(no_global_oom_handling))]
     pub fn reserve_exact(&mut self, len: usize, additional: usize) {
-        if let Err(err) = self.try_reserve_exact(len, additional) {
-            handle_error(err);
-        }
+        self.inner.reserve_exact(len, additional, T::LAYOUT)
     }
 
     /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting.
@@ -407,14 +382,7 @@ impl<T, A: Allocator> RawVec<T, A> {
         len: usize,
         additional: usize,
     ) -> Result<(), TryReserveError> {
-        if self.needs_to_grow(len, additional) {
-            self.grow_exact(len, additional)?;
-        }
-        unsafe {
-            // Inform the optimizer that the reservation has succeeded or wasn't needed
-            hint::assert_unchecked(!self.needs_to_grow(len, additional));
-        }
-        Ok(())
+        self.inner.try_reserve_exact(len, additional, T::LAYOUT)
     }
 
     /// Shrinks the buffer down to the specified capacity. If the given amount
@@ -430,22 +398,230 @@ impl<T, A: Allocator> RawVec<T, A> {
     #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn shrink_to_fit(&mut self, cap: usize) {
-        if let Err(err) = self.shrink(cap) {
+        self.inner.shrink_to_fit(cap, T::LAYOUT)
+    }
+}
+
+unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> {
+    /// Frees the memory owned by the `RawVec` *without* trying to drop its contents.
+    fn drop(&mut self) {
+        // SAFETY: We are in a Drop impl, self.inner will not be used again.
+        unsafe { self.inner.deallocate(T::LAYOUT) }
+    }
+}
+
+impl<A: Allocator> RawVecInner<A> {
+    #[inline]
+    #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")]
+    const fn new_in(alloc: A, align: usize) -> Self {
+        let ptr = unsafe { core::mem::transmute(align) };
+        // `cap: 0` means "unallocated". zero-sized types are ignored.
+        Self { ptr, cap: Cap::ZERO, alloc }
+    }
+
+    #[cfg(not(no_global_oom_handling))]
+    #[inline]
+    fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self {
+        match Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) {
+            Ok(this) => {
+                unsafe {
+                    // Make it more obvious that a subsquent Vec::reserve(capacity) will not allocate.
+                    hint::assert_unchecked(!this.needs_to_grow(0, capacity, elem_layout));
+                }
+                this
+            }
+            Err(err) => handle_error(err),
+        }
+    }
+
+    #[inline]
+    fn try_with_capacity_in(
+        capacity: usize,
+        alloc: A,
+        elem_layout: Layout,
+    ) -> Result<Self, TryReserveError> {
+        Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout)
+    }
+
+    #[cfg(not(no_global_oom_handling))]
+    #[inline]
+    fn with_capacity_zeroed_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self {
+        match Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc, elem_layout) {
+            Ok(res) => res,
+            Err(err) => handle_error(err),
+        }
+    }
+
+    fn try_allocate_in(
+        capacity: usize,
+        init: AllocInit,
+        alloc: A,
+        elem_layout: Layout,
+    ) -> Result<Self, TryReserveError> {
+        // We avoid `unwrap_or_else` here because it bloats the amount of
+        // LLVM IR generated.
+        let layout = match layout_array(capacity, elem_layout) {
+            Ok(layout) => layout,
+            Err(_) => return Err(CapacityOverflow.into()),
+        };
+
+        // Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
+        if layout.size() == 0 {
+            return Ok(Self::new_in(alloc, elem_layout.align()));
+        }
+
+        if let Err(err) = alloc_guard(layout.size()) {
+            return Err(err);
+        }
+
+        let result = match init {
+            AllocInit::Uninitialized => alloc.allocate(layout),
+            #[cfg(not(no_global_oom_handling))]
+            AllocInit::Zeroed => alloc.allocate_zeroed(layout),
+        };
+        let ptr = match result {
+            Ok(ptr) => ptr,
+            Err(_) => return Err(AllocError { layout, non_exhaustive: () }.into()),
+        };
+
+        // Allocators currently return a `NonNull<[u8]>` whose length
+        // matches the size requested. If that ever changes, the capacity
+        // here should change to `ptr.len() / mem::size_of::<T>()`.
+        Ok(Self { ptr: Unique::from(ptr.cast()), cap: unsafe { Cap(capacity) }, alloc })
+    }
+
+    #[inline]
+    unsafe fn from_raw_parts_in(ptr: *mut u8, cap: Cap, alloc: A) -> Self {
+        Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap, alloc }
+    }
+
+    #[inline]
+    unsafe fn from_nonnull_in(ptr: NonNull<u8>, cap: Cap, alloc: A) -> Self {
+        Self { ptr: Unique::from(ptr), cap, alloc }
+    }
+
+    #[inline]
+    fn ptr<T>(&self) -> *mut T {
+        self.non_null::<T>().as_ptr()
+    }
+
+    #[inline]
+    fn non_null<T>(&self) -> NonNull<T> {
+        self.ptr.cast().into()
+    }
+
+    #[inline]
+    fn capacity(&self, elem_size: usize) -> usize {
+        if elem_size == 0 { usize::MAX } else { self.cap.0 }
+    }
+
+    #[inline]
+    fn allocator(&self) -> &A {
+        &self.alloc
+    }
+
+    #[inline]
+    fn current_memory(&self, elem_layout: Layout) -> Option<(NonNull<u8>, Layout)> {
+        if elem_layout.size() == 0 || self.cap.0 == 0 {
+            None
+        } else {
+            // We could use Layout::array here which ensures the absence of isize and usize overflows
+            // and could hypothetically handle differences between stride and size, but this memory
+            // has already been allocated so we know it can't overflow and currently Rust does not
+            // support such types. So we can do better by skipping some checks and avoid an unwrap.
+            unsafe {
+                let alloc_size = elem_layout.size().unchecked_mul(self.cap.0);
+                let layout = Layout::from_size_align_unchecked(alloc_size, elem_layout.align());
+                Some((self.ptr.into(), layout))
+            }
+        }
+    }
+
+    #[cfg(not(no_global_oom_handling))]
+    #[inline]
+    fn reserve(&mut self, len: usize, additional: usize, elem_layout: Layout) {
+        // Callers expect this function to be very cheap when there is already sufficient capacity.
+        // Therefore, we move all the resizing and error-handling logic from grow_amortized and
+        // handle_reserve behind a call, while making sure that this function is likely to be
+        // inlined as just a comparison and a call if the comparison fails.
+        #[cold]
+        fn do_reserve_and_handle<A: Allocator>(
+            slf: &mut RawVecInner<A>,
+            len: usize,
+            additional: usize,
+            elem_layout: Layout,
+        ) {
+            if let Err(err) = slf.grow_amortized(len, additional, elem_layout) {
+                handle_error(err);
+            }
+        }
+
+        if self.needs_to_grow(len, additional, elem_layout) {
+            do_reserve_and_handle(self, len, additional, elem_layout);
+        }
+    }
+
+    #[cfg(not(no_global_oom_handling))]
+    #[inline]
+    fn grow_one(&mut self, elem_layout: Layout) {
+        if let Err(err) = self.grow_amortized(self.cap.0, 1, elem_layout) {
             handle_error(err);
         }
     }
-}
 
-impl<T, A: Allocator> RawVec<T, A> {
-    /// Returns if the buffer needs to grow to fulfill the needed extra capacity.
-    /// Mainly used to make inlining reserve-calls possible without inlining `grow`.
-    fn needs_to_grow(&self, len: usize, additional: usize) -> bool {
-        additional > self.capacity().wrapping_sub(len)
+    fn try_reserve(
+        &mut self,
+        len: usize,
+        additional: usize,
+        elem_layout: Layout,
+    ) -> Result<(), TryReserveError> {
+        if self.needs_to_grow(len, additional, elem_layout) {
+            self.grow_amortized(len, additional, elem_layout)?;
+        }
+        unsafe {
+            // Inform the optimizer that the reservation has succeeded or wasn't needed
+            hint::assert_unchecked(!self.needs_to_grow(len, additional, elem_layout));
+        }
+        Ok(())
     }
 
-    /// # Safety:
-    ///
-    /// `cap` must not exceed `isize::MAX`.
+    #[cfg(not(no_global_oom_handling))]
+    fn reserve_exact(&mut self, len: usize, additional: usize, elem_layout: Layout) {
+        if let Err(err) = self.try_reserve_exact(len, additional, elem_layout) {
+            handle_error(err);
+        }
+    }
+
+    fn try_reserve_exact(
+        &mut self,
+        len: usize,
+        additional: usize,
+        elem_layout: Layout,
+    ) -> Result<(), TryReserveError> {
+        if self.needs_to_grow(len, additional, elem_layout) {
+            self.grow_exact(len, additional, elem_layout)?;
+        }
+        unsafe {
+            // Inform the optimizer that the reservation has succeeded or wasn't needed
+            hint::assert_unchecked(!self.needs_to_grow(len, additional, elem_layout));
+        }
+        Ok(())
+    }
+
+    #[cfg(not(no_global_oom_handling))]
+    #[inline]
+    fn shrink_to_fit(&mut self, cap: usize, elem_layout: Layout) {
+        if let Err(err) = self.shrink(cap, elem_layout) {
+            handle_error(err);
+        }
+    }
+
+    #[inline]
+    fn needs_to_grow(&self, len: usize, additional: usize, elem_layout: Layout) -> bool {
+        additional > self.capacity(elem_layout.size()).wrapping_sub(len)
+    }
+
+    #[inline]
     unsafe fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) {
         // Allocators currently return a `NonNull<[u8]>` whose length matches
         // the size requested. If that ever changes, the capacity here should
@@ -454,18 +630,16 @@ impl<T, A: Allocator> RawVec<T, A> {
         self.cap = unsafe { Cap(cap) };
     }
 
-    // This method is usually instantiated many times. So we want it to be as
-    // small as possible, to improve compile times. But we also want as much of
-    // its contents to be statically computable as possible, to make the
-    // generated code run faster. Therefore, this method is carefully written
-    // so that all of the code that depends on `T` is within it, while as much
-    // of the code that doesn't depend on `T` as possible is in functions that
-    // are non-generic over `T`.
-    fn grow_amortized(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
+    fn grow_amortized(
+        &mut self,
+        len: usize,
+        additional: usize,
+        elem_layout: Layout,
+    ) -> Result<(), TryReserveError> {
         // This is ensured by the calling contexts.
         debug_assert!(additional > 0);
 
-        if T::IS_ZST {
+        if elem_layout.size() == 0 {
             // Since we return a capacity of `usize::MAX` when `elem_size` is
             // 0, getting to here necessarily means the `RawVec` is overfull.
             return Err(CapacityOverflow.into());
@@ -477,33 +651,34 @@ impl<T, A: Allocator> RawVec<T, A> {
         // This guarantees exponential growth. The doubling cannot overflow
         // because `cap <= isize::MAX` and the type of `cap` is `usize`.
         let cap = cmp::max(self.cap.0 * 2, required_cap);
-        let cap = cmp::max(Self::MIN_NON_ZERO_CAP, cap);
+        let cap = cmp::max(min_non_zero_cap(elem_layout.size()), cap);
 
-        let new_layout = Layout::array::<T>(cap);
+        let new_layout = layout_array(cap, elem_layout)?;
 
-        // `finish_grow` is non-generic over `T`.
-        let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?;
+        let ptr = finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)?;
         // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items
+
         unsafe { self.set_ptr_and_cap(ptr, cap) };
         Ok(())
     }
 
-    // The constraints on this method are much the same as those on
-    // `grow_amortized`, but this method is usually instantiated less often so
-    // it's less critical.
-    fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
-        if T::IS_ZST {
+    fn grow_exact(
+        &mut self,
+        len: usize,
+        additional: usize,
+        elem_layout: Layout,
+    ) -> Result<(), TryReserveError> {
+        if elem_layout.size() == 0 {
             // Since we return a capacity of `usize::MAX` when the type size is
             // 0, getting to here necessarily means the `RawVec` is overfull.
             return Err(CapacityOverflow.into());
         }
 
         let cap = len.checked_add(additional).ok_or(CapacityOverflow)?;
-        let new_layout = Layout::array::<T>(cap);
+        let new_layout = layout_array(cap, elem_layout)?;
 
-        // `finish_grow` is non-generic over `T`.
-        let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?;
-        // SAFETY: `finish_grow` would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items
+        let ptr = finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)?;
+        // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items
         unsafe {
             self.set_ptr_and_cap(ptr, cap);
         }
@@ -512,10 +687,10 @@ impl<T, A: Allocator> RawVec<T, A> {
 
     #[cfg(not(no_global_oom_handling))]
     #[inline]
-    fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> {
-        assert!(cap <= self.capacity(), "Tried to shrink to a larger capacity");
+    fn shrink(&mut self, cap: usize, elem_layout: Layout) -> Result<(), TryReserveError> {
+        assert!(cap <= self.capacity(elem_layout.size()), "Tried to shrink to a larger capacity");
         // SAFETY: Just checked this isn't trying to grow
-        unsafe { self.shrink_unchecked(cap) }
+        unsafe { self.shrink_unchecked(cap, elem_layout) }
     }
 
     /// `shrink`, but without the capacity check.
@@ -529,23 +704,27 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// # Safety
     /// `cap <= self.capacity()`
     #[cfg(not(no_global_oom_handling))]
-    unsafe fn shrink_unchecked(&mut self, cap: usize) -> Result<(), TryReserveError> {
-        let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) };
-        // See current_memory() why this assert is here
-        const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
+    unsafe fn shrink_unchecked(
+        &mut self,
+        cap: usize,
+        elem_layout: Layout,
+    ) -> Result<(), TryReserveError> {
+        let (ptr, layout) =
+            if let Some(mem) = self.current_memory(elem_layout) { mem } else { return Ok(()) };
 
         // If shrinking to 0, deallocate the buffer. We don't reach this point
         // for the T::IS_ZST case since current_memory() will have returned
         // None.
         if cap == 0 {
             unsafe { self.alloc.deallocate(ptr, layout) };
-            self.ptr = Unique::dangling();
+            self.ptr =
+                unsafe { Unique::new_unchecked(ptr::without_provenance_mut(elem_layout.align())) };
             self.cap = Cap::ZERO;
         } else {
             let ptr = unsafe {
-                // `Layout::array` cannot overflow here because it would have
+                // Layout cannot overflow here because it would have
                 // overflowed earlier when capacity was larger.
-                let new_size = mem::size_of::<T>().unchecked_mul(cap);
+                let new_size = elem_layout.size().unchecked_mul(cap);
                 let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
                 self.alloc
                     .shrink(ptr, layout, new_layout)
@@ -558,24 +737,32 @@ impl<T, A: Allocator> RawVec<T, A> {
         }
         Ok(())
     }
+
+    /// # Safety
+    ///
+    /// This function deallocates the owned allocation, but does not update `ptr` or `cap` to
+    /// prevent double-free or use-after-free. Essentially, do not do anything with the caller
+    /// after this function returns.
+    /// Ideally this function would take `self` by move, but it cannot because it exists to be
+    /// called from a `Drop` impl.
+    unsafe fn deallocate(&mut self, elem_layout: Layout) {
+        if let Some((ptr, layout)) = self.current_memory(elem_layout) {
+            unsafe {
+                self.alloc.deallocate(ptr, layout);
+            }
+        }
+    }
 }
 
-// This function is outside `RawVec` to minimize compile times. See the comment
-// above `RawVec::grow_amortized` for details. (The `A` parameter isn't
-// significant, because the number of different `A` types seen in practice is
-// much smaller than the number of `T` types.)
 #[inline(never)]
 fn finish_grow<A>(
-    new_layout: Result<Layout, LayoutError>,
+    new_layout: Layout,
     current_memory: Option<(NonNull<u8>, Layout)>,
     alloc: &mut A,
 ) -> Result<NonNull<[u8]>, TryReserveError>
 where
     A: Allocator,
 {
-    // Check for the error here to minimize the size of `RawVec::grow_*`.
-    let new_layout = new_layout.map_err(|_| CapacityOverflow)?;
-
     alloc_guard(new_layout.size())?;
 
     let memory = if let Some((ptr, old_layout)) = current_memory {
@@ -592,15 +779,6 @@ where
     memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }.into())
 }
 
-unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> {
-    /// Frees the memory owned by the `RawVec` *without* trying to drop its contents.
-    fn drop(&mut self) {
-        if let Some((ptr, layout)) = self.current_memory() {
-            unsafe { self.alloc.deallocate(ptr, layout) }
-        }
-    }
-}
-
 // Central function for reserve error handling.
 #[cfg(not(no_global_oom_handling))]
 #[cold]
@@ -627,3 +805,8 @@ fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
         Ok(())
     }
 }
+
+#[inline]
+fn layout_array(cap: usize, elem_layout: Layout) -> Result<Layout, TryReserveError> {
+    elem_layout.repeat(cap).map(|(layout, _pad)| layout).map_err(|_| CapacityOverflow.into())
+}
diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs
index 48c6e5f46f8..d78ded104fb 100644
--- a/library/alloc/src/raw_vec/tests.rs
+++ b/library/alloc/src/raw_vec/tests.rs
@@ -43,9 +43,9 @@ fn allocator_param() {
 
     let a = BoundedAlloc { fuel: Cell::new(500) };
     let mut v: RawVec<u8, _> = RawVec::with_capacity_in(50, a);
-    assert_eq!(v.alloc.fuel.get(), 450);
+    assert_eq!(v.inner.alloc.fuel.get(), 450);
     v.reserve(50, 150); // (causes a realloc, thus using 50 + 150 = 200 units of fuel)
-    assert_eq!(v.alloc.fuel.get(), 250);
+    assert_eq!(v.inner.alloc.fuel.get(), 250);
 }
 
 #[test]
@@ -86,7 +86,7 @@ struct ZST;
 fn zst_sanity<T>(v: &RawVec<T>) {
     assert_eq!(v.capacity(), usize::MAX);
     assert_eq!(v.ptr(), core::ptr::Unique::<T>::dangling().as_ptr());
-    assert_eq!(v.current_memory(), None);
+    assert_eq!(v.inner.current_memory(T::LAYOUT), None);
 }
 
 #[test]
@@ -106,22 +106,11 @@ fn zst() {
     let v: RawVec<ZST> = RawVec::with_capacity_in(100, Global);
     zst_sanity(&v);
 
-    let v: RawVec<ZST> = RawVec::try_allocate_in(0, AllocInit::Uninitialized, Global).unwrap();
-    zst_sanity(&v);
-
-    let v: RawVec<ZST> = RawVec::try_allocate_in(100, AllocInit::Uninitialized, Global).unwrap();
-    zst_sanity(&v);
-
-    let mut v: RawVec<ZST> =
-        RawVec::try_allocate_in(usize::MAX, AllocInit::Uninitialized, Global).unwrap();
+    let mut v: RawVec<ZST> = RawVec::with_capacity_in(usize::MAX, Global);
     zst_sanity(&v);
 
     // Check all these operations work as expected with zero-sized elements.
 
-    assert!(!v.needs_to_grow(100, usize::MAX - 100));
-    assert!(v.needs_to_grow(101, usize::MAX - 100));
-    zst_sanity(&v);
-
     v.reserve(100, usize::MAX - 100);
     //v.reserve(101, usize::MAX - 100); // panics, in `zst_reserve_panic` below
     zst_sanity(&v);
@@ -138,12 +127,12 @@ fn zst() {
     assert_eq!(v.try_reserve_exact(101, usize::MAX - 100), cap_err);
     zst_sanity(&v);
 
-    assert_eq!(v.grow_amortized(100, usize::MAX - 100), cap_err);
-    assert_eq!(v.grow_amortized(101, usize::MAX - 100), cap_err);
+    assert_eq!(v.inner.grow_amortized(100, usize::MAX - 100, ZST::LAYOUT), cap_err);
+    assert_eq!(v.inner.grow_amortized(101, usize::MAX - 100, ZST::LAYOUT), cap_err);
     zst_sanity(&v);
 
-    assert_eq!(v.grow_exact(100, usize::MAX - 100), cap_err);
-    assert_eq!(v.grow_exact(101, usize::MAX - 100), cap_err);
+    assert_eq!(v.inner.grow_exact(100, usize::MAX - 100, ZST::LAYOUT), cap_err);
+    assert_eq!(v.inner.grow_exact(101, usize::MAX - 100, ZST::LAYOUT), cap_err);
     zst_sanity(&v);
 }
 
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index 7dcf344cdc5..9d704870326 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -178,15 +178,25 @@ impl<T> [T] {
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*))
     /// worst-case.
     ///
-    /// If `T: Ord` does not implement a total order the resulting order is unspecified. All
-    /// original elements will remain in the slice and any possible modifications via interior
-    /// mutability are observed in the input. Same is true if `T: Ord` panics.
+    /// If the implementation of [`Ord`] for `T` does not implement a [total order] the resulting
+    /// order of elements in the slice is unspecified. All original elements will remain in the
+    /// slice and any possible modifications via interior mutability are observed in the input. Same
+    /// is true if the implementation of [`Ord`] for `T` panics.
     ///
     /// When applicable, unstable sorting is preferred because it is generally faster than stable
     /// sorting and it doesn't allocate auxiliary memory. See
     /// [`sort_unstable`](slice::sort_unstable). The exception are partially sorted slices, which
     /// may be better served with `slice::sort`.
     ///
+    /// Sorting types that only implement [`PartialOrd`] such as [`f32`] and [`f64`] require
+    /// additional precautions. For example, `f32::NAN != f32::NAN`, which doesn't fulfill the
+    /// reflexivity requirement of [`Ord`]. By using an alternative comparison function with
+    /// `slice::sort_by` such as [`f32::total_cmp`] or [`f64::total_cmp`] that defines a [total
+    /// order] users can sort slices containing floating-point values. Alternatively, if all values
+    /// in the slice are guaranteed to be in a subset for which [`PartialOrd::partial_cmp`] forms a
+    /// [total order], it's possible to sort the slice with `sort_by(|a, b|
+    /// a.partial_cmp(b).unwrap())`.
+    ///
     /// # Current implementation
     ///
     /// The current implementation is based on [driftsort] by Orson Peters and Lukas Bergdoll, which
@@ -198,18 +208,21 @@ impl<T> [T] {
     /// handled without allocation, medium sized slices allocate `self.len()` and beyond that it
     /// clamps at `self.len() / 2`.
     ///
-    /// If `T: Ord` does not implement a total order, the implementation may panic.
+    /// # Panics
+    ///
+    /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order].
     ///
     /// # Examples
     ///
     /// ```
-    /// let mut v = [-5, 4, 1, -3, 2];
+    /// let mut v = [4, -5, 1, -3, 2];
     ///
     /// v.sort();
-    /// assert!(v == [-5, -3, 1, 2, 4]);
+    /// assert_eq!(v, [-5, -3, 1, 2, 4]);
     /// ```
     ///
     /// [driftsort]: https://github.com/Voultapher/driftsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[cfg(not(no_global_oom_handling))]
     #[rustc_allow_incoherent_impl]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -221,30 +234,19 @@ impl<T> [T] {
         stable_sort(self, T::lt);
     }
 
-    /// Sorts the slice with a comparator function, preserving initial order of equal elements.
+    /// Sorts the slice with a comparison function, preserving initial order of equal elements.
     ///
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*))
     /// worst-case.
     ///
-    /// The comparator function should define a total ordering for the elements in the slice. If the
-    /// ordering is not total, the order of the elements is unspecified.
-    ///
-    /// If the comparator function does not implement a total order the resulting order is
-    /// unspecified. All original elements will remain in the slice and any possible modifications
-    /// via interior mutability are observed in the input. Same is true if the comparator function
-    /// panics. A total order (for all `a`, `b` and `c`):
+    /// If the comparison function `compare` does not implement a [total order] the resulting order
+    /// of elements in the slice is unspecified. All original elements will remain in the slice and
+    /// any possible modifications via interior mutability are observed in the input. Same is true
+    /// if `compare` panics.
     ///
-    /// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and
-    /// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
-    ///
-    /// For example, while [`f64`] doesn't implement [`Ord`] because `NaN != NaN`, we can use
-    /// `partial_cmp` as our sort function when we know the slice doesn't contain a `NaN`.
-    ///
-    /// ```
-    /// let mut floats = [5f64, 4.0, 1.0, 3.0, 2.0];
-    /// floats.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
-    /// assert_eq!(floats, [1.0, 2.0, 3.0, 4.0, 5.0]);
-    /// ```
+    /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor
+    /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and
+    /// examples see the [`Ord`] documentation.
     ///
     /// # Current implementation
     ///
@@ -257,21 +259,24 @@ impl<T> [T] {
     /// handled without allocation, medium sized slices allocate `self.len()` and beyond that it
     /// clamps at `self.len() / 2`.
     ///
-    /// If `T: Ord` does not implement a total order, the implementation may panic.
+    /// # Panics
+    ///
+    /// May panic if `compare` does not implement a [total order].
     ///
     /// # Examples
     ///
     /// ```
-    /// let mut v = [5, 4, 1, 3, 2];
+    /// let mut v = [4, -5, 1, -3, 2];
     /// v.sort_by(|a, b| a.cmp(b));
-    /// assert!(v == [1, 2, 3, 4, 5]);
+    /// assert_eq!(v, [-5, -3, 1, 2, 4]);
     ///
     /// // reverse sorting
     /// v.sort_by(|a, b| b.cmp(a));
-    /// assert!(v == [5, 4, 3, 2, 1]);
+    /// assert_eq!(v, [4, 2, 1, -3, -5]);
     /// ```
     ///
     /// [driftsort]: https://github.com/Voultapher/driftsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[cfg(not(no_global_oom_handling))]
     #[rustc_allow_incoherent_impl]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -288,9 +293,10 @@ impl<T> [T] {
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* \* log(*n*))
     /// worst-case, where the key function is *O*(*m*).
     ///
-    /// If `K: Ord` does not implement a total order the resulting order is unspecified.
-    /// All original elements will remain in the slice and any possible modifications via interior
-    /// mutability are observed in the input. Same is true if `K: Ord` panics.
+    /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting
+    /// order of elements in the slice is unspecified. All original elements will remain in the
+    /// slice and any possible modifications via interior mutability are observed in the input. Same
+    /// is true if the implementation of [`Ord`] for `K` panics.
     ///
     /// # Current implementation
     ///
@@ -303,18 +309,21 @@ impl<T> [T] {
     /// handled without allocation, medium sized slices allocate `self.len()` and beyond that it
     /// clamps at `self.len() / 2`.
     ///
-    /// If `K: Ord` does not implement a total order, the implementation may panic.
+    /// # Panics
+    ///
+    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order].
     ///
     /// # Examples
     ///
     /// ```
-    /// let mut v = [-5i32, 4, 1, -3, 2];
+    /// let mut v = [4i32, -5, 1, -3, 2];
     ///
     /// v.sort_by_key(|k| k.abs());
-    /// assert!(v == [1, 2, -3, 4, -5]);
+    /// assert_eq!(v, [1, 2, -3, 4, -5]);
     /// ```
     ///
     /// [driftsort]: https://github.com/Voultapher/driftsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[cfg(not(no_global_oom_handling))]
     #[rustc_allow_incoherent_impl]
     #[stable(feature = "slice_sort_by_key", since = "1.7.0")]
@@ -336,9 +345,10 @@ impl<T> [T] {
     /// storage to remember the results of key evaluation. The order of calls to the key function is
     /// unspecified and may change in future versions of the standard library.
     ///
-    /// If `K: Ord` does not implement a total order the resulting order is unspecified.
-    /// All original elements will remain in the slice and any possible modifications via interior
-    /// mutability are observed in the input. Same is true if `K: Ord` panics.
+    /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting
+    /// order of elements in the slice is unspecified. All original elements will remain in the
+    /// slice and any possible modifications via interior mutability are observed in the input. Same
+    /// is true if the implementation of [`Ord`] for `K` panics.
     ///
     /// For simple key functions (e.g., functions that are property accesses or basic operations),
     /// [`sort_by_key`](slice::sort_by_key) is likely to be faster.
@@ -355,16 +365,22 @@ impl<T> [T] {
     /// In the worst case, the algorithm allocates temporary storage in a `Vec<(K, usize)>` the
     /// length of the slice.
     ///
+    /// # Panics
+    ///
+    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order].
+    ///
     /// # Examples
     ///
     /// ```
-    /// let mut v = [-5i32, 4, 32, -3, 2];
+    /// let mut v = [4i32, -5, 1, -3, 2, 10];
     ///
+    /// // Strings are sorted by lexicographical order.
     /// v.sort_by_cached_key(|k| k.to_string());
-    /// assert!(v == [-3, -5, 2, 32, 4]);
+    /// assert_eq!(v, [-3, -5, 1, 10, 2, 4]);
     /// ```
     ///
     /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[cfg(not(no_global_oom_handling))]
     #[rustc_allow_incoherent_impl]
     #[stable(feature = "slice_sort_by_cached_key", since = "1.34.0")]
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 5c826b9993f..61c713c9e81 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -889,6 +889,7 @@ impl<T> Guard<'_, T> {
 }
 
 impl<T> Drop for Guard<'_, T> {
+    #[inline]
     fn drop(&mut self) {
         debug_assert!(self.initialized <= self.array_mut.len());
 
diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs
index 34a05ac3888..375358dddf5 100644
--- a/library/core/src/ascii/ascii_char.rs
+++ b/library/core/src/ascii/ascii_char.rs
@@ -3,7 +3,7 @@
 //! suggestions from rustc if you get anything slightly wrong in here, and overall
 //! helps with clarity as we're also referring to `char` intentionally in here.
 
-use crate::fmt::{self, Write};
+use crate::fmt;
 use crate::mem::transmute;
 
 /// One of the 128 Unicode characters from U+0000 through U+007F,
@@ -583,9 +583,10 @@ impl fmt::Display for AsciiChar {
 #[unstable(feature = "ascii_char", issue = "110998")]
 impl fmt::Debug for AsciiChar {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        #[inline]
-        fn backslash(a: AsciiChar) -> ([AsciiChar; 4], u8) {
-            ([AsciiChar::ReverseSolidus, a, AsciiChar::Null, AsciiChar::Null], 2)
+        use AsciiChar::{Apostrophe, Null, ReverseSolidus as Backslash};
+
+        fn backslash(a: AsciiChar) -> ([AsciiChar; 6], usize) {
+            ([Apostrophe, Backslash, a, Apostrophe, Null, Null], 4)
         }
 
         let (buf, len) = match self {
@@ -595,24 +596,17 @@ impl fmt::Debug for AsciiChar {
             AsciiChar::LineFeed => backslash(AsciiChar::SmallN),
             AsciiChar::ReverseSolidus => backslash(AsciiChar::ReverseSolidus),
             AsciiChar::Apostrophe => backslash(AsciiChar::Apostrophe),
-            _ => {
-                let byte = self.to_u8();
-                if !byte.is_ascii_control() {
-                    ([*self, AsciiChar::Null, AsciiChar::Null, AsciiChar::Null], 1)
-                } else {
-                    const HEX_DIGITS: [AsciiChar; 16] = *b"0123456789abcdef".as_ascii().unwrap();
+            _ if self.to_u8().is_ascii_control() => {
+                const HEX_DIGITS: [AsciiChar; 16] = *b"0123456789abcdef".as_ascii().unwrap();
 
-                    let hi = HEX_DIGITS[usize::from(byte >> 4)];
-                    let lo = HEX_DIGITS[usize::from(byte & 0xf)];
-                    ([AsciiChar::ReverseSolidus, AsciiChar::SmallX, hi, lo], 4)
-                }
+                let byte = self.to_u8();
+                let hi = HEX_DIGITS[usize::from(byte >> 4)];
+                let lo = HEX_DIGITS[usize::from(byte & 0xf)];
+                ([Apostrophe, Backslash, AsciiChar::SmallX, hi, lo, Apostrophe], 6)
             }
+            _ => ([Apostrophe, *self, Apostrophe, Null, Null, Null], 3),
         };
 
-        f.write_char('\'')?;
-        for byte in &buf[..len as usize] {
-            f.write_str(byte.as_str())?;
-        }
-        f.write_char('\'')
+        f.write_str(buf[..len].as_str())
     }
 }
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 6f1e0cb7471..bd99e90376a 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2675,12 +2675,12 @@ extern "rust-intrinsic" {
     #[rustc_nounwind]
     pub fn catch_unwind(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32;
 
-    /// Emits a `!nontemporal` store according to LLVM (see their docs).
-    /// Probably will never become stable.
+    /// Emits a `nontemporal` store, which gives a hint to the CPU that the data should not be held
+    /// in cache. Except for performance, this is fully equivalent to `ptr.write(val)`.
     ///
-    /// Do NOT use this intrinsic; "nontemporal" operations do not exist in our memory model!
-    /// It exists to support current stdarch, but the plan is to change stdarch and remove this intrinsic.
-    /// See <https://github.com/rust-lang/rust/issues/114582> for some more discussion.
+    /// Not all architectures provide such an operation. For instance, x86 does not: while `MOVNT`
+    /// exists, that operation is *not* equivalent to `ptr.write(val)` (`MOVNT` writes can be reordered
+    /// in ways that are not allowed for regular writes).
     #[rustc_nounwind]
     pub fn nontemporal_store<T>(ptr: *mut T, val: T);
 
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 9d4520d4ee8..07daa32afa8 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -192,6 +192,7 @@
 //
 // Language features:
 // tidy-alphabetical-start
+#![cfg_attr(bootstrap, feature(min_exhaustive_patterns))]
 #![feature(abi_unadjusted)]
 #![feature(adt_const_params)]
 #![feature(allow_internal_unsafe)]
@@ -225,7 +226,6 @@
 #![feature(link_llvm_intrinsics)]
 #![feature(macro_metavar_expr)]
 #![feature(marker_trait_attr)]
-#![feature(min_exhaustive_patterns)]
 #![feature(min_specialization)]
 #![feature(multiple_supertrait_upcastable)]
 #![feature(must_not_suspend)]
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index ea2dcdce6e8..7a9ca4011be 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -5,6 +5,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+use crate::alloc::Layout;
 use crate::marker::DiscriminantKind;
 use crate::{clone, cmp, fmt, hash, intrinsics, ptr};
 
@@ -1238,6 +1239,10 @@ pub trait SizedTypeProperties: Sized {
     #[doc(hidden)]
     #[unstable(feature = "sized_type_properties", issue = "none")]
     const IS_ZST: bool = size_of::<Self>() == 0;
+
+    #[doc(hidden)]
+    #[unstable(feature = "sized_type_properties", issue = "none")]
+    const LAYOUT: Layout = Layout::new::<Self>();
 }
 #[doc(hidden)]
 #[unstable(feature = "sized_type_properties", issue = "none")]
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index b1440214d79..c76157720b7 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -28,6 +28,7 @@ pub mod memchr;
     issue = "none",
     reason = "exposed from core to be reused in std;"
 )]
+#[doc(hidden)]
 pub mod sort;
 
 mod ascii;
@@ -2880,9 +2881,19 @@ impl<T> [T] {
     /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not
     /// allocate), and *O*(*n* \* log(*n*)) worst-case.
     ///
-    /// If `T: Ord` does not implement a total order the resulting order is unspecified. All
-    /// original elements will remain in the slice and any possible modifications via interior
-    /// mutability are observed in the input. Same is true if `T: Ord` panics.
+    /// If the implementation of [`Ord`] for `T` does not implement a [total order] the resulting
+    /// order of elements in the slice is unspecified. All original elements will remain in the
+    /// slice and any possible modifications via interior mutability are observed in the input. Same
+    /// is true if the implementation of [`Ord`] for `T` panics.
+    ///
+    /// Sorting types that only implement [`PartialOrd`] such as [`f32`] and [`f64`] require
+    /// additional precautions. For example, `f32::NAN != f32::NAN`, which doesn't fulfill the
+    /// reflexivity requirement of [`Ord`]. By using an alternative comparison function with
+    /// `slice::sort_unstable_by` such as [`f32::total_cmp`] or [`f64::total_cmp`] that defines a
+    /// [total order] users can sort slices containing floating-point values. Alternatively, if all
+    /// values in the slice are guaranteed to be in a subset for which [`PartialOrd::partial_cmp`]
+    /// forms a [total order], it's possible to sort the slice with `sort_unstable_by(|a, b|
+    /// a.partial_cmp(b).unwrap())`.
     ///
     /// # Current implementation
     ///
@@ -2894,18 +2905,21 @@ impl<T> [T] {
     /// It is typically faster than stable sorting, except in a few special cases, e.g., when the
     /// slice is partially sorted.
     ///
-    /// If `T: Ord` does not implement a total order, the implementation may panic.
+    /// # Panics
+    ///
+    /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order].
     ///
     /// # Examples
     ///
     /// ```
-    /// let mut v = [-5, 4, 1, -3, 2];
+    /// let mut v = [4, -5, 1, -3, 2];
     ///
     /// v.sort_unstable();
-    /// assert!(v == [-5, -3, 1, 2, 4]);
+    /// assert_eq!(v, [-5, -3, 1, 2, 4]);
     /// ```
     ///
     /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[stable(feature = "sort_unstable", since = "1.20.0")]
     #[inline]
     pub fn sort_unstable(&mut self)
@@ -2915,31 +2929,20 @@ impl<T> [T] {
         sort::unstable::sort(self, &mut T::lt);
     }
 
-    /// Sorts the slice with a comparator function, **without** preserving the initial order of
+    /// Sorts the slice with a comparison function, **without** preserving the initial order of
     /// equal elements.
     ///
     /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not
     /// allocate), and *O*(*n* \* log(*n*)) worst-case.
     ///
-    /// The comparator function should define a total ordering for the elements in the slice. If the
-    /// ordering is not total, the order of the elements is unspecified.
-    ///
-    /// If the comparator function does not implement a total order the resulting order is
-    /// unspecified. All original elements will remain in the slice and any possible modifications
-    /// via interior mutability are observed in the input. Same is true if the comparator function
-    /// panics. A total order (for all `a`, `b` and `c`):
-    ///
-    /// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and
-    /// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
+    /// If the comparison function `compare` does not implement a [total order] the resulting order
+    /// of elements in the slice is unspecified. All original elements will remain in the slice and
+    /// any possible modifications via interior mutability are observed in the input. Same is true
+    /// if `compare` panics.
     ///
-    /// For example, while [`f64`] doesn't implement [`Ord`] because `NaN != NaN`, we can use
-    /// `partial_cmp` as our sort function when we know the slice doesn't contain a `NaN`.
-    ///
-    /// ```
-    /// let mut floats = [5f64, 4.0, 1.0, 3.0, 2.0];
-    /// floats.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
-    /// assert_eq!(floats, [1.0, 2.0, 3.0, 4.0, 5.0]);
-    /// ```
+    /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor
+    /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and
+    /// examples see the [`Ord`] documentation.
     ///
     /// # Current implementation
     ///
@@ -2951,21 +2954,24 @@ impl<T> [T] {
     /// It is typically faster than stable sorting, except in a few special cases, e.g., when the
     /// slice is partially sorted.
     ///
-    /// If `T: Ord` does not implement a total order, the implementation may panic.
+    /// # Panics
+    ///
+    /// May panic if `compare` does not implement a [total order].
     ///
     /// # Examples
     ///
     /// ```
-    /// let mut v = [5, 4, 1, 3, 2];
+    /// let mut v = [4, -5, 1, -3, 2];
     /// v.sort_unstable_by(|a, b| a.cmp(b));
-    /// assert!(v == [1, 2, 3, 4, 5]);
+    /// assert_eq!(v, [-5, -3, 1, 2, 4]);
     ///
     /// // reverse sorting
     /// v.sort_unstable_by(|a, b| b.cmp(a));
-    /// assert!(v == [5, 4, 3, 2, 1]);
+    /// assert_eq!(v, [4, 2, 1, -3, -5]);
     /// ```
     ///
     /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[stable(feature = "sort_unstable", since = "1.20.0")]
     #[inline]
     pub fn sort_unstable_by<F>(&mut self, mut compare: F)
@@ -2981,9 +2987,10 @@ impl<T> [T] {
     /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not
     /// allocate), and *O*(*n* \* log(*n*)) worst-case.
     ///
-    /// If `K: Ord` does not implement a total order the resulting order is unspecified.
-    /// All original elements will remain in the slice and any possible modifications via interior
-    /// mutability are observed in the input. Same is true if `K: Ord` panics.
+    /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting
+    /// order of elements in the slice is unspecified. All original elements will remain in the
+    /// slice and any possible modifications via interior mutability are observed in the input. Same
+    /// is true if the implementation of [`Ord`] for `K` panics.
     ///
     /// # Current implementation
     ///
@@ -2995,18 +3002,21 @@ impl<T> [T] {
     /// It is typically faster than stable sorting, except in a few special cases, e.g., when the
     /// slice is partially sorted.
     ///
-    /// If `K: Ord` does not implement a total order, the implementation may panic.
+    /// # Panics
+    ///
+    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order].
     ///
     /// # Examples
     ///
     /// ```
-    /// let mut v = [-5i32, 4, 1, -3, 2];
+    /// let mut v = [4i32, -5, 1, -3, 2];
     ///
     /// v.sort_unstable_by_key(|k| k.abs());
-    /// assert!(v == [1, 2, -3, 4, -5]);
+    /// assert_eq!(v, [1, 2, -3, 4, -5]);
     /// ```
     ///
     /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[stable(feature = "sort_unstable", since = "1.20.0")]
     #[inline]
     pub fn sort_unstable_by_key<K, F>(&mut self, mut f: F)
@@ -3038,15 +3048,14 @@ impl<T> [T] {
     /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime
     /// for all inputs.
     ///
-    /// It is typically faster than stable sorting, except in a few special cases, e.g., when the
-    /// slice is nearly fully sorted, where `slice::sort` may be faster.
-    ///
     /// [`sort_unstable`]: slice::sort_unstable
     ///
     /// # Panics
     ///
     /// Panics when `index >= len()`, meaning it always panics on empty slices.
     ///
+    /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order].
+    ///
     /// # Examples
     ///
     /// ```
@@ -3069,6 +3078,7 @@ impl<T> [T] {
     /// ```
     ///
     /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")]
     #[inline]
     pub fn select_nth_unstable(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T])
@@ -3099,15 +3109,14 @@ impl<T> [T] {
     /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime
     /// for all inputs.
     ///
-    /// It is typically faster than stable sorting, except in a few special cases, e.g., when the
-    /// slice is nearly fully sorted, where `slice::sort` may be faster.
-    ///
     /// [`sort_unstable`]: slice::sort_unstable
     ///
     /// # Panics
     ///
     /// Panics when `index >= len()`, meaning it always panics on empty slices.
     ///
+    /// May panic if `compare` does not implement a [total order].
+    ///
     /// # Examples
     ///
     /// ```
@@ -3130,6 +3139,7 @@ impl<T> [T] {
     /// ```
     ///
     /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")]
     #[inline]
     pub fn select_nth_unstable_by<F>(
@@ -3164,15 +3174,14 @@ impl<T> [T] {
     /// Median of Medians using Tukey's Ninther for pivot selection, which guarantees linear runtime
     /// for all inputs.
     ///
-    /// It is typically faster than stable sorting, except in a few special cases, e.g., when the
-    /// slice is nearly fully sorted, where `slice::sort` may be faster.
-    ///
     /// [`sort_unstable`]: slice::sort_unstable
     ///
     /// # Panics
     ///
     /// Panics when `index >= len()`, meaning it always panics on empty slices.
     ///
+    /// May panic if `K: Ord` does not implement a total order.
+    ///
     /// # Examples
     ///
     /// ```
@@ -3195,6 +3204,7 @@ impl<T> [T] {
     /// ```
     ///
     /// [ipnsort]: https://github.com/Voultapher/sort-research-rs/tree/main/ipnsort
+    /// [total order]: https://en.wikipedia.org/wiki/Total_order
     #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")]
     #[inline]
     pub fn select_nth_unstable_by_key<K, F>(
diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs
index 5064c5a0ae5..db0c5c72822 100644
--- a/library/core/src/slice/sort/shared/smallsort.rs
+++ b/library/core/src/slice/sort/shared/smallsort.rs
@@ -831,9 +831,9 @@ unsafe fn bidirectional_merge<T: FreezeMarker, F: FnMut(&T, &T) -> bool>(
             right = right.add((!left_nonempty) as usize);
         }
 
-        // We now should have consumed the full input exactly once. This can
-        // only fail if the comparison operator fails to be Ord, in which case
-        // we will panic and never access the inconsistent state in dst.
+        // We now should have consumed the full input exactly once. This can only fail if the
+        // user-provided comparison function fails to implement a strict weak ordering. In that case
+        // we panic and never access the inconsistent state in dst.
         if left != left_end || right != right_end {
             panic_on_ord_violation();
         }
@@ -842,7 +842,21 @@ unsafe fn bidirectional_merge<T: FreezeMarker, F: FnMut(&T, &T) -> bool>(
 
 #[inline(never)]
 fn panic_on_ord_violation() -> ! {
-    panic!("Ord violation");
+    // This is indicative of a logic bug in the user-provided comparison function or Ord
+    // implementation. They are expected to implement a total order as explained in the Ord
+    // documentation.
+    //
+    // By panicking we inform the user, that they have a logic bug in their program. If a strict
+    // weak ordering is not given, the concept of comparison based sorting cannot yield a sorted
+    // result. E.g.: a < b < c < a
+    //
+    // The Ord documentation requires users to implement a total order. Arguably that's
+    // unnecessarily strict in the context of sorting. Issues only arise if the weaker requirement
+    // of a strict weak ordering is violated.
+    //
+    // The panic message talks about a total order because that's what the Ord documentation talks
+    // about and requires, so as to not confuse users.
+    panic!("user-provided comparison function does not correctly implement a total order");
 }
 
 #[must_use]
diff --git a/library/core/src/slice/sort/unstable/mod.rs b/library/core/src/slice/sort/unstable/mod.rs
index ed735e1ebfb..932e01f4401 100644
--- a/library/core/src/slice/sort/unstable/mod.rs
+++ b/library/core/src/slice/sort/unstable/mod.rs
@@ -8,7 +8,7 @@ use crate::slice::sort::shared::smallsort::insertion_sort_shift_left;
 pub(crate) mod heapsort;
 pub(crate) mod quicksort;
 
-/// Unstable sort called ipnsort by Lukas Bergdoll.
+/// Unstable sort called ipnsort by Lukas Bergdoll and Orson Peters.
 /// Design document:
 /// <https://github.com/Voultapher/sort-research-rs/blob/main/writeup/ipnsort_introduction/text.md>
 ///
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 8ce3eb2ea39..29932c0d1ff 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -502,6 +502,8 @@ impl Waker {
     #[must_use]
     #[stable(feature = "futures_api", since = "1.36.0")]
     pub fn will_wake(&self, other: &Waker) -> bool {
+        // We optimize this by comparing vtable addresses instead of vtable contents.
+        // This is permitted since the function is documented as best-effort.
         let RawWaker { data: a_data, vtable: a_vtable } = self.waker;
         let RawWaker { data: b_data, vtable: b_vtable } = other.waker;
         a_data == b_data && ptr::eq(a_vtable, b_vtable)
@@ -761,7 +763,11 @@ impl LocalWaker {
     #[must_use]
     #[unstable(feature = "local_waker", issue = "118959")]
     pub fn will_wake(&self, other: &LocalWaker) -> bool {
-        self.waker == other.waker
+        // We optimize this by comparing vtable addresses instead of vtable contents.
+        // This is permitted since the function is documented as best-effort.
+        let RawWaker { data: a_data, vtable: a_vtable } = self.waker;
+        let RawWaker { data: b_data, vtable: b_vtable } = other.waker;
+        a_data == b_data && ptr::eq(a_vtable, b_vtable)
     }
 
     /// Creates a new `LocalWaker` from [`RawWaker`].
diff --git a/library/core/tests/ascii_char.rs b/library/core/tests/ascii_char.rs
new file mode 100644
index 00000000000..75b5fd4b9e6
--- /dev/null
+++ b/library/core/tests/ascii_char.rs
@@ -0,0 +1,28 @@
+use core::ascii::Char;
+use core::fmt::Write;
+
+/// Tests Display implementation for ascii::Char.
+#[test]
+fn test_display() {
+    let want = (0..128u8).map(|b| b as char).collect::<String>();
+    let mut got = String::with_capacity(128);
+    for byte in 0..128 {
+        write!(&mut got, "{}", Char::from_u8(byte).unwrap()).unwrap();
+    }
+    assert_eq!(want, got);
+}
+
+/// Tests Debug implementation for ascii::Char.
+#[test]
+fn test_debug_control() {
+    for byte in 0..128u8 {
+        let mut want = format!("{:?}", byte as char);
+        // `char` uses `'\u{#}'` representation where ascii::char uses `'\x##'`.
+        // Transform former into the latter.
+        if let Some(rest) = want.strip_prefix("'\\u{") {
+            want = format!("'\\x{:0>2}'", rest.strip_suffix("}'").unwrap());
+        }
+        let chr = core::ascii::Char::from_u8(byte).unwrap();
+        assert_eq!(want, format!("{chr:?}"), "byte: {byte}");
+    }
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 1e336bf96b8..8872b4cbfd5 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -122,6 +122,7 @@ mod alloc;
 mod any;
 mod array;
 mod ascii;
+mod ascii_char;
 mod asserting;
 mod async_iter;
 mod atomic;
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 7fc1bc46fef..93a74ef739b 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -272,6 +272,7 @@
 //
 // Language features:
 // tidy-alphabetical-start
+#![cfg_attr(bootstrap, feature(min_exhaustive_patterns))]
 #![feature(alloc_error_handler)]
 #![feature(allocator_internals)]
 #![feature(allow_internal_unsafe)]
@@ -299,7 +300,6 @@
 #![feature(link_cfg)]
 #![feature(linkage)]
 #![feature(macro_metavar_expr_concat)]
-#![feature(min_exhaustive_patterns)]
 #![feature(min_specialization)]
 #![feature(must_not_suspend)]
 #![feature(needs_panic_runtime)]
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index 4c496ade81c..6f0952c41ed 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -440,13 +440,12 @@ impl BacktraceStyle {
     }
 
     fn from_u8(s: u8) -> Option<Self> {
-        Some(match s {
-            0 => return None,
-            1 => BacktraceStyle::Short,
-            2 => BacktraceStyle::Full,
-            3 => BacktraceStyle::Off,
-            _ => unreachable!(),
-        })
+        match s {
+            1 => Some(BacktraceStyle::Short),
+            2 => Some(BacktraceStyle::Full),
+            3 => Some(BacktraceStyle::Off),
+            _ => None,
+        }
     }
 }
 
@@ -465,7 +464,7 @@ static SHOULD_CAPTURE: AtomicU8 = AtomicU8::new(0);
 pub fn set_backtrace_style(style: BacktraceStyle) {
     if cfg!(feature = "backtrace") {
         // If the `backtrace` feature of this crate is enabled, set the backtrace style.
-        SHOULD_CAPTURE.store(style.as_u8(), Ordering::Release);
+        SHOULD_CAPTURE.store(style.as_u8(), Ordering::Relaxed);
     }
 }
 
@@ -498,7 +497,9 @@ pub fn get_backtrace_style() -> Option<BacktraceStyle> {
         // to optimize away callers.
         return None;
     }
-    if let Some(style) = BacktraceStyle::from_u8(SHOULD_CAPTURE.load(Ordering::Acquire)) {
+
+    let current = SHOULD_CAPTURE.load(Ordering::Relaxed);
+    if let Some(style) = BacktraceStyle::from_u8(current) {
         return Some(style);
     }
 
@@ -509,8 +510,11 @@ pub fn get_backtrace_style() -> Option<BacktraceStyle> {
         None if crate::sys::FULL_BACKTRACE_DEFAULT => BacktraceStyle::Full,
         None => BacktraceStyle::Off,
     };
-    set_backtrace_style(format);
-    Some(format)
+
+    match SHOULD_CAPTURE.compare_exchange(0, format.as_u8(), Ordering::Relaxed, Ordering::Relaxed) {
+        Ok(_) => Some(format),
+        Err(new) => BacktraceStyle::from_u8(new),
+    }
 }
 
 #[cfg(test)]
diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs
index dc8b5487a61..f03f03e2d93 100644
--- a/src/bootstrap/src/bin/main.rs
+++ b/src/bootstrap/src/bin/main.rs
@@ -11,13 +11,19 @@ use std::str::FromStr;
 use std::{env, process};
 
 use bootstrap::{
-    find_recent_config_change_ids, human_readable_changes, t, Build, Config, Subcommand,
+    find_recent_config_change_ids, human_readable_changes, t, Build, Config, Flags, Subcommand,
     CONFIG_CHANGE_HISTORY,
 };
 
 fn main() {
     let args = env::args().skip(1).collect::<Vec<_>>();
-    let config = Config::parse(&args);
+
+    if Flags::try_parse_verbose_help(&args) {
+        return;
+    }
+
+    let flags = Flags::parse(&args);
+    let config = Config::parse(flags);
 
     let mut build_lock;
     let _build_lock_guard;
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index 011c289d932..d04e2fbeb78 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -89,6 +89,25 @@ fn main() {
         rustc_real
     };
 
+    // Get the name of the crate we're compiling, if any.
+    let crate_name = parse_value_from_args(&orig_args, "--crate-name");
+
+    // When statically linking `std` into `rustc_driver`, remove `-C prefer-dynamic`
+    if env::var("RUSTC_LINK_STD_INTO_RUSTC_DRIVER").unwrap() == "1"
+        && crate_name == Some("rustc_driver")
+        && stage != "0"
+    {
+        if let Some(pos) = args.iter().enumerate().position(|(i, a)| {
+            a == "-C" && args.get(i + 1).map(|a| a == "prefer-dynamic").unwrap_or(false)
+        }) {
+            args.remove(pos);
+            args.remove(pos);
+        }
+        if let Some(pos) = args.iter().position(|a| a == "-Cprefer-dynamic") {
+            args.remove(pos);
+        }
+    }
+
     let mut cmd = match env::var_os("RUSTC_WRAPPER_REAL") {
         Some(wrapper) if !wrapper.is_empty() => {
             let mut cmd = Command::new(wrapper);
@@ -99,9 +118,6 @@ fn main() {
     };
     cmd.args(&args).env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
 
-    // Get the name of the crate we're compiling, if any.
-    let crate_name = parse_value_from_args(&orig_args, "--crate-name");
-
     if let Some(crate_name) = crate_name {
         if let Some(target) = env::var_os("RUSTC_TIME") {
             if target == "all"
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index ffae245dfb5..c5a1ab78801 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -194,6 +194,7 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool {
     let supported_platforms = [
         // tier 1
         ("aarch64-unknown-linux-gnu", false),
+        ("aarch64-apple-darwin", false),
         ("i686-pc-windows-gnu", false),
         ("i686-pc-windows-msvc", false),
         ("i686-unknown-linux-gnu", false),
@@ -202,7 +203,6 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool {
         ("x86_64-pc-windows-gnu", true),
         ("x86_64-pc-windows-msvc", true),
         // tier 2 with host tools
-        ("aarch64-apple-darwin", false),
         ("aarch64-pc-windows-msvc", false),
         ("aarch64-unknown-linux-musl", false),
         ("arm-unknown-linux-gnueabi", false),
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index 84c23c059e9..ccdeb442af4 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -1106,6 +1106,12 @@ impl<'a> Builder<'a> {
         StepDescription::run(v, self, paths);
     }
 
+    /// Returns if `std` should be statically linked into `rustc_driver`.
+    /// It's currently not done on `windows-gnu` due to linker bugs.
+    pub fn link_std_into_rustc_driver(&self, target: TargetSelection) -> bool {
+        !target.triple.ends_with("-windows-gnu")
+    }
+
     /// Obtain a compiler at a given stage and for a given host (i.e., this is the target that the
     /// compiler will run on, *not* the target it will build code for). Explicitly does not take
     /// `Compiler` since all `Compiler` instances are meant to be obtained through this function,
@@ -2162,10 +2168,18 @@ impl<'a> Builder<'a> {
         // When we build Rust dylibs they're all intended for intermediate
         // usage, so make sure we pass the -Cprefer-dynamic flag instead of
         // linking all deps statically into the dylib.
-        if matches!(mode, Mode::Std | Mode::Rustc) {
+        if matches!(mode, Mode::Std) {
+            rustflags.arg("-Cprefer-dynamic");
+        }
+        if matches!(mode, Mode::Rustc) && !self.link_std_into_rustc_driver(target) {
             rustflags.arg("-Cprefer-dynamic");
         }
 
+        cargo.env(
+            "RUSTC_LINK_STD_INTO_RUSTC_DRIVER",
+            if self.link_std_into_rustc_driver(target) { "1" } else { "0" },
+        );
+
         // When building incrementally we default to a lower ThinLTO import limit
         // (unless explicitly specified otherwise). This will produce a somewhat
         // slower code but give way better compile times.
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index f19a4dd6d49..e06df65c1bc 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -3,13 +3,14 @@ use std::thread;
 use super::*;
 use crate::core::build_steps::doc::DocumentationFormat;
 use crate::core::config::Config;
+use crate::Flags;
 
 fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
     configure_with_args(&[cmd.to_owned()], host, target)
 }
 
 fn configure_with_args(cmd: &[String], host: &[&str], target: &[&str]) -> Config {
-    let mut config = Config::parse(cmd);
+    let mut config = Config::parse(Flags::parse(cmd));
     // don't save toolstates
     config.save_toolstates = None;
     config.dry_run = DryRun::SelfCheck;
@@ -23,7 +24,7 @@ fn configure_with_args(cmd: &[String], host: &[&str], target: &[&str]) -> Config
     let submodule_build = Build::new(Config {
         // don't include LLVM, so CI doesn't require ninja/cmake to be installed
         rust_codegen_backends: vec![],
-        ..Config::parse(&["check".to_owned()])
+        ..Config::parse(Flags::parse(&["check".to_owned()]))
     });
     submodule_build.require_submodule("src/doc/book", None);
     config.submodules = Some(false);
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 915fcb449e8..35ee4a29c68 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -1191,7 +1191,7 @@ impl Config {
         }
     }
 
-    pub fn parse(args: &[String]) -> Config {
+    pub fn parse(flags: Flags) -> Config {
         #[cfg(test)]
         fn get_toml(_: &Path) -> TomlConfig {
             TomlConfig::default()
@@ -1221,11 +1221,10 @@ impl Config {
                     exit!(2);
                 })
         }
-        Self::parse_inner(args, get_toml)
+        Self::parse_inner(flags, get_toml)
     }
 
-    pub(crate) fn parse_inner(args: &[String], get_toml: impl Fn(&Path) -> TomlConfig) -> Config {
-        let mut flags = Flags::parse(args);
+    pub(crate) fn parse_inner(mut flags: Flags, get_toml: impl Fn(&Path) -> TomlConfig) -> Config {
         let mut config = Config::default_opts();
 
         // Set flags.
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index 19f752da81c..3948fe0d98c 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -183,9 +183,9 @@ pub struct Flags {
 }
 
 impl Flags {
-    pub fn parse(args: &[String]) -> Self {
-        let first = String::from("x.py");
-        let it = std::iter::once(&first).chain(args.iter());
+    /// Check if `<cmd> -h -v` was passed.
+    /// If yes, print the available paths and return `true`.
+    pub fn try_parse_verbose_help(args: &[String]) -> bool {
         // We need to check for `<cmd> -h -v`, in which case we list the paths
         #[derive(Parser)]
         #[command(disable_help_flag(true))]
@@ -198,10 +198,10 @@ impl Flags {
             cmd: Kind,
         }
         if let Ok(HelpVerboseOnly { help: true, verbose: 1.., cmd: subcommand }) =
-            HelpVerboseOnly::try_parse_from(it.clone())
+            HelpVerboseOnly::try_parse_from(normalize_args(args))
         {
             println!("NOTE: updating submodules before printing available paths");
-            let config = Config::parse(&[String::from("build")]);
+            let config = Config::parse(Self::parse(&[String::from("build")]));
             let build = Build::new(config);
             let paths = Builder::get_help(&build, subcommand);
             if let Some(s) = paths {
@@ -209,13 +209,23 @@ impl Flags {
             } else {
                 panic!("No paths available for subcommand `{}`", subcommand.as_str());
             }
-            crate::exit!(0);
+            true
+        } else {
+            false
         }
+    }
 
-        Flags::parse_from(it)
+    pub fn parse(args: &[String]) -> Self {
+        Flags::parse_from(normalize_args(args))
     }
 }
 
+fn normalize_args(args: &[String]) -> Vec<String> {
+    let first = String::from("x.py");
+    let it = std::iter::once(first).chain(args.iter().cloned());
+    it.collect()
+}
+
 #[derive(Debug, Clone, Default, clap::Subcommand)]
 pub enum Subcommand {
     #[command(aliases = ["b"], long_about = "\n
diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs
index 23556e8bc5d..9f09dd13f29 100644
--- a/src/bootstrap/src/core/config/mod.rs
+++ b/src/bootstrap/src/core/config/mod.rs
@@ -1,6 +1,6 @@
 #[allow(clippy::module_inception)]
 mod config;
-pub(crate) mod flags;
+pub mod flags;
 #[cfg(test)]
 mod tests;
 
diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs
index 6e695d269cf..40f3e5e7222 100644
--- a/src/bootstrap/src/core/config/tests.rs
+++ b/src/bootstrap/src/core/config/tests.rs
@@ -12,9 +12,10 @@ use crate::core::build_steps::clippy::get_clippy_rules_in_order;
 use crate::core::config::{LldMode, Target, TargetSelection, TomlConfig};
 
 fn parse(config: &str) -> Config {
-    Config::parse_inner(&["check".to_string(), "--config=/does/not/exist".to_string()], |&_| {
-        toml::from_str(&config).unwrap()
-    })
+    Config::parse_inner(
+        Flags::parse(&["check".to_string(), "--config=/does/not/exist".to_string()]),
+        |&_| toml::from_str(&config).unwrap(),
+    )
 }
 
 #[test]
@@ -108,7 +109,7 @@ fn clap_verify() {
 #[test]
 fn override_toml() {
     let config = Config::parse_inner(
-        &[
+        Flags::parse(&[
             "check".to_owned(),
             "--config=/does/not/exist".to_owned(),
             "--set=change-id=1".to_owned(),
@@ -121,7 +122,7 @@ fn override_toml() {
             "--set=target.x86_64-unknown-linux-gnu.rpath=false".to_owned(),
             "--set=target.aarch64-unknown-linux-gnu.sanitizers=false".to_owned(),
             "--set=target.aarch64-apple-darwin.runner=apple".to_owned(),
-        ],
+        ]),
         |&_| {
             toml::from_str(
                 r#"
@@ -201,12 +202,12 @@ runner = "x86_64-runner"
 #[should_panic]
 fn override_toml_duplicate() {
     Config::parse_inner(
-        &[
+        Flags::parse(&[
             "check".to_owned(),
             "--config=/does/not/exist".to_string(),
             "--set=change-id=1".to_owned(),
             "--set=change-id=2".to_owned(),
-        ],
+        ]),
         |&_| toml::from_str("change-id = 0").unwrap(),
     );
 }
@@ -226,7 +227,7 @@ fn profile_user_dist() {
             .and_then(|table: toml::Value| TomlConfig::deserialize(table))
             .unwrap()
     }
-    Config::parse_inner(&["check".to_owned()], get_toml);
+    Config::parse_inner(Flags::parse(&["check".to_owned()]), get_toml);
 }
 
 #[test]
@@ -301,7 +302,7 @@ fn order_of_clippy_rules() {
         "-Aclippy::foo1".to_string(),
         "-Aclippy::foo2".to_string(),
     ];
-    let config = Config::parse(&args);
+    let config = Config::parse(Flags::parse(&args));
 
     let actual = match &config.cmd {
         crate::Subcommand::Clippy { allow, deny, warn, forbid, .. } => {
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 2062d435bfc..e8a61ab4cf5 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -43,7 +43,7 @@ mod core;
 mod utils;
 
 pub use core::builder::PathSet;
-pub use core::config::flags::Subcommand;
+pub use core::config::flags::{Flags, Subcommand};
 pub use core::config::Config;
 
 pub use utils::change_tracker::{
diff --git a/src/bootstrap/src/utils/helpers/tests.rs b/src/bootstrap/src/utils/helpers/tests.rs
index f0cb324674f..103c4d26a18 100644
--- a/src/bootstrap/src/utils/helpers/tests.rs
+++ b/src/bootstrap/src/utils/helpers/tests.rs
@@ -5,7 +5,7 @@ use std::path::PathBuf;
 use crate::utils::helpers::{
     check_cfg_arg, extract_beta_rev, hex_encode, make, program_out_of_date, symlink_dir,
 };
-use crate::Config;
+use crate::{Config, Flags};
 
 #[test]
 fn test_make() {
@@ -58,7 +58,8 @@ fn test_check_cfg_arg() {
 
 #[test]
 fn test_program_out_of_date() {
-    let config = Config::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]);
+    let config =
+        Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]));
     let tempfile = config.tempdir().join(".tmp-stamp-file");
     File::create(&tempfile).unwrap().write_all(b"dummy value").unwrap();
     assert!(tempfile.exists());
@@ -73,7 +74,8 @@ fn test_program_out_of_date() {
 
 #[test]
 fn test_symlink_dir() {
-    let config = Config::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]);
+    let config =
+        Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]));
     let tempdir = config.tempdir().join(".tmp-dir");
     let link_path = config.tempdir().join(".tmp-link");
 
diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index 72ab8ab5ce9..fa23e3e414d 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -96,9 +96,7 @@ This modifier translates to `--whole-archive` for `ld`-like linkers,
 to `/WHOLEARCHIVE` for `link.exe`, and to `-force_load` for `ld64`.
 The modifier does nothing for linkers that don't support it.
 
-The default for this modifier is `-whole-archive`. \
-NOTE: The default may currently be different in some cases for backward compatibility,
-but it is not guaranteed. If you need whole archive semantics use `+whole-archive` explicitly.
+The default for this modifier is `-whole-archive`.
 
 ### Linking modifiers: `bundle`
 
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 90e30f85bd6..bd12172ecbb 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -33,6 +33,7 @@ All tier 1 targets with host tools support the full standard library.
 target | notes
 -------|-------
 `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+)
+[`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+)
 `i686-pc-windows-gnu` | 32-bit MinGW (Windows 10+, Windows Server 2016+) [^x86_32-floats-return-ABI]
 `i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+) [^x86_32-floats-return-ABI]
 `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+) [^x86_32-floats-return-ABI]
@@ -86,7 +87,6 @@ so Rustup may install the documentation for a similar tier 1 target instead.
 
 target | notes
 -------|-------
-[`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+)
 `aarch64-pc-windows-msvc` | ARM64 Windows MSVC
 `aarch64-unknown-linux-musl` | ARM64 Linux with musl 1.2.3
 `arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2, glibc 2.17)
diff --git a/src/doc/rustc/src/platform-support/apple-darwin.md b/src/doc/rustc/src/platform-support/apple-darwin.md
index 0fb86949a4b..c3a7b81f411 100644
--- a/src/doc/rustc/src/platform-support/apple-darwin.md
+++ b/src/doc/rustc/src/platform-support/apple-darwin.md
@@ -5,9 +5,6 @@ Apple macOS targets.
 **Tier: 1**
 
 - `x86_64-apple-darwin`: macOS on 64-bit x86.
-
-**Tier: 2 (with Host Tools)**
-
 - `aarch64-apple-darwin`: macOS on ARM64 (M1-family or later Apple Silicon CPUs).
 
 ## Target maintainers
diff --git a/src/doc/unstable-book/src/language-features/rustc-private.md b/src/doc/unstable-book/src/language-features/rustc-private.md
new file mode 100644
index 00000000000..97fce5980e4
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/rustc-private.md
@@ -0,0 +1,11 @@
+# `rustc_private`
+
+The tracking issue for this feature is: [#27812]
+
+[#27812]: https://github.com/rust-lang/rust/issues/27812
+
+------------------------
+
+This feature allows access to unstable internal compiler crates.
+
+Additionally it changes the linking behavior of crates which have this feature enabled. It will prevent linking to a dylib if there's a static variant of it already statically linked into another dylib dependency. This is required to successfully link to `rustc_driver`.
diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py
index 227695cdadd..e8f9dee07d3 100644
--- a/src/etc/gdb_providers.py
+++ b/src/etc/gdb_providers.py
@@ -56,7 +56,7 @@ class StdStringProvider(printer_base):
         self._valobj = valobj
         vec = valobj["vec"]
         self._length = int(vec["len"])
-        self._data_ptr = unwrap_unique_or_non_null(vec["buf"]["ptr"])
+        self._data_ptr = unwrap_unique_or_non_null(vec["buf"]["inner"]["ptr"])
 
     def to_string(self):
         return self._data_ptr.lazy_string(encoding="utf-8", length=self._length)
@@ -74,7 +74,7 @@ class StdOsStringProvider(printer_base):
         vec = buf[ZERO_FIELD] if is_windows else buf
 
         self._length = int(vec["len"])
-        self._data_ptr = unwrap_unique_or_non_null(vec["buf"]["ptr"])
+        self._data_ptr = unwrap_unique_or_non_null(vec["buf"]["inner"]["ptr"])
 
     def to_string(self):
         return self._data_ptr.lazy_string(encoding="utf-8", length=self._length)
@@ -96,6 +96,7 @@ class StdStrProvider(printer_base):
     def display_hint():
         return "string"
 
+
 def _enumerate_array_elements(element_ptrs):
     for (i, element_ptr) in enumerate(element_ptrs):
         key = "[{}]".format(i)
@@ -112,6 +113,7 @@ def _enumerate_array_elements(element_ptrs):
 
         yield key, element
 
+
 class StdSliceProvider(printer_base):
     def __init__(self, valobj):
         self._valobj = valobj
@@ -130,11 +132,14 @@ class StdSliceProvider(printer_base):
     def display_hint():
         return "array"
 
+
 class StdVecProvider(printer_base):
     def __init__(self, valobj):
         self._valobj = valobj
         self._length = int(valobj["len"])
-        self._data_ptr = unwrap_unique_or_non_null(valobj["buf"]["ptr"])
+        self._data_ptr = unwrap_unique_or_non_null(valobj["buf"]["inner"]["ptr"])
+        ptr_ty = gdb.Type.pointer(valobj.type.template_argument(0))
+        self._data_ptr = self._data_ptr.reinterpret_cast(ptr_ty)
 
     def to_string(self):
         return "Vec(size={})".format(self._length)
@@ -155,11 +160,13 @@ class StdVecDequeProvider(printer_base):
         self._head = int(valobj["head"])
         self._size = int(valobj["len"])
         # BACKCOMPAT: rust 1.75
-        cap = valobj["buf"]["cap"]
+        cap = valobj["buf"]["inner"]["cap"]
         if cap.type.code != gdb.TYPE_CODE_INT:
             cap = cap[ZERO_FIELD]
         self._cap = int(cap)
-        self._data_ptr = unwrap_unique_or_non_null(valobj["buf"]["ptr"])
+        self._data_ptr = unwrap_unique_or_non_null(valobj["buf"]["inner"]["ptr"])
+        ptr_ty = gdb.Type.pointer(valobj.type.template_argument(0))
+        self._data_ptr = self._data_ptr.reinterpret_cast(ptr_ty)
 
     def to_string(self):
         return "VecDeque(size={})".format(self._size)
diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index c6330117380..8750d7682d1 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -389,11 +389,11 @@ class StdVecSyntheticProvider:
     def update(self):
         # type: () -> None
         self.length = self.valobj.GetChildMemberWithName("len").GetValueAsUnsigned()
-        self.buf = self.valobj.GetChildMemberWithName("buf")
+        self.buf = self.valobj.GetChildMemberWithName("buf").GetChildMemberWithName("inner")
 
         self.data_ptr = unwrap_unique_or_non_null(self.buf.GetChildMemberWithName("ptr"))
 
-        self.element_type = self.data_ptr.GetType().GetPointeeType()
+        self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
         self.element_type_size = self.element_type.GetByteSize()
 
     def has_children(self):
@@ -474,7 +474,7 @@ class StdVecDequeSyntheticProvider:
         # type: () -> None
         self.head = self.valobj.GetChildMemberWithName("head").GetValueAsUnsigned()
         self.size = self.valobj.GetChildMemberWithName("len").GetValueAsUnsigned()
-        self.buf = self.valobj.GetChildMemberWithName("buf")
+        self.buf = self.valobj.GetChildMemberWithName("buf").GetChildMemberWithName("inner")
         cap = self.buf.GetChildMemberWithName("cap")
         if cap.GetType().num_fields == 1:
             cap = cap.GetChildAtIndex(0)
@@ -482,7 +482,7 @@ class StdVecDequeSyntheticProvider:
 
         self.data_ptr = unwrap_unique_or_non_null(self.buf.GetChildMemberWithName("ptr"))
 
-        self.element_type = self.data_ptr.GetType().GetPointeeType()
+        self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
         self.element_type_size = self.element_type.GetByteSize()
 
     def has_children(self):
diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis
index da307809f7b..49d82dfad82 100644
--- a/src/etc/natvis/liballoc.natvis
+++ b/src/etc/natvis/liballoc.natvis
@@ -4,10 +4,10 @@
     <DisplayString>{{ len={len} }}</DisplayString>
     <Expand>
       <Item Name="[len]" ExcludeView="simple">len</Item>
-      <Item Name="[capacity]" ExcludeView="simple">buf.cap.__0</Item>
+      <Item Name="[capacity]" ExcludeView="simple">buf.inner.cap.__0</Item>
       <ArrayItems>
         <Size>len</Size>
-        <ValuePointer>buf.ptr.pointer.pointer</ValuePointer>
+        <ValuePointer>($T1*)buf.inner.ptr.pointer.pointer</ValuePointer>
       </ArrayItems>
     </Expand>
   </Type>
@@ -15,7 +15,7 @@
     <DisplayString>{{ len={len} }}</DisplayString>
     <Expand>
       <Item Name="[len]" ExcludeView="simple">len</Item>
-      <Item Name="[capacity]" ExcludeView="simple">buf.cap.__0</Item>
+      <Item Name="[capacity]" ExcludeView="simple">buf.inner.cap.__0</Item>
       <CustomListItems>
         <Variable Name="i" InitialValue="0" />
         <Size>len</Size>
@@ -23,7 +23,7 @@
           <If Condition="i == len">
             <Break/>
           </If>
-          <Item>buf.ptr.pointer.pointer[(i + head) % buf.cap.__0]</Item>
+          <Item>(($T1*)buf.inner.ptr.pointer.pointer)[(i + head) % buf.inner.cap.__0]</Item>
           <Exec>i = i + 1</Exec>
         </Loop>
       </CustomListItems>
@@ -41,17 +41,17 @@
     </Expand>
   </Type>
   <Type Name="alloc::string::String">
-    <DisplayString>{(char*)vec.buf.ptr.pointer.pointer,[vec.len]s8}</DisplayString>
-    <StringView>(char*)vec.buf.ptr.pointer.pointer,[vec.len]s8</StringView>
+    <DisplayString>{(char*)vec.buf.inner.ptr.pointer.pointer,[vec.len]s8}</DisplayString>
+    <StringView>(char*)vec.buf.inner.ptr.pointer.pointer,[vec.len]s8</StringView>
     <Expand>
       <Item Name="[len]" ExcludeView="simple">vec.len</Item>
-      <Item Name="[capacity]" ExcludeView="simple">vec.buf.cap.__0</Item>
+      <Item Name="[capacity]" ExcludeView="simple">vec.buf.inner.cap.__0</Item>
       <Synthetic Name="[chars]">
-        <DisplayString>{(char*)vec.buf.ptr.pointer.pointer,[vec.len]s8}</DisplayString>
+        <DisplayString>{(char*)vec.buf.inner.ptr.pointer.pointer,[vec.len]s8}</DisplayString>
         <Expand>
           <ArrayItems>
             <Size>vec.len</Size>
-            <ValuePointer>(char*)vec.buf.ptr.pointer.pointer</ValuePointer>
+            <ValuePointer>(char*)vec.buf.inner.ptr.pointer.pointer</ValuePointer>
           </ArrayItems>
         </Expand>
       </Synthetic>
diff --git a/src/etc/natvis/libstd.natvis b/src/etc/natvis/libstd.natvis
index 4371b995318..4719a479c47 100644
--- a/src/etc/natvis/libstd.natvis
+++ b/src/etc/natvis/libstd.natvis
@@ -104,14 +104,14 @@
   </Type>
 
   <Type Name="std::ffi::os_str::OsString">
-    <DisplayString>{(char*)inner.inner.bytes.buf.ptr.pointer.pointer,[inner.inner.bytes.len]}</DisplayString>
+    <DisplayString>{(char*)inner.inner.bytes.buf.inner.ptr.pointer.pointer,[inner.inner.bytes.len]}</DisplayString>
     <Expand>
       <Synthetic Name="[chars]">
-        <DisplayString>{(char*)inner.inner.bytes.buf.ptr.pointer.pointer,[inner.inner.bytes.len]}</DisplayString>
+        <DisplayString>{(char*)inner.inner.bytes.buf.inner.ptr.pointer.pointer,[inner.inner.bytes.len]}</DisplayString>
         <Expand>
           <ArrayItems>
             <Size>inner.inner.bytes.len</Size>
-            <ValuePointer>(char*)inner.inner.bytes.buf.ptr.pointer.pointer</ValuePointer>
+            <ValuePointer>(char*)inner.inner.bytes.buf.inner.ptr.pointer.pointer</ValuePointer>
           </ArrayItems>
         </Expand>
       </Synthetic>
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 4850500a1bf..ff5c16f2b3e 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -2446,6 +2446,10 @@ impl Impl {
             .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name).collect())
             .unwrap_or_default()
     }
+
+    pub(crate) fn is_negative_trait_impl(&self) -> bool {
+        matches!(self.polarity, ty::ImplPolarity::Negative)
+    }
 }
 
 #[derive(Clone, Debug)]
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index b5ab6a35fdb..6357cfee141 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1285,9 +1285,8 @@ impl clean::Impl {
             f.write_str(" ")?;
 
             if let Some(ref ty) = self.trait_ {
-                match self.polarity {
-                    ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => {}
-                    ty::ImplPolarity::Negative => write!(f, "!")?,
+                if self.is_negative_trait_impl() {
+                    write!(f, "!")?;
                 }
                 ty.print(cx).fmt(f)?;
                 write!(f, " for ")?;
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index bb8d39aaf1d..c41db654112 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -304,7 +304,8 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
             Some(format!(
                 "<a class=\"test-arrow\" \
                     target=\"_blank\" \
-                    href=\"{url}?code={test_escaped}{channel}&amp;edition={edition}\">Run</a>",
+                    title=\"Run code\" \
+                    href=\"{url}?code={test_escaped}{channel}&amp;edition={edition}\"></a>",
             ))
         });
 
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 9074e40a536..7ce637d3ab4 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1780,20 +1780,23 @@ fn render_impl(
 
     let mut impl_items = Buffer::empty_from(w);
     let mut default_impl_items = Buffer::empty_from(w);
+    let impl_ = i.inner_impl();
 
-    for trait_item in &i.inner_impl().items {
-        doc_impl_item(
-            &mut default_impl_items,
-            &mut impl_items,
-            cx,
-            trait_item,
-            if trait_.is_some() { &i.impl_item } else { parent },
-            link,
-            render_mode,
-            false,
-            trait_,
-            rendering_params,
-        );
+    if !impl_.is_negative_trait_impl() {
+        for trait_item in &impl_.items {
+            doc_impl_item(
+                &mut default_impl_items,
+                &mut impl_items,
+                cx,
+                trait_item,
+                if trait_.is_some() { &i.impl_item } else { parent },
+                link,
+                render_mode,
+                false,
+                trait_,
+                rendering_params,
+            );
+        }
     }
 
     fn render_default_items(
@@ -1844,13 +1847,15 @@ fn render_impl(
     // We don't emit documentation for default items if they appear in the
     // Implementations on Foreign Types or Implementors sections.
     if rendering_params.show_default_items {
-        if let Some(t) = trait_ {
+        if let Some(t) = trait_
+            && !impl_.is_negative_trait_impl()
+        {
             render_default_items(
                 &mut default_impl_items,
                 &mut impl_items,
                 cx,
                 t,
-                i.inner_impl(),
+                impl_,
                 &i.impl_item,
                 render_mode,
                 rendering_params,
@@ -1882,7 +1887,7 @@ fn render_impl(
         }
 
         if let Some(ref dox) = i.impl_item.opt_doc_value() {
-            if trait_.is_none() && i.inner_impl().items.is_empty() {
+            if trait_.is_none() && impl_.items.is_empty() {
                 w.write_str(
                     "<div class=\"item-info\">\
                          <div class=\"stab empty-impl\">This impl block contains no items.</div>\
diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css
index 6e10cf21537..86e8edad703 100644
--- a/src/librustdoc/html/static/css/noscript.css
+++ b/src/librustdoc/html/static/css/noscript.css
@@ -104,10 +104,6 @@ nav.sub {
 	--code-highlight-doc-comment-color: #4d4d4c;
 	--src-line-numbers-span-color: #c67e2d;
 	--src-line-number-highlighted-background-color: #fdffd3;
-	--test-arrow-color: #f5f5f5;
-	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
-	--test-arrow-hover-color: #f5f5f5;
-	--test-arrow-hover-background-color: rgb(78, 139, 202);
 	--target-background-color: #fdffd3;
 	--target-border-color: #ad7c37;
 	--kbd-color: #000;
@@ -210,10 +206,6 @@ nav.sub {
 		--code-highlight-doc-comment-color: #8ca375;
 		--src-line-numbers-span-color: #3b91e2;
 		--src-line-number-highlighted-background-color: #0a042f;
-		--test-arrow-color: #dedede;
-		--test-arrow-background-color: rgba(78, 139, 202, 0.2);
-		--test-arrow-hover-color: #dedede;
-		--test-arrow-hover-background-color: #4e8bca;
 		--target-background-color: #494a3d;
 		--target-border-color: #bb7410;
 		--kbd-color: #000;
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 02a6bb8f548..eb5a5d935e2 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -353,7 +353,7 @@ details:not(.toggle) summary {
 	margin-bottom: .6em;
 }
 
-code, pre, a.test-arrow, .code-header {
+code, pre, .code-header {
 	font-family: "Source Code Pro", monospace;
 }
 .docblock code, .docblock-short code {
@@ -946,8 +946,8 @@ because of the `[-]` element which would overlap with it. */
 .main-heading a:hover,
 .example-wrap .rust a:hover,
 .all-items a:hover,
-.docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover:not(.doc-anchor),
-.docblock-short a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover,
+.docblock a:not(.scrape-help):not(.tooltip):hover:not(.doc-anchor),
+.docblock-short a:not(.scrape-help):not(.tooltip):hover,
 .item-info a {
 	text-decoration: underline;
 }
@@ -1461,22 +1461,17 @@ documentation. */
 	z-index: 1;
 }
 a.test-arrow {
-	padding: 5px 7px;
-	border-radius: var(--button-border-radius);
-	font-size: 1rem;
-	color: var(--test-arrow-color);
-	background-color: var(--test-arrow-background-color);
+	height: var(--copy-path-height);
+	padding: 6px 4px 0 11px;
 }
-a.test-arrow:hover {
-	color: var(--test-arrow-hover-color);
-	background-color: var(--test-arrow-hover-background-color);
+a.test-arrow::before {
+	content: url('data:image/svg+xml,<svg viewBox="0 0 20 20" width="18" height="20" \
+		xmlns="http://www.w3.org/2000/svg"><path d="M0 0l18 10-18 10z"/></svg>');
 }
 .example-wrap .button-holder {
 	display: flex;
 }
-.example-wrap:hover > .test-arrow {
-	padding: 2px 7px;
-}
+
 /*
 On iPad, the ":hover" state sticks around, making things work not greatly. Do work around
 it, we move it into this media query. More information can be found at:
@@ -1486,29 +1481,34 @@ However, using `@media (hover: hover)` makes this rule never to be applied in GU
 instead, we check that it's not a "finger" cursor.
 */
 @media not (pointer: coarse) {
-	.example-wrap:hover > .test-arrow, .example-wrap:hover > .button-holder {
+	.example-wrap:hover > a.test-arrow, .example-wrap:hover > .button-holder {
 		visibility: visible;
 	}
 }
 .example-wrap .button-holder.keep-visible {
 	visibility: visible;
 }
-.example-wrap .button-holder .copy-button {
-	color: var(--copy-path-button-color);
+.example-wrap .button-holder .copy-button, .example-wrap .test-arrow {
 	background: var(--main-background-color);
+	cursor: pointer;
+	border-radius: var(--button-border-radius);
 	height: var(--copy-path-height);
 	width: var(--copy-path-width);
+}
+.example-wrap .button-holder .copy-button {
 	margin-left: var(--button-left-margin);
 	padding: 2px 0 0 4px;
 	border: 0;
-	cursor: pointer;
-	border-radius: var(--button-border-radius);
 }
-.example-wrap .button-holder .copy-button::before {
+.example-wrap .button-holder .copy-button::before,
+.example-wrap .test-arrow::before {
 	filter: var(--copy-path-img-filter);
+}
+.example-wrap .button-holder .copy-button::before {
 	content: var(--clipboard-image);
 }
-.example-wrap .button-holder .copy-button:hover::before {
+.example-wrap .button-holder .copy-button:hover::before,
+.example-wrap .test-arrow:hover::before {
 	filter: var(--copy-path-img-hover-filter);
 }
 .example-wrap .button-holder .copy-button.clicked::before {
@@ -2552,10 +2552,6 @@ by default.
 	--code-highlight-doc-comment-color: #4d4d4c;
 	--src-line-numbers-span-color: #c67e2d;
 	--src-line-number-highlighted-background-color: #fdffd3;
-	--test-arrow-color: #f5f5f5;
-	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
-	--test-arrow-hover-color: #f5f5f5;
-	--test-arrow-hover-background-color: rgb(78, 139, 202);
 	--target-background-color: #fdffd3;
 	--target-border-color: #ad7c37;
 	--kbd-color: #000;
@@ -2658,10 +2654,6 @@ by default.
 	--code-highlight-doc-comment-color: #8ca375;
 	--src-line-numbers-span-color: #3b91e2;
 	--src-line-number-highlighted-background-color: #0a042f;
-	--test-arrow-color: #dedede;
-	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
-	--test-arrow-hover-color: #dedede;
-	--test-arrow-hover-background-color: #4e8bca;
 	--target-background-color: #494a3d;
 	--target-border-color: #bb7410;
 	--kbd-color: #000;
@@ -2771,10 +2763,6 @@ Original by Dempfi (https://github.com/dempfi/ayu)
 	--code-highlight-doc-comment-color: #a1ac88;
 	--src-line-numbers-span-color: #5c6773;
 	--src-line-number-highlighted-background-color: rgba(255, 236, 164, 0.06);
-	--test-arrow-color: #788797;
-	--test-arrow-background-color: rgba(57, 175, 215, 0.09);
-	--test-arrow-hover-color: #c5c5c5;
-	--test-arrow-hover-background-color: rgba(57, 175, 215, 0.368);
 	--target-background-color: rgba(255, 236, 164, 0.06);
 	--target-border-color: rgba(255, 180, 76, 0.85);
 	--kbd-color: #c5c5c5;
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 62fbde6f225..75f2a1418cd 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -1835,10 +1835,14 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     function getExampleWrap(event) {
         let elem = event.target;
         while (!hasClass(elem, "example-wrap")) {
-            elem = elem.parentElement;
-            if (elem === document.body || hasClass(elem, "docblock")) {
+            if (elem === document.body ||
+                elem.tagName === "A" ||
+                elem.tagName === "BUTTON" ||
+                hasClass(elem, "docblock")
+            ) {
                 return null;
             }
+            elem = elem.parentElement;
         }
         return elem;
     }
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 57ae1a3474057fead2c438928ed368b3740bf0e
+Subproject ccf4c38bdd73f1a37ec266c73bdaef80e39f8cf
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index a93ac6ccaf1..999134a4090 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -634,7 +634,7 @@ pub struct Discriminant {
     /// hexadecimal, and underscores), making it unsuitable to be machine
     /// interpreted.
     ///
-    /// In some cases, when the value is to complex, this may be `"{ _ }"`.
+    /// In some cases, when the value is too complex, this may be `"{ _ }"`.
     /// When this occurs is unstable, and may change without notice.
     pub expr: String,
     /// The numerical value of the discriminant. Stored as a string due to
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index af74e4b67c1..28755ae0710 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -2931,6 +2931,7 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> ExprU
             moved_before_use,
             same_ctxt,
         },
+        #[allow(unreachable_patterns)]
         Some(ControlFlow::Break(_)) => unreachable!("type of node is ControlFlow<!>"),
         None => ExprUseCtxt {
             node: Node::Crate(cx.tcx.hir().root_module()),
diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs
index c9af2138a72..c9853e53f3b 100644
--- a/src/tools/clippy/src/main.rs
+++ b/src/tools/clippy/src/main.rs
@@ -1,3 +1,6 @@
+// We need this feature as it changes `dylib` linking behavior and allows us to link to
+// `rustc_driver`.
+#![feature(rustc_private)]
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index c7080e5dcdc..64253514fbe 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -1,3 +1,6 @@
+// We need this feature as it changes `dylib` linking behavior and allows us to link to
+// `rustc_driver`.
+#![feature(rustc_private)]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(unused_extern_crates)]
 
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
index 0ea93dd8462..452d1b19813 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
@@ -10,7 +10,7 @@ use std::sync::Once;
 
 const ATOMIC: AtomicUsize = AtomicUsize::new(5);
 const CELL: Cell<usize> = Cell::new(6);
-const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
+const ATOMIC_TUPLE: ([AtomicUsize; 1], Option<Box<AtomicUsize>>, u8) = ([ATOMIC], None, 7);
 const INTEGER: u8 = 8;
 const STRING: String = String::new();
 const STR: &str = "012345";
@@ -74,7 +74,6 @@ fn main() {
     let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR: interior mutability
     let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR: interior mutability
     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR: interior mutability
-    let _ = &*ATOMIC_TUPLE.1;
     let _ = &ATOMIC_TUPLE.2;
     let _ = (&&&&ATOMIC_TUPLE).0;
     let _ = (&&&&ATOMIC_TUPLE).2;
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
index 33c774667f9..9a9028c8649 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
@@ -92,7 +92,7 @@ LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst);
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:82:13
+  --> tests/ui/borrow_interior_mutable_const/others.rs:81:13
    |
 LL |     let _ = ATOMIC_TUPLE.0[0];
    |             ^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL |     let _ = ATOMIC_TUPLE.0[0];
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:87:5
+  --> tests/ui/borrow_interior_mutable_const/others.rs:86:5
    |
 LL |     CELL.set(2);
    |     ^^^^
@@ -108,7 +108,7 @@ LL |     CELL.set(2);
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:88:16
+  --> tests/ui/borrow_interior_mutable_const/others.rs:87:16
    |
 LL |     assert_eq!(CELL.get(), 6);
    |                ^^^^
diff --git a/src/tools/clippy/tests/ui/single_match_else.fixed b/src/tools/clippy/tests/ui/single_match_else.fixed
index e840adf0fa3..163be16ad8b 100644
--- a/src/tools/clippy/tests/ui/single_match_else.fixed
+++ b/src/tools/clippy/tests/ui/single_match_else.fixed
@@ -89,7 +89,7 @@ fn main() {
 
     // lint here
     use std::convert::Infallible;
-    if let Ok(a) = Result::<i32, Infallible>::Ok(1) { println!("${:?}", a) } else {
+    if let Ok(a) = Result::<i32, &Infallible>::Ok(1) { println!("${:?}", a) } else {
         println!("else block");
         return;
     }
diff --git a/src/tools/clippy/tests/ui/single_match_else.rs b/src/tools/clippy/tests/ui/single_match_else.rs
index 430c4da20f1..3f1fd2b3183 100644
--- a/src/tools/clippy/tests/ui/single_match_else.rs
+++ b/src/tools/clippy/tests/ui/single_match_else.rs
@@ -98,7 +98,7 @@ fn main() {
 
     // lint here
     use std::convert::Infallible;
-    match Result::<i32, Infallible>::Ok(1) {
+    match Result::<i32, &Infallible>::Ok(1) {
         Ok(a) => println!("${:?}", a),
         Err(_) => {
             println!("else block");
diff --git a/src/tools/clippy/tests/ui/single_match_else.stderr b/src/tools/clippy/tests/ui/single_match_else.stderr
index f8f88379d6d..61c348260d0 100644
--- a/src/tools/clippy/tests/ui/single_match_else.stderr
+++ b/src/tools/clippy/tests/ui/single_match_else.stderr
@@ -64,7 +64,7 @@ LL +     }
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
   --> tests/ui/single_match_else.rs:101:5
    |
-LL | /     match Result::<i32, Infallible>::Ok(1) {
+LL | /     match Result::<i32, &Infallible>::Ok(1) {
 LL | |         Ok(a) => println!("${:?}", a),
 LL | |         Err(_) => {
 LL | |             println!("else block");
@@ -75,7 +75,7 @@ LL | |     }
    |
 help: try
    |
-LL ~     if let Ok(a) = Result::<i32, Infallible>::Ok(1) { println!("${:?}", a) } else {
+LL ~     if let Ok(a) = Result::<i32, &Infallible>::Ok(1) { println!("${:?}", a) } else {
 LL +         println!("else block");
 LL +         return;
 LL +     }
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index b1b6d6fc8eb..ce6569f5537 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -3027,11 +3027,17 @@ impl<'test> TestCx<'test> {
         const PREFIX: &str = "MONO_ITEM ";
         const CGU_MARKER: &str = "@@";
 
+        // Some MonoItems can contain {closure@/path/to/checkout/tests/codgen-units/test.rs}
+        // To prevent the current dir from leaking, we just replace the entire path to the test
+        // file with TEST_PATH.
         let actual: Vec<MonoItem> = proc_res
             .stdout
             .lines()
             .filter(|line| line.starts_with(PREFIX))
-            .map(|line| str_to_mono_item(line, true))
+            .map(|line| {
+                line.replace(&self.testpaths.file.display().to_string(), "TEST_PATH").to_string()
+            })
+            .map(|line| str_to_mono_item(&line, true))
             .collect();
 
         let expected: Vec<MonoItem> = errors::load_errors(&self.testpaths.file, None)
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 499d0fe2f1c..a0bff386a71 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -212,7 +212,6 @@ degree documented below):
 - All Rust [Tier 1 targets](https://doc.rust-lang.org/rustc/platform-support.html) are supported by
   Miri. They are all checked on Miri's CI, and some (at least one per OS) are even checked on every
   Rust PR, so the shipped Miri should always work on these targets.
-- `aarch64-apple-darwin` is supported.
 - `s390x-unknown-linux-gnu` is supported as our "big-endian target of choice".
 - For every other target with OS `linux`, `macos`, or `windows`, Miri should generally work, but we
   make no promises and we don't run tests for such targets.
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index 5e75638f467..3e90ecc5c03 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -137,7 +137,7 @@ case $HOST_TARGET in
     MANY_SEEDS=16 TEST_TARGET=x86_64-pc-windows-gnu run_tests
     ;;
   aarch64-apple-darwin)
-    # Host (tier 2)
+    # Host
     GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests
     # Extra tier 1
     MANY_SEEDS=64 TEST_TARGET=i686-pc-windows-gnu run_tests
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 1173da46975..d781188cd0c 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -463,6 +463,7 @@ pub fn eval_entry<'tcx>(
     let res = match res {
         Err(res) => res,
         // `Ok` can never happen
+        #[cfg(bootstrap)]
         Ok(never) => match never {},
     };
 
diff --git a/src/tools/miri/tests/pass/async-fn.rs b/src/tools/miri/tests/pass/async-fn.rs
index 13400c88c71..67ec2e26b30 100644
--- a/src/tools/miri/tests/pass/async-fn.rs
+++ b/src/tools/miri/tests/pass/async-fn.rs
@@ -59,6 +59,7 @@ async fn hello_world() {
 }
 
 // This example comes from https://github.com/rust-lang/rust/issues/115145
+#[allow(unreachable_patterns)]
 async fn uninhabited_variant() {
     async fn unreachable(_: Never) {}
 
diff --git a/src/tools/miri/tests/pass/enums.rs b/src/tools/miri/tests/pass/enums.rs
index ac7aafc1bb2..1dafef025e9 100644
--- a/src/tools/miri/tests/pass/enums.rs
+++ b/src/tools/miri/tests/pass/enums.rs
@@ -43,6 +43,7 @@ fn discriminant_overflow() {
     }
 }
 
+#[allow(unreachable_patterns)]
 fn more_discriminant_overflow() {
     pub enum Infallible {}
 
diff --git a/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs b/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs
index 05090d685ab..9debe224d45 100644
--- a/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs
+++ b/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs
@@ -1,3 +1,5 @@
+// FIXME: This test is broken since https://github.com/rust-lang/rust/pull/126793,
+// possibly related to the additional struct between Vec and Unique.
 //@revisions: default uniq
 // We disable the GC for this test because it would change what is printed.
 //@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0
diff --git a/src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr b/src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr
index 7942e9884f4..e3796a742e9 100644
--- a/src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr
+++ b/src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr
@@ -2,7 +2,9 @@
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..   2
 | Act |    └─┬──<TAG=root of the allocation>
-|-----|      └─┬──<TAG=base.as_ptr(), base.as_ptr()>
-|-----|        └─┬──<TAG=raw_parts.0>
-|-----|          └────<TAG=reconstructed.as_ptr(), reconstructed.as_ptr()>
+|-----|      ├────<TAG=base.as_ptr()>
+|-----|      ├────<TAG=base.as_ptr()>
+|-----|      └─┬──<TAG=raw_parts.0>
+|-----|        ├────<TAG=reconstructed.as_ptr()>
+|-----|        └────<TAG=reconstructed.as_ptr()>
 ──────────────────────────────────────────────────
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index bd43a62341d..d76f5381871 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -27,6 +27,7 @@ macro_rules! from_bytes {
     ($ty:tt, $value:expr) => {
         ($ty::from_le_bytes(match ($value).try_into() {
             Ok(it) => it,
+            #[allow(unreachable_patterns)]
             Err(_) => return Err(MirEvalError::InternalError("mismatched size".into())),
         }))
     };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 057f5533805..9aa2eeebc17 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -1161,6 +1161,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                                     ProjectionElem::OpaqueCast(it) => {
                                         ProjectionElem::OpaqueCast(it)
                                     }
+                                    #[allow(unreachable_patterns)]
                                     ProjectionElem::Index(it) => match it {},
                                 })
                                 .collect(),
diff --git a/src/tools/rustdoc/main.rs b/src/tools/rustdoc/main.rs
index 5b499a1fa1f..d4099cafe5d 100644
--- a/src/tools/rustdoc/main.rs
+++ b/src/tools/rustdoc/main.rs
@@ -1,3 +1,6 @@
+// We need this feature as it changes `dylib` linking behavior and allows us to link to `rustc_driver`.
+#![feature(rustc_private)]
+
 fn main() {
     rustdoc::main()
 }
diff --git a/src/tools/rustfmt/src/git-rustfmt/main.rs b/src/tools/rustfmt/src/git-rustfmt/main.rs
index 3059d917c6b..5674f40bef9 100644
--- a/src/tools/rustfmt/src/git-rustfmt/main.rs
+++ b/src/tools/rustfmt/src/git-rustfmt/main.rs
@@ -1,3 +1,7 @@
+// We need this feature as it changes `dylib` linking behavior and allows us to link to
+// `rustc_driver`.
+#![feature(rustc_private)]
+
 #[macro_use]
 extern crate tracing;
 
diff --git a/tests/codegen-units/item-collection/auxiliary/cgu_extern_closures.rs b/tests/codegen-units/item-collection/auxiliary/cgu_extern_closures.rs
index 0192a3d4188..33a32d7fea9 100644
--- a/tests/codegen-units/item-collection/auxiliary/cgu_extern_closures.rs
+++ b/tests/codegen-units/item-collection/auxiliary/cgu_extern_closures.rs
@@ -1,3 +1,5 @@
+//@ compile-flags: -Zinline-mir=no
+
 #![crate_type = "lib"]
 
 #[inline]
diff --git a/tests/codegen-units/item-collection/cross-crate-closures.rs b/tests/codegen-units/item-collection/cross-crate-closures.rs
index 2dab19401ed..cb86cf18c0c 100644
--- a/tests/codegen-units/item-collection/cross-crate-closures.rs
+++ b/tests/codegen-units/item-collection/cross-crate-closures.rs
@@ -1,9 +1,6 @@
-// In the current version of the collector that still has to support
-// legacy-codegen, closures do not generate their own MonoItems, so we are
-// ignoring this test until MIR codegen has taken over completely
-//@ ignore-test
-
-//@ compile-flags:-Zprint-mono-items=eager
+// We need to disable MIR inlining in both this and its aux-build crate. The MIR inliner
+// will just inline everything into our start function if we let it. As it should.
+//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
 #![feature(start)]
@@ -11,15 +8,15 @@
 //@ aux-build:cgu_extern_closures.rs
 extern crate cgu_extern_closures;
 
-//~ MONO_ITEM fn cross_crate_closures::start[0]
+//~ MONO_ITEM fn start @@ cross_crate_closures-cgu.0[Internal]
 #[start]
 fn start(_: isize, _: *const *const u8) -> isize {
-    //~ MONO_ITEM fn cgu_extern_closures::inlined_fn[0]
-    //~ MONO_ITEM fn cgu_extern_closures::inlined_fn[0]::{{closure}}[0]
+    //~ MONO_ITEM fn cgu_extern_closures::inlined_fn @@ cross_crate_closures-cgu.0[Internal]
+    //~ MONO_ITEM fn cgu_extern_closures::inlined_fn::{closure#0} @@ cross_crate_closures-cgu.0[Internal]
     let _ = cgu_extern_closures::inlined_fn(1, 2);
 
-    //~ MONO_ITEM fn cgu_extern_closures::inlined_fn_generic[0]<i32>
-    //~ MONO_ITEM fn cgu_extern_closures::inlined_fn_generic[0]::{{closure}}[0]<i32>
+    //~ MONO_ITEM fn cgu_extern_closures::inlined_fn_generic::<i32> @@ cross_crate_closures-cgu.0[Internal]
+    //~ MONO_ITEM fn cgu_extern_closures::inlined_fn_generic::<i32>::{closure#0} @@ cross_crate_closures-cgu.0[Internal]
     let _ = cgu_extern_closures::inlined_fn_generic(3, 4, 5i32);
 
     // Nothing should be generated for this call, we just link to the instance
@@ -28,5 +25,3 @@ fn start(_: isize, _: *const *const u8) -> isize {
 
     0
 }
-
-//~ MONO_ITEM drop-glue i8
diff --git a/tests/codegen-units/item-collection/non-generic-closures.rs b/tests/codegen-units/item-collection/non-generic-closures.rs
index 105348e9d09..dc0846f2cd3 100644
--- a/tests/codegen-units/item-collection/non-generic-closures.rs
+++ b/tests/codegen-units/item-collection/non-generic-closures.rs
@@ -1,49 +1,45 @@
-// In the current version of the collector that still has to support
-// legacy-codegen, closures do not generate their own MonoItems, so we are
-// ignoring this test until MIR codegen has taken over completely
-//@ ignore-test
-
-//
-//@ compile-flags:-Zprint-mono-items=eager
+//@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no
 
 #![deny(dead_code)]
 #![feature(start)]
 
-//~ MONO_ITEM fn non_generic_closures::temporary[0]
+//~ MONO_ITEM fn temporary @@ non_generic_closures-cgu.0[Internal]
 fn temporary() {
-    //~ MONO_ITEM fn non_generic_closures::temporary[0]::{{closure}}[0]
+    //~ MONO_ITEM fn temporary::{closure#0} @@ non_generic_closures-cgu.0[Internal]
     (|a: u32| {
         let _ = a;
     })(4);
 }
 
-//~ MONO_ITEM fn non_generic_closures::assigned_to_variable_but_not_executed[0]
+//~ MONO_ITEM fn assigned_to_variable_but_not_executed @@ non_generic_closures-cgu.0[Internal]
 fn assigned_to_variable_but_not_executed() {
-    //~ MONO_ITEM fn non_generic_closures::assigned_to_variable_but_not_executed[0]::{{closure}}[0]
     let _x = |a: i16| {
         let _ = a + 1;
     };
 }
 
-//~ MONO_ITEM fn non_generic_closures::assigned_to_variable_executed_directly[0]
+//~ MONO_ITEM fn assigned_to_variable_executed_indirectly @@ non_generic_closures-cgu.0[Internal]
 fn assigned_to_variable_executed_indirectly() {
-    //~ MONO_ITEM fn non_generic_closures::assigned_to_variable_executed_directly[0]::{{closure}}[0]
+    //~ MONO_ITEM fn assigned_to_variable_executed_indirectly::{closure#0} @@ non_generic_closures-cgu.0[Internal]
+    //~ MONO_ITEM fn <{closure@TEST_PATH:27:13: 27:21} as std::ops::FnOnce<(i32,)>>::call_once - shim @@ non_generic_closures-cgu.0[Internal]
+    //~ MONO_ITEM fn <{closure@TEST_PATH:27:13: 27:21} as std::ops::FnOnce<(i32,)>>::call_once - shim(vtable) @@ non_generic_closures-cgu.0[Internal]
+    //~ MONO_ITEM fn std::ptr::drop_in_place::<{closure@TEST_PATH:27:13: 27:21}> - shim(None) @@ non_generic_closures-cgu.0[Internal]
     let f = |a: i32| {
         let _ = a + 2;
     };
     run_closure(&f);
 }
 
-//~ MONO_ITEM fn non_generic_closures::assigned_to_variable_executed_indirectly[0]
+//~ MONO_ITEM fn assigned_to_variable_executed_directly @@ non_generic_closures-cgu.0[Internal]
 fn assigned_to_variable_executed_directly() {
-    //~ MONO_ITEM fn non_generic_closures::assigned_to_variable_executed_indirectly[0]::{{closure}}[0]
+    //~ MONO_ITEM fn assigned_to_variable_executed_directly::{closure#0} @@ non_generic_closures-cgu.0[Internal]
     let f = |a: i64| {
         let _ = a + 3;
     };
     f(4);
 }
 
-//~ MONO_ITEM fn non_generic_closures::start[0]
+//~ MONO_ITEM fn start @@ non_generic_closures-cgu.0[Internal]
 #[start]
 fn start(_: isize, _: *const *const u8) -> isize {
     temporary();
@@ -54,7 +50,7 @@ fn start(_: isize, _: *const *const u8) -> isize {
     0
 }
 
-//~ MONO_ITEM fn non_generic_closures::run_closure[0]
+//~ MONO_ITEM fn run_closure @@ non_generic_closures-cgu.0[Internal]
 fn run_closure(f: &Fn(i32)) {
     f(3);
 }
diff --git a/tests/codegen-units/partitioning/methods-are-with-self-type.rs b/tests/codegen-units/partitioning/methods-are-with-self-type.rs
index 901e7507d73..7c9045e8f1a 100644
--- a/tests/codegen-units/partitioning/methods-are-with-self-type.rs
+++ b/tests/codegen-units/partitioning/methods-are-with-self-type.rs
@@ -1,30 +1,23 @@
-// Currently, all generic functions are instantiated in each codegen unit that
-// uses them, even those not marked with #[inline], so this test does not make
-// much sense at the moment.
-//@ ignore-test
-
 // We specify incremental here because we want to test the partitioning for incremental compilation
 //@ incremental
 //@ compile-flags:-Zprint-mono-items=lazy
 
-#![allow(dead_code)]
-#![feature(start)]
+#![crate_type = "lib"]
 
-struct SomeType;
+pub struct SomeType;
 
 struct SomeGenericType<T1, T2>(T1, T2);
 
-mod mod1 {
+pub mod mod1 {
     use super::{SomeGenericType, SomeType};
 
     // Even though the impl is in `mod1`, the methods should end up in the
     // parent module, since that is where their self-type is.
     impl SomeType {
-        //~ MONO_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[0]::method[0] @@ methods_are_with_self_type[External]
-        fn method(&self) {}
-
-        //~ MONO_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[0]::associated_fn[0] @@ methods_are_with_self_type[External]
-        fn associated_fn() {}
+        //~ MONO_ITEM fn mod1::<impl SomeType>::method @@ methods_are_with_self_type[External]
+        pub fn method(&self) {}
+        //~ MONO_ITEM fn mod1::<impl SomeType>::associated_fn @@ methods_are_with_self_type[External]
+        pub fn associated_fn() {}
     }
 
     impl<T1, T2> SomeGenericType<T1, T2> {
@@ -52,25 +45,20 @@ mod type2 {
     pub struct Struct;
 }
 
-//~ MONO_ITEM fn methods_are_with_self_type::start[0]
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    //~ MONO_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[1]::method[0]<u32, u64> @@ methods_are_with_self_type.volatile[WeakODR]
+//~ MONO_ITEM fn start @@ methods_are_with_self_type[External]
+pub fn start() {
+    //~ MONO_ITEM fn mod1::<impl SomeGenericType<u32, u64>>::method @@ methods_are_with_self_type.volatile[External]
     SomeGenericType(0u32, 0u64).method();
-    //~ MONO_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[1]::associated_fn[0]<char, &str> @@ methods_are_with_self_type.volatile[WeakODR]
+    //~ MONO_ITEM fn mod1::<impl SomeGenericType<char, &str>>::associated_fn @@ methods_are_with_self_type.volatile[External]
     SomeGenericType::associated_fn('c', "&str");
 
-    //~ MONO_ITEM fn methods_are_with_self_type::{{impl}}[0]::foo[0]<methods_are_with_self_type::type1[0]::Struct[0]> @@ methods_are_with_self_type-type1.volatile[WeakODR]
+    //~ MONO_ITEM fn <type1::Struct as Trait>::foo @@ methods_are_with_self_type-type1.volatile[External]
     type1::Struct.foo();
-    //~ MONO_ITEM fn methods_are_with_self_type::{{impl}}[0]::foo[0]<methods_are_with_self_type::type2[0]::Struct[0]> @@ methods_are_with_self_type-type2.volatile[WeakODR]
+    //~ MONO_ITEM fn <type2::Struct as Trait>::foo @@ methods_are_with_self_type-type2.volatile[External]
     type2::Struct.foo();
 
-    //~ MONO_ITEM fn methods_are_with_self_type::Trait[0]::default[0]<methods_are_with_self_type::type1[0]::Struct[0]> @@ methods_are_with_self_type-type1.volatile[WeakODR]
+    //~ MONO_ITEM fn <type1::Struct as Trait>::default @@ methods_are_with_self_type-type1.volatile[External]
     type1::Struct.default();
-    //~ MONO_ITEM fn methods_are_with_self_type::Trait[0]::default[0]<methods_are_with_self_type::type2[0]::Struct[0]> @@ methods_are_with_self_type-type2.volatile[WeakODR]
+    //~ MONO_ITEM fn <type2::Struct as Trait>::default @@ methods_are_with_self_type-type2.volatile[External]
     type2::Struct.default();
-
-    0
 }
-
-//~ MONO_ITEM drop-glue i8
diff --git a/tests/codegen/array-from_fn.rs b/tests/codegen/array-from_fn.rs
new file mode 100644
index 00000000000..7202d0c67e6
--- /dev/null
+++ b/tests/codegen/array-from_fn.rs
@@ -0,0 +1,13 @@
+//@ revisions: NORMAL OPT
+//@ [NORMAL] compile-flags: -C opt-level=0 -C debuginfo=2
+//@ [OPT] compile-flags: -C opt-level=s -C debuginfo=0
+
+#![crate_type = "lib"]
+#![feature(array_from_fn)]
+
+#[no_mangle]
+pub fn iota() -> [u8; 16] {
+    // OPT-NOT: core..array..Guard
+    // NORMAL: core..array..Guard
+    std::array::from_fn(|i| i as _)
+}
diff --git a/tests/codegen/call-metadata.rs b/tests/codegen/call-metadata.rs
index b2168990ff8..73c4b33e2cf 100644
--- a/tests/codegen/call-metadata.rs
+++ b/tests/codegen/call-metadata.rs
@@ -2,6 +2,7 @@
 // scalar value.
 
 //@ compile-flags: -O -C no-prepopulate-passes
+//@ ignore-llvm-version: 19 - 99
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/cast-optimized.rs b/tests/codegen/cast-optimized.rs
index 313b2b4f0d6..59cf40935cd 100644
--- a/tests/codegen/cast-optimized.rs
+++ b/tests/codegen/cast-optimized.rs
@@ -20,8 +20,6 @@ pub fn u32_index(c: u32) -> [bool; 22] {
 // CHECK-LABEL: @char_as_u32_index
 #[no_mangle]
 pub fn char_as_u32_index(c: char) -> [bool; 22] {
-    // CHECK: %[[B:.+]] = icmp ult i32 %c, 1114112
-    // CHECK: call void @llvm.assume(i1 %[[B]])
     let c = c as u32;
 
     let mut array = [false; 22];
diff --git a/tests/codegen/common_prim_int_ptr.rs b/tests/codegen/common_prim_int_ptr.rs
index 87fa89abb86..aa7ebb4c911 100644
--- a/tests/codegen/common_prim_int_ptr.rs
+++ b/tests/codegen/common_prim_int_ptr.rs
@@ -28,7 +28,7 @@ pub fn insert_box(x: Box<()>) -> Result<usize, Box<()>> {
 
 // CHECK-LABEL: @extract_int
 // CHECK-NOT: nonnull
-// CHECK-SAME: (i{{[0-9]+}} {{[^,]+}} [[DISCRIMINANT:%[0-9]+]], ptr {{[^,]+}} [[PAYLOAD:%[0-9]+]])
+// CHECK-SAME: (i{{[0-9]+}} {{[^%]+}} [[DISCRIMINANT:%[0-9]+]], ptr {{[^,]+}} [[PAYLOAD:%[0-9]+]])
 #[no_mangle]
 pub unsafe fn extract_int(x: Result<usize, Box<()>>) -> usize {
     // CHECK: [[TEMP:%.+]] = ptrtoint ptr [[PAYLOAD]] to [[USIZE:i[0-9]+]]
@@ -40,7 +40,7 @@ pub unsafe fn extract_int(x: Result<usize, Box<()>>) -> usize {
 }
 
 // CHECK-LABEL: @extract_box
-// CHECK-SAME: (i{{[0-9]+}} {{[^,]+}} [[DISCRIMINANT:%[0-9]+]], ptr {{[^,]+}} [[PAYLOAD:%[0-9]+]])
+// CHECK-SAME: (i{{[0-9]+}} {{[^%]+}} [[DISCRIMINANT:%[0-9]+]], ptr {{[^,]+}} [[PAYLOAD:%[0-9]+]])
 #[no_mangle]
 pub unsafe fn extract_box(x: Result<usize, Box<i32>>) -> Box<i32> {
     // CHECK: ret ptr [[PAYLOAD]]
diff --git a/tests/codegen/const-vector.rs b/tests/codegen/const-vector.rs
new file mode 100644
index 00000000000..d368838201e
--- /dev/null
+++ b/tests/codegen/const-vector.rs
@@ -0,0 +1,107 @@
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+
+// This test checks that constants of SIMD type are passed as immediate vectors.
+// We ensure that both vector representations (struct with fields and struct wrapping array) work.
+#![crate_type = "lib"]
+#![feature(abi_unadjusted)]
+#![feature(const_trait_impl)]
+#![feature(repr_simd)]
+#![feature(rustc_attrs)]
+#![feature(simd_ffi)]
+#![allow(non_camel_case_types)]
+
+// Setting up structs that can be used as const vectors
+#[repr(simd)]
+#[derive(Clone)]
+pub struct i8x2(i8, i8);
+
+#[repr(simd)]
+#[derive(Clone)]
+pub struct i8x2_arr([i8; 2]);
+
+#[repr(simd)]
+#[derive(Clone)]
+pub struct f32x2(f32, f32);
+
+#[repr(simd)]
+#[derive(Clone)]
+pub struct f32x2_arr([f32; 2]);
+
+#[repr(simd, packed)]
+#[derive(Copy, Clone)]
+pub struct Simd<T, const N: usize>([T; N]);
+
+// The following functions are required for the tests to ensure
+// that they are called with a const vector
+
+extern "unadjusted" {
+    #[no_mangle]
+    fn test_i8x2(a: i8x2);
+}
+
+extern "unadjusted" {
+    #[no_mangle]
+    fn test_i8x2_two_args(a: i8x2, b: i8x2);
+}
+
+extern "unadjusted" {
+    #[no_mangle]
+    fn test_i8x2_mixed_args(a: i8x2, c: i32, b: i8x2);
+}
+
+extern "unadjusted" {
+    #[no_mangle]
+    fn test_i8x2_arr(a: i8x2_arr);
+}
+
+extern "unadjusted" {
+    #[no_mangle]
+    fn test_f32x2(a: f32x2);
+}
+
+extern "unadjusted" {
+    #[no_mangle]
+    fn test_f32x2_arr(a: f32x2_arr);
+}
+
+extern "unadjusted" {
+    #[no_mangle]
+    fn test_simd(a: Simd<i32, 4>);
+}
+
+extern "unadjusted" {
+    #[no_mangle]
+    fn test_simd_unaligned(a: Simd<i32, 3>);
+}
+
+// Ensure the packed variant of the simd struct does not become a const vector
+// if the size is not a power of 2
+// CHECK: %"Simd<i32, 3>" = type { [3 x i32] }
+
+pub fn do_call() {
+    unsafe {
+        // CHECK: call void @test_i8x2(<2 x i8> <i8 32, i8 64>
+        test_i8x2(const { i8x2(32, 64) });
+
+        // CHECK: call void @test_i8x2_two_args(<2 x i8> <i8 32, i8 64>, <2 x i8> <i8 8, i8 16>
+        test_i8x2_two_args(const { i8x2(32, 64) }, const { i8x2(8, 16) });
+
+        // CHECK: call void @test_i8x2_mixed_args(<2 x i8> <i8 32, i8 64>, i32 43, <2 x i8> <i8 8, i8 16>
+        test_i8x2_mixed_args(const { i8x2(32, 64) }, 43, const { i8x2(8, 16) });
+
+        // CHECK: call void @test_i8x2_arr(<2 x i8> <i8 32, i8 64>
+        test_i8x2_arr(const { i8x2_arr([32, 64]) });
+
+        // CHECK: call void @test_f32x2(<2 x float> <float 0x3FD47AE140000000, float 0x3FE47AE140000000>
+        test_f32x2(const { f32x2(0.32, 0.64) });
+
+        // CHECK: void @test_f32x2_arr(<2 x float> <float 0x3FD47AE140000000, float 0x3FE47AE140000000>
+        test_f32x2_arr(const { f32x2_arr([0.32, 0.64]) });
+
+        // CHECK: call void @test_simd(<4 x i32> <i32 2, i32 4, i32 6, i32 8>
+        test_simd(const { Simd::<i32, 4>([2, 4, 6, 8]) });
+
+        // CHECK: call void @test_simd_unaligned(%"Simd<i32, 3>" %1
+        test_simd_unaligned(const { Simd::<i32, 3>([2, 4, 6]) });
+    }
+}
diff --git a/tests/codegen/enum/enum-match.rs b/tests/codegen/enum/enum-match.rs
index 8da5de63e67..a24b98050d2 100644
--- a/tests/codegen/enum/enum-match.rs
+++ b/tests/codegen/enum/enum-match.rs
@@ -34,7 +34,7 @@ pub enum Enum1 {
 
 // CHECK: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match1{{.*}}
 // CHECK-NEXT: start:
-// CHECK-NEXT: %1 = add i8 %0, -2
+// CHECK-NEXT: %1 = add{{( nsw)?}} i8 %0, -2
 // CHECK-NEXT: %2 = zext i8 %1 to i64
 // CHECK-NEXT: %3 = icmp ult i8 %1, 2
 // CHECK-NEXT: %4 = add nuw nsw i64 %2, 1
diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs
index 56504df4034..bf9f405192b 100644
--- a/tests/codegen/function-arguments.rs
+++ b/tests/codegen/function-arguments.rs
@@ -50,7 +50,7 @@ pub fn maybeuninit_enum_bool(x: MaybeUninit<MyBool>) -> MaybeUninit<MyBool> {
     x
 }
 
-// CHECK: noundef i32 @char(i32 noundef %x)
+// CHECK: noundef{{( range\(i32 0, 1114112\))?}} i32 @char(i32 noundef{{( range\(i32 0, 1114112\))?}} %x)
 #[no_mangle]
 pub fn char(x: char) -> char {
     x
@@ -68,7 +68,7 @@ pub fn int(x: u64) -> u64 {
     x
 }
 
-// CHECK: noundef i64 @nonzero_int(i64 noundef %x)
+// CHECK: noundef{{( range\(i64 1, 0\))?}} i64 @nonzero_int(i64 noundef{{( range\(i64 1, 0\))?}} %x)
 #[no_mangle]
 pub fn nonzero_int(x: NonZero<u64>) -> NonZero<u64> {
     x
@@ -250,7 +250,7 @@ pub fn return_slice(x: &[u16]) -> &[u16] {
     x
 }
 
-// CHECK: { i16, i16 } @enum_id_1(i16 noundef %x.0, i16 %x.1)
+// CHECK: { i16, i16 } @enum_id_1(i16 noundef{{( range\(i16 0, 3\))?}} %x.0, i16 %x.1)
 #[no_mangle]
 pub fn enum_id_1(x: Option<Result<u16, u16>>) -> Option<Result<u16, u16>> {
     x
diff --git a/tests/codegen/intrinsics/nontemporal.rs b/tests/codegen/intrinsics/nontemporal.rs
index 076d6d6d9da..ff2d6296066 100644
--- a/tests/codegen/intrinsics/nontemporal.rs
+++ b/tests/codegen/intrinsics/nontemporal.rs
@@ -1,13 +1,37 @@
 //@ compile-flags: -O
+//@revisions: with_nontemporal without_nontemporal
+//@[with_nontemporal] compile-flags: --target aarch64-unknown-linux-gnu
+//@[with_nontemporal] needs-llvm-components: aarch64
+//@[without_nontemporal] compile-flags: --target x86_64-unknown-linux-gnu
+//@[without_nontemporal] needs-llvm-components: x86
 
-#![feature(core_intrinsics)]
+// Ensure that we *do* emit the `!nontemporal` flag on architectures where it
+// is well-behaved, but do *not* emit it on architectures where it is ill-behaved.
+// For more context, see <https://github.com/rust-lang/rust/issues/114582> and
+// <https://github.com/llvm/llvm-project/issues/64521>.
+
+#![feature(no_core, lang_items, intrinsics)]
+#![no_core]
 #![crate_type = "lib"]
 
+#[lang = "sized"]
+pub trait Sized {}
+#[lang = "copy"]
+pub trait Copy {}
+
+impl Copy for u32 {}
+impl<T> Copy for *mut T {}
+
+extern "rust-intrinsic" {
+    pub fn nontemporal_store<T>(ptr: *mut T, val: T);
+}
+
 #[no_mangle]
 pub fn a(a: &mut u32, b: u32) {
     // CHECK-LABEL: define{{.*}}void @a
-    // CHECK: store i32 %b, ptr %a, align 4, !nontemporal
+    // with_nontemporal: store i32 %b, ptr %a, align 4, !nontemporal
+    // without_nontemporal-NOT: nontemporal
     unsafe {
-        std::intrinsics::nontemporal_store(a, b);
+        nontemporal_store(a, b);
     }
 }
diff --git a/tests/codegen/issues/issue-68667-unwrap-combinators.rs b/tests/codegen/issues/issue-68667-unwrap-combinators.rs
index 6bd4c566a0c..21a5a5bf4ee 100644
--- a/tests/codegen/issues/issue-68667-unwrap-combinators.rs
+++ b/tests/codegen/issues/issue-68667-unwrap-combinators.rs
@@ -5,7 +5,7 @@
 // MIR inlining now optimizes this code.
 
 // CHECK-LABEL: @unwrap_combinators
-// CHECK: icmp
+// CHECK: {{icmp|trunc}}
 // CHECK-NEXT: icmp
 // CHECK-NEXT: select i1
 // CHECK-NEXT: ret i1
diff --git a/tests/codegen/range-attribute.rs b/tests/codegen/range-attribute.rs
new file mode 100644
index 00000000000..bb19bec0fb9
--- /dev/null
+++ b/tests/codegen/range-attribute.rs
@@ -0,0 +1,68 @@
+// Checks that range metadata gets emitted on functions result and arguments
+// with scalar value.
+
+//@ compile-flags: -O -C no-prepopulate-passes
+//@ min-llvm-version: 19
+
+#![crate_type = "lib"]
+
+use std::num::NonZero;
+
+// Hack to get the correct size for usize
+// CHECK: @helper([[USIZE:i[0-9]+]] noundef %_1)
+#[no_mangle]
+pub fn helper(_: usize) {}
+
+// CHECK: noundef range(i128 1, 0) i128 @nonzero_int(i128 noundef range(i128 1, 0) %x)
+#[no_mangle]
+pub fn nonzero_int(x: NonZero<u128>) -> NonZero<u128> {
+    x
+}
+
+// CHECK: noundef range(i8 0, 3) i8 @optional_bool(i8 noundef range(i8 0, 3) %x)
+#[no_mangle]
+pub fn optional_bool(x: Option<bool>) -> Option<bool> {
+    x
+}
+
+pub enum Enum0 {
+    A(bool),
+    B,
+    C,
+}
+
+// CHECK: noundef range(i8 0, 4) i8 @enum0_value(i8 noundef range(i8 0, 4) %x)
+#[no_mangle]
+pub fn enum0_value(x: Enum0) -> Enum0 {
+    x
+}
+
+pub enum Enum1 {
+    A(u64),
+    B(u64),
+    C(u64),
+}
+
+// CHECK: { [[ENUM1_TYP:i[0-9]+]], i64 } @enum1_value([[ENUM1_TYP]] noundef range([[ENUM1_TYP]] 0, 3) %x.0, i64 noundef %x.1)
+#[no_mangle]
+pub fn enum1_value(x: Enum1) -> Enum1 {
+    x
+}
+
+pub enum Enum2 {
+    A(Enum0),
+    B(Enum0),
+    C(Enum0),
+}
+
+// CHECK: { i8, i8 } @enum2_value(i8 noundef range(i8 0, 3) %x.0, i8 noundef %x.1)
+#[no_mangle]
+pub fn enum2_value(x: Enum2) -> Enum2 {
+    x
+}
+
+// CHECK: noundef [[USIZE]] @takes_slice(ptr noalias noundef nonnull readonly align 4 %x.0, [[USIZE]] noundef %x.1)
+#[no_mangle]
+pub fn takes_slice(x: &[i32]) -> usize {
+    x.len()
+}
diff --git a/tests/codegen/repr/transparent.rs b/tests/codegen/repr/transparent.rs
index 4b41332db45..9140b8542ec 100644
--- a/tests/codegen/repr/transparent.rs
+++ b/tests/codegen/repr/transparent.rs
@@ -74,7 +74,7 @@ pub enum Bool {
     FileNotFound,
 }
 
-// CHECK: define{{( dso_local)?}} noundef{{( zeroext)?}} i8 @test_Gpz(i8 noundef{{( zeroext)?}} %_1)
+// CHECK: define{{( dso_local)?}} noundef{{( zeroext)?( range\(i8 0, 3\))?}} i8 @test_Gpz(i8 noundef{{( zeroext)?( range\(i8 0, 3\))?}} %_1)
 #[no_mangle]
 pub extern "C" fn test_Gpz(_: GenericPlusZst<Bool>) -> GenericPlusZst<Bool> {
     loop {}
diff --git a/tests/debuginfo/pretty-std.rs b/tests/debuginfo/pretty-std.rs
index 70827d551ca..45c6dbf3439 100644
--- a/tests/debuginfo/pretty-std.rs
+++ b/tests/debuginfo/pretty-std.rs
@@ -81,10 +81,10 @@
 // cdb-check:vec,d [...] : { len=4 } [Type: [...]::Vec<u64,alloc::alloc::Global>]
 // cdb-check:    [len]            : 4 [Type: [...]]
 // cdb-check:    [capacity]       : [...] [Type: [...]]
-// cdb-check:    [0]              : 4 [Type: unsigned __int64]
-// cdb-check:    [1]              : 5 [Type: unsigned __int64]
-// cdb-check:    [2]              : 6 [Type: unsigned __int64]
-// cdb-check:    [3]              : 7 [Type: unsigned __int64]
+// cdb-check:    [0]              : 4 [Type: u64]
+// cdb-check:    [1]              : 5 [Type: u64]
+// cdb-check:    [2]              : 6 [Type: u64]
+// cdb-check:    [3]              : 7 [Type: u64]
 
 // cdb-command: dx str_slice
 // cdb-check:str_slice        : "IAMA string slice!" [Type: ref$<str$>]
@@ -141,8 +141,8 @@
 // cdb-check:    [<Raw View>]     [Type: alloc::collections::vec_deque::VecDeque<i32,alloc::alloc::Global>]
 // cdb-check:    [len]            : 0x2 [Type: unsigned [...]]
 // cdb-check:    [capacity]       : 0x8 [Type: unsigned [...]]
-// cdb-check:    [0x0]            : 90 [Type: int]
-// cdb-check:    [0x1]            : 20 [Type: int]
+// cdb-check:    [0x0]            : 90 [Type: i32]
+// cdb-check:    [0x1]            : 20 [Type: i32]
 
 #![allow(unused_variables)]
 use std::collections::{LinkedList, VecDeque};
diff --git a/tests/debuginfo/strings-and-strs.rs b/tests/debuginfo/strings-and-strs.rs
index 4a6adc2fc53..2d29ac12bd8 100644
--- a/tests/debuginfo/strings-and-strs.rs
+++ b/tests/debuginfo/strings-and-strs.rs
@@ -7,7 +7,7 @@
 // gdb-command:run
 
 // gdb-command:print plain_string
-// gdbr-check:$1 = alloc::string::String {vec: alloc::vec::Vec<u8, alloc::alloc::Global> {buf: alloc::raw_vec::RawVec<u8, alloc::alloc::Global> {ptr: core::ptr::unique::Unique<u8> {pointer: core::ptr::non_null::NonNull<u8> {pointer: 0x[...]}, _marker: core::marker::PhantomData<u8>}, cap: alloc::raw_vec::Cap (5), alloc: alloc::alloc::Global}, len: 5}}
+// gdbr-check:$1 = alloc::string::String {vec: alloc::vec::Vec<u8, alloc::alloc::Global> {buf: alloc::raw_vec::RawVec<u8, alloc::alloc::Global> {inner: alloc::raw_vec::RawVecInner<alloc::alloc::Global> {ptr: core::ptr::unique::Unique<u8> {pointer: core::ptr::non_null::NonNull<u8> {pointer: 0x[...]}, _marker: core::marker::PhantomData<u8>}, cap: alloc::raw_vec::Cap (5), alloc: alloc::alloc::Global}, _marker: core::marker::PhantomData<u8>}, len: 5}}
 
 // gdb-command:print plain_str
 // gdbr-check:$2 = "Hello"
diff --git a/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir
index 78356a90743..bba4d9c0149 100644
--- a/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir
@@ -13,17 +13,17 @@ fn opt1(_1: &Result<u32, Void>) -> &u32 {
 
     bb0: {
         PlaceMention(_1);
-        _2 = discriminant((*_1));
-        switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1];
+        falseEdge -> [real: bb4, imaginary: bb1];
     }
 
     bb1: {
-        FakeRead(ForMatchedPlace(None), _1);
-        unreachable;
+        _2 = discriminant((*_1));
+        switchInt(move _2) -> [1: bb3, otherwise: bb2];
     }
 
     bb2: {
-        falseEdge -> [real: bb4, imaginary: bb3];
+        FakeRead(ForMatchedPlace(None), _1);
+        unreachable;
     }
 
     bb3: {
diff --git a/tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir
index 979fbb2860d..fc0769d6f7d 100644
--- a/tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir
@@ -11,25 +11,10 @@ fn opt2(_1: &Result<u32, Void>) -> &u32 {
 
     bb0: {
         PlaceMention(_1);
-        _2 = discriminant((*_1));
-        switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1];
-    }
-
-    bb1: {
-        FakeRead(ForMatchedPlace(None), _1);
-        unreachable;
-    }
-
-    bb2: {
         StorageLive(_3);
         _3 = &(((*_1) as Ok).0: u32);
         _0 = &(*_3);
         StorageDead(_3);
         return;
     }
-
-    bb3: {
-        FakeRead(ForMatchedPlace(None), (((*_1) as Err).0: Void));
-        unreachable;
-    }
 }
diff --git a/tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir
index 93ebe600b3f..86347db4d92 100644
--- a/tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir
@@ -12,24 +12,19 @@ fn opt3(_1: &Result<u32, Void>) -> &u32 {
     bb0: {
         PlaceMention(_1);
         _2 = discriminant((*_1));
-        switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
+        switchInt(move _2) -> [1: bb2, otherwise: bb1];
     }
 
     bb1: {
-        FakeRead(ForMatchedPlace(None), _1);
-        unreachable;
-    }
-
-    bb2: {
-        FakeRead(ForMatchedPlace(None), (((*_1) as Err).0: Void));
-        unreachable;
-    }
-
-    bb3: {
         StorageLive(_3);
         _3 = &(((*_1) as Ok).0: u32);
         _0 = &(*_3);
         StorageDead(_3);
         return;
     }
+
+    bb2: {
+        FakeRead(ForMatchedPlace(None), (((*_1) as Err).0: Void));
+        unreachable;
+    }
 }
diff --git a/tests/mir-opt/elaborate_box_deref_in_debuginfo.pointee.ElaborateBoxDerefs.diff b/tests/mir-opt/elaborate_box_deref_in_debuginfo.pointee.ElaborateBoxDerefs.diff
new file mode 100644
index 00000000000..279c1a1990d
--- /dev/null
+++ b/tests/mir-opt/elaborate_box_deref_in_debuginfo.pointee.ElaborateBoxDerefs.diff
@@ -0,0 +1,13 @@
+- // MIR for `pointee` before ElaborateBoxDerefs
++ // MIR for `pointee` after ElaborateBoxDerefs
+  
+  fn pointee(_1: Box<i32>) -> () {
+-     debug foo => (*_1);
++     debug foo => (*(((_1.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>).0: *const i32));
+      let mut _0: ();
+  
+      bb0: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/elaborate_box_deref_in_debuginfo.rs b/tests/mir-opt/elaborate_box_deref_in_debuginfo.rs
new file mode 100644
index 00000000000..0046e7104f1
--- /dev/null
+++ b/tests/mir-opt/elaborate_box_deref_in_debuginfo.rs
@@ -0,0 +1,20 @@
+// skip-filecheck
+//@ test-mir-pass: ElaborateBoxDerefs
+
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+// EMIT_MIR elaborate_box_deref_in_debuginfo.pointee.ElaborateBoxDerefs.diff
+#[custom_mir(dialect = "built")]
+fn pointee(opt: Box<i32>) {
+    mir!(
+        debug foo => *opt;
+        {
+            Return()
+        }
+    )
+}
+
+fn main() {}
diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir
index 14ad951a476..0fe4fd37072 100644
--- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir
@@ -5,63 +5,93 @@ fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] {
     let mut _0: &[u8];
     scope 1 (inlined <Vec<u8> as Deref>::deref) {
         debug self => _1;
-        let mut _4: *const u8;
-        let mut _5: usize;
+        let mut _7: usize;
         scope 2 (inlined Vec::<u8>::as_ptr) {
             debug self => _1;
             let mut _2: &alloc::raw_vec::RawVec<u8>;
             scope 3 (inlined alloc::raw_vec::RawVec::<u8>::ptr) {
                 debug self => _2;
-                let mut _3: std::ptr::NonNull<u8>;
-                scope 4 (inlined Unique::<u8>::as_ptr) {
-                    debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _3;
-                    debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
-                    scope 5 (inlined NonNull::<u8>::as_ptr) {
+                let mut _3: &alloc::raw_vec::RawVecInner;
+                scope 4 (inlined alloc::raw_vec::RawVecInner::ptr::<u8>) {
+                    debug self => _3;
+                    let mut _6: std::ptr::NonNull<u8>;
+                    scope 5 (inlined alloc::raw_vec::RawVecInner::non_null::<u8>) {
                         debug self => _3;
+                        let mut _4: std::ptr::NonNull<u8>;
+                        scope 6 (inlined Unique::<u8>::cast::<u8>) {
+                            debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4;
+                            debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
+                            scope 7 (inlined NonNull::<u8>::cast::<u8>) {
+                                debug self => _4;
+                                scope 8 (inlined NonNull::<u8>::as_ptr) {
+                                    debug self => _4;
+                                    let mut _5: *const u8;
+                                }
+                            }
+                        }
+                        scope 9 (inlined #[track_caller] <Unique<u8> as Into<NonNull<u8>>>::into) {
+                            debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _6;
+                            debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
+                            scope 10 (inlined <NonNull<u8> as From<Unique<u8>>>::from) {
+                                debug ((unique: Unique<u8>).0: std::ptr::NonNull<u8>) => _6;
+                                debug ((unique: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
+                                scope 11 (inlined Unique::<u8>::as_non_null_ptr) {
+                                    debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _6;
+                                    debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
+                                }
+                            }
+                        }
+                    }
+                    scope 12 (inlined NonNull::<u8>::as_ptr) {
+                        debug self => _6;
                     }
                 }
             }
         }
-        scope 6 (inlined std::slice::from_raw_parts::<'_, u8>) {
-            debug data => _4;
-            debug len => _5;
-            let _6: *const [u8];
-            scope 7 (inlined core::ub_checks::check_language_ub) {
-                scope 8 (inlined core::ub_checks::check_language_ub::runtime) {
+        scope 13 (inlined std::slice::from_raw_parts::<'_, u8>) {
+            debug data => _5;
+            debug len => _7;
+            let _8: *const [u8];
+            scope 14 (inlined core::ub_checks::check_language_ub) {
+                scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
                 }
             }
-            scope 9 (inlined std::mem::size_of::<u8>) {
+            scope 16 (inlined std::mem::size_of::<u8>) {
             }
-            scope 10 (inlined align_of::<u8>) {
+            scope 17 (inlined align_of::<u8>) {
             }
-            scope 11 (inlined slice_from_raw_parts::<u8>) {
-                debug data => _4;
-                debug len => _5;
-                scope 12 (inlined std::ptr::from_raw_parts::<[u8], u8>) {
-                    debug data_pointer => _4;
-                    debug metadata => _5;
+            scope 18 (inlined slice_from_raw_parts::<u8>) {
+                debug data => _5;
+                debug len => _7;
+                scope 19 (inlined std::ptr::from_raw_parts::<[u8], u8>) {
+                    debug data_pointer => _5;
+                    debug metadata => _7;
                 }
             }
         }
     }
 
     bb0: {
-        StorageLive(_4);
         StorageLive(_2);
         _2 = &((*_1).0: alloc::raw_vec::RawVec<u8>);
         StorageLive(_3);
-        _3 = ((((*_1).0: alloc::raw_vec::RawVec<u8>).0: std::ptr::Unique<u8>).0: std::ptr::NonNull<u8>);
-        _4 = (_3.0: *const u8);
-        StorageDead(_3);
-        StorageDead(_2);
-        StorageLive(_5);
-        _5 = ((*_1).1: usize);
+        _3 = &(((*_1).0: alloc::raw_vec::RawVec<u8>).0: alloc::raw_vec::RawVecInner);
         StorageLive(_6);
-        _6 = *const [u8] from (_4, _5);
-        _0 = &(*_6);
-        StorageDead(_6);
-        StorageDead(_5);
+        StorageLive(_4);
+        _4 = (((((*_1).0: alloc::raw_vec::RawVec<u8>).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique<u8>).0: std::ptr::NonNull<u8>);
+        _5 = (_4.0: *const u8);
+        _6 = NonNull::<u8> { pointer: _5 };
         StorageDead(_4);
+        StorageDead(_6);
+        StorageDead(_3);
+        StorageDead(_2);
+        StorageLive(_7);
+        _7 = ((*_1).1: usize);
+        StorageLive(_8);
+        _8 = *const [u8] from (_5, _7);
+        _0 = &(*_8);
+        StorageDead(_8);
+        StorageDead(_7);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir
index 14ad951a476..0fe4fd37072 100644
--- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir
@@ -5,63 +5,93 @@ fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] {
     let mut _0: &[u8];
     scope 1 (inlined <Vec<u8> as Deref>::deref) {
         debug self => _1;
-        let mut _4: *const u8;
-        let mut _5: usize;
+        let mut _7: usize;
         scope 2 (inlined Vec::<u8>::as_ptr) {
             debug self => _1;
             let mut _2: &alloc::raw_vec::RawVec<u8>;
             scope 3 (inlined alloc::raw_vec::RawVec::<u8>::ptr) {
                 debug self => _2;
-                let mut _3: std::ptr::NonNull<u8>;
-                scope 4 (inlined Unique::<u8>::as_ptr) {
-                    debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _3;
-                    debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
-                    scope 5 (inlined NonNull::<u8>::as_ptr) {
+                let mut _3: &alloc::raw_vec::RawVecInner;
+                scope 4 (inlined alloc::raw_vec::RawVecInner::ptr::<u8>) {
+                    debug self => _3;
+                    let mut _6: std::ptr::NonNull<u8>;
+                    scope 5 (inlined alloc::raw_vec::RawVecInner::non_null::<u8>) {
                         debug self => _3;
+                        let mut _4: std::ptr::NonNull<u8>;
+                        scope 6 (inlined Unique::<u8>::cast::<u8>) {
+                            debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4;
+                            debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
+                            scope 7 (inlined NonNull::<u8>::cast::<u8>) {
+                                debug self => _4;
+                                scope 8 (inlined NonNull::<u8>::as_ptr) {
+                                    debug self => _4;
+                                    let mut _5: *const u8;
+                                }
+                            }
+                        }
+                        scope 9 (inlined #[track_caller] <Unique<u8> as Into<NonNull<u8>>>::into) {
+                            debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _6;
+                            debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
+                            scope 10 (inlined <NonNull<u8> as From<Unique<u8>>>::from) {
+                                debug ((unique: Unique<u8>).0: std::ptr::NonNull<u8>) => _6;
+                                debug ((unique: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
+                                scope 11 (inlined Unique::<u8>::as_non_null_ptr) {
+                                    debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _6;
+                                    debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
+                                }
+                            }
+                        }
+                    }
+                    scope 12 (inlined NonNull::<u8>::as_ptr) {
+                        debug self => _6;
                     }
                 }
             }
         }
-        scope 6 (inlined std::slice::from_raw_parts::<'_, u8>) {
-            debug data => _4;
-            debug len => _5;
-            let _6: *const [u8];
-            scope 7 (inlined core::ub_checks::check_language_ub) {
-                scope 8 (inlined core::ub_checks::check_language_ub::runtime) {
+        scope 13 (inlined std::slice::from_raw_parts::<'_, u8>) {
+            debug data => _5;
+            debug len => _7;
+            let _8: *const [u8];
+            scope 14 (inlined core::ub_checks::check_language_ub) {
+                scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
                 }
             }
-            scope 9 (inlined std::mem::size_of::<u8>) {
+            scope 16 (inlined std::mem::size_of::<u8>) {
             }
-            scope 10 (inlined align_of::<u8>) {
+            scope 17 (inlined align_of::<u8>) {
             }
-            scope 11 (inlined slice_from_raw_parts::<u8>) {
-                debug data => _4;
-                debug len => _5;
-                scope 12 (inlined std::ptr::from_raw_parts::<[u8], u8>) {
-                    debug data_pointer => _4;
-                    debug metadata => _5;
+            scope 18 (inlined slice_from_raw_parts::<u8>) {
+                debug data => _5;
+                debug len => _7;
+                scope 19 (inlined std::ptr::from_raw_parts::<[u8], u8>) {
+                    debug data_pointer => _5;
+                    debug metadata => _7;
                 }
             }
         }
     }
 
     bb0: {
-        StorageLive(_4);
         StorageLive(_2);
         _2 = &((*_1).0: alloc::raw_vec::RawVec<u8>);
         StorageLive(_3);
-        _3 = ((((*_1).0: alloc::raw_vec::RawVec<u8>).0: std::ptr::Unique<u8>).0: std::ptr::NonNull<u8>);
-        _4 = (_3.0: *const u8);
-        StorageDead(_3);
-        StorageDead(_2);
-        StorageLive(_5);
-        _5 = ((*_1).1: usize);
+        _3 = &(((*_1).0: alloc::raw_vec::RawVec<u8>).0: alloc::raw_vec::RawVecInner);
         StorageLive(_6);
-        _6 = *const [u8] from (_4, _5);
-        _0 = &(*_6);
-        StorageDead(_6);
-        StorageDead(_5);
+        StorageLive(_4);
+        _4 = (((((*_1).0: alloc::raw_vec::RawVec<u8>).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique<u8>).0: std::ptr::NonNull<u8>);
+        _5 = (_4.0: *const u8);
+        _6 = NonNull::<u8> { pointer: _5 };
         StorageDead(_4);
+        StorageDead(_6);
+        StorageDead(_3);
+        StorageDead(_2);
+        StorageLive(_7);
+        _7 = ((*_1).1: usize);
+        StorageLive(_8);
+        _8 = *const [u8] from (_5, _7);
+        _0 = &(*_8);
+        StorageDead(_8);
+        StorageDead(_7);
         return;
     }
 }
diff --git a/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-abort.diff b/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-abort.diff
index da7a2bd10e0..1e1ddfae0eb 100644
--- a/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-abort.diff
+++ b/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-abort.diff
@@ -19,14 +19,16 @@
   
       bb1: {
           _2 = discriminant(_1);
--         switchInt(move _2) -> [0: bb4, 1: bb3, otherwise: bb2];
-+         _5 = Eq(_2, const 0_isize);
+-         switchInt(move _2) -> [1: bb3, otherwise: bb2];
++         _5 = Ne(_2, const 1_isize);
 +         assume(move _5);
-+         goto -> bb4;
++         goto -> bb2;
       }
   
       bb2: {
-          unreachable;
+          _0 = const ();
+          StorageDead(_1);
+          return;
       }
   
       bb3: {
@@ -35,11 +37,5 @@
 -         StorageLive(_4);
           unreachable;
       }
-  
-      bb4: {
-          _0 = const ();
-          StorageDead(_1);
-          return;
-      }
   }
   
diff --git a/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-unwind.diff b/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-unwind.diff
index a2121fc684f..809d24aa15a 100644
--- a/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-unwind.diff
+++ b/tests/mir-opt/unreachable.as_match.UnreachablePropagation.panic-unwind.diff
@@ -19,14 +19,16 @@
   
       bb1: {
           _2 = discriminant(_1);
--         switchInt(move _2) -> [0: bb4, 1: bb3, otherwise: bb2];
-+         _5 = Eq(_2, const 0_isize);
+-         switchInt(move _2) -> [1: bb3, otherwise: bb2];
++         _5 = Ne(_2, const 1_isize);
 +         assume(move _5);
-+         goto -> bb4;
++         goto -> bb2;
       }
   
       bb2: {
-          unreachable;
+          _0 = const ();
+          StorageDead(_1);
+          return;
       }
   
       bb3: {
@@ -35,11 +37,5 @@
 -         StorageLive(_4);
           unreachable;
       }
-  
-      bb4: {
-          _0 = const ();
-          StorageDead(_1);
-          return;
-      }
   }
   
diff --git a/tests/mir-opt/unreachable.rs b/tests/mir-opt/unreachable.rs
index 881e3542f0a..f7f4815ae7c 100644
--- a/tests/mir-opt/unreachable.rs
+++ b/tests/mir-opt/unreachable.rs
@@ -45,18 +45,16 @@ fn as_match() {
     // CHECK: bb0: {
     // CHECK: {{_.*}} = empty()
     // CHECK: bb1: {
-    // CHECK: [[eq:_.*]] = Eq({{.*}}, const 0_isize);
+    // CHECK: [[eq:_.*]] = Ne({{.*}}, const 1_isize);
     // CHECK-NEXT: assume(move [[eq]]);
-    // CHECK-NEXT: goto -> bb4;
+    // CHECK-NEXT: goto -> bb2;
     // CHECK: bb2: {
-    // CHECK-NEXT: unreachable;
+    // CHECK: return;
     // CHECK: bb3: {
     // CHECK-NEXT: unreachable;
-    // CHECK: bb4: {
-    // CHECK: return;
     match empty() {
-        None => {}
         Some(_x) => match _x {},
+        None => {}
     }
 }
 
diff --git a/tests/mir-opt/unreachable_enum_branching.rs b/tests/mir-opt/unreachable_enum_branching.rs
index fac14042b10..7647f9bf077 100644
--- a/tests/mir-opt/unreachable_enum_branching.rs
+++ b/tests/mir-opt/unreachable_enum_branching.rs
@@ -49,7 +49,7 @@ struct Plop {
 fn simple() {
     // CHECK-LABEL: fn simple(
     // CHECK: [[discr:_.*]] = discriminant(
-    // CHECK: switchInt(move [[discr]]) -> [0: [[unreachable:bb.*]], 1: [[unreachable]], 2: bb2, otherwise: [[unreachable]]];
+    // CHECK: switchInt(move [[discr]]) -> [0: [[unreachable:bb.*]], 1: [[unreachable]], 2: bb1, otherwise: [[unreachable]]];
     // CHECK: [[unreachable]]: {
     // CHECK-NEXT: unreachable;
     match Test1::C {
diff --git a/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff
index 8aef9914936..5c08648fac3 100644
--- a/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff
+++ b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-abort.diff
@@ -14,40 +14,40 @@
           StorageLive(_2);
           _2 = Test1::C;
           _3 = discriminant(_2);
--         switchInt(move _3) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb1];
-+         switchInt(move _3) -> [0: bb1, 1: bb1, 2: bb2, otherwise: bb1];
+-         switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1];
++         switchInt(move _3) -> [0: bb5, 1: bb5, 2: bb1, otherwise: bb5];
       }
   
       bb1: {
-          unreachable;
-      }
-  
-      bb2: {
           StorageLive(_5);
           _5 = const "C";
           _1 = &(*_5);
           StorageDead(_5);
-          goto -> bb5;
+          goto -> bb4;
       }
   
-      bb3: {
+      bb2: {
           StorageLive(_4);
           _4 = const "B(Empty)";
           _1 = &(*_4);
           StorageDead(_4);
-          goto -> bb5;
+          goto -> bb4;
       }
   
-      bb4: {
+      bb3: {
           _1 = const "A(Empty)";
-          goto -> bb5;
+          goto -> bb4;
       }
   
-      bb5: {
+      bb4: {
           StorageDead(_2);
           StorageDead(_1);
           _0 = const ();
           return;
++     }
++ 
++     bb5: {
++         unreachable;
       }
   }
   
diff --git a/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff
index 8aef9914936..5c08648fac3 100644
--- a/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff
+++ b/tests/mir-opt/unreachable_enum_branching.simple.UnreachableEnumBranching.panic-unwind.diff
@@ -14,40 +14,40 @@
           StorageLive(_2);
           _2 = Test1::C;
           _3 = discriminant(_2);
--         switchInt(move _3) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb1];
-+         switchInt(move _3) -> [0: bb1, 1: bb1, 2: bb2, otherwise: bb1];
+-         switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1];
++         switchInt(move _3) -> [0: bb5, 1: bb5, 2: bb1, otherwise: bb5];
       }
   
       bb1: {
-          unreachable;
-      }
-  
-      bb2: {
           StorageLive(_5);
           _5 = const "C";
           _1 = &(*_5);
           StorageDead(_5);
-          goto -> bb5;
+          goto -> bb4;
       }
   
-      bb3: {
+      bb2: {
           StorageLive(_4);
           _4 = const "B(Empty)";
           _1 = &(*_4);
           StorageDead(_4);
-          goto -> bb5;
+          goto -> bb4;
       }
   
-      bb4: {
+      bb3: {
           _1 = const "A(Empty)";
-          goto -> bb5;
+          goto -> bb4;
       }
   
-      bb5: {
+      bb4: {
           StorageDead(_2);
           StorageDead(_1);
           _0 = const ();
           return;
++     }
++ 
++     bb5: {
++         unreachable;
       }
   }
   
diff --git a/tests/run-make/dump-ice-to-disk/rmake.rs b/tests/run-make/dump-ice-to-disk/rmake.rs
index a64103fa516..48b4071e065 100644
--- a/tests/run-make/dump-ice-to-disk/rmake.rs
+++ b/tests/run-make/dump-ice-to-disk/rmake.rs
@@ -1,137 +1,197 @@
-// This test checks if internal compilation error (ICE) log files work as expected.
-// - Get the number of lines from the log files without any configuration options,
-// then check that the line count doesn't change if the backtrace gets configured to be short
-// or full.
-// - Check that disabling ICE logging results in zero files created.
-// - Check that the ICE files contain some of the expected strings.
-// - exercise the -Zmetrics-dir nightly flag
-// - verify what happens when both the nightly flag and env variable are set
-// - test the RUST_BACKTRACE=0 behavior against the file creation
+//! This test checks if Internal Compilation Error (ICE) dump files `rustc-ice*.txt` work as
+//! expected.
+//!
+//! - Basic sanity checks on a default ICE dump.
+//! - Get the number of lines from the dump files without any `RUST_BACKTRACE` options, then check
+//!   ICE dump file (line count) is not affected by `RUSTC_BACKTRACE` settings.
+//! - Check that disabling ICE dumping results in zero dump files created.
+//! - Check that the ICE dump contain some of the expected strings.
+//! - Check that `RUST_BACKTRACE=0` prevents ICE dump from created.
+//! - Exercise the `-Zmetrics-dir` nightly flag (#128914):
+//!     - When `-Zmetrics=dir=PATH` is present but `RUSTC_ICE` is not set, check that the ICE dump
+//!       is placed under `PATH`.
+//!     - When `RUSTC_ICE=RUSTC_ICE_PATH` and `-Zmetrics-dir=METRICS_PATH` are both provided, check
+//!       that `RUSTC_ICE_PATH` takes precedence and no ICE dump is emitted under `METRICS_PATH`.
+//!
+//! See <https://github.com/rust-lang/rust/pull/108714>.
 
-// See https://github.com/rust-lang/rust/pull/108714
+//@ ignore-windows
+// FIXME(#128911): @jieyouxu: This test is sometimes for whatever forsaken reason flakey in
+// `i686-mingw`, and I cannot reproduce it locally. The error messages upon assertion failure in
+// this test is intentionally extremely verbose to aid debugging that issue.
 
-use run_make_support::{cwd, has_extension, has_prefix, rfs, rustc, shallow_find_files};
+use std::cell::OnceCell;
+use std::path::{Path, PathBuf};
 
-fn main() {
-    rustc().input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail();
-    let default = get_text_from_ice(".").lines().count();
-
-    clear_ice_files();
-    rustc().env("RUSTC_ICE", cwd()).input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail();
-    let ice_text = get_text_from_ice(cwd());
-    let default_set = ice_text.lines().count();
-    let content = ice_text;
-    let ice_files = shallow_find_files(cwd(), |path| {
-        has_prefix(path, "rustc-ice") && has_extension(path, "txt")
-    });
+use run_make_support::{
+    cwd, filename_contains, has_extension, has_prefix, rfs, run_in_tmpdir, rustc,
+    shallow_find_files,
+};
+
+#[derive(Debug)]
+struct IceDump {
+    name: &'static str,
+    path: PathBuf,
+    message: String,
+}
+
+impl IceDump {
+    fn lines_count(&self) -> usize {
+        self.message.lines().count()
+    }
+}
+
+#[track_caller]
+fn assert_ice_len_equals(left: &IceDump, right: &IceDump) {
+    let left_len = left.lines_count();
+    let right_len = right.lines_count();
+
+    if left_len != right_len {
+        eprintln!("=== {} ICE MESSAGE ({} lines) ====", left.name, left_len);
+        eprintln!("{}", left.message);
+
+        eprintln!("=== {} ICE MESSAGE ({} lines) ====", right.name, right_len);
+        eprintln!("{}", right.message);
+
+        eprintln!("====================================");
+        panic!(
+            "ICE message length mismatch: {} has {} lines but {} has {} lines",
+            left.name, left_len, right.name, right_len
+        );
+    }
+}
+
+fn find_ice_dumps_in_dir<P: AsRef<Path>>(dir: P) -> Vec<PathBuf> {
+    shallow_find_files(dir, |path| has_prefix(path, "rustc-ice") && has_extension(path, "txt"))
+}
+
+// Assert only one `rustc-ice*.txt` ICE file exists, and extract the ICE message from the ICE file.
+#[track_caller]
+fn extract_exactly_one_ice_file<P: AsRef<Path>>(name: &'static str, dir: P) -> IceDump {
+    let ice_files = find_ice_dumps_in_dir(dir);
     assert_eq!(ice_files.len(), 1); // There should only be 1 ICE file.
-    let ice_file_name =
-        ice_files.first().and_then(|f| f.file_name()).and_then(|n| n.to_str()).unwrap();
-    // Ensure that the ICE dump path doesn't contain `:`, because they cause problems on Windows.
-    assert!(!ice_file_name.contains(":"), "{ice_file_name}");
-    assert_eq!(default, default_set);
-    assert!(default > 0);
-    // Some of the expected strings in an ICE file should appear.
-    assert!(content.contains("thread 'rustc' panicked at"));
-    assert!(content.contains("stack backtrace:"));
-
-    test_backtrace_short(default);
-    test_backtrace_full(default);
-    test_backtrace_disabled(default);
-
-    clear_ice_files();
-    // The ICE dump is explicitly disabled. Therefore, this should produce no files.
-    rustc().env("RUSTC_ICE", "0").input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail();
-    let ice_files = shallow_find_files(cwd(), |path| {
-        has_prefix(path, "rustc-ice") && has_extension(path, "txt")
+    let path = ice_files.get(0).unwrap();
+    let message = rfs::read_to_string(path);
+    IceDump { name, path: path.to_path_buf(), message }
+}
+
+fn main() {
+    // Establish baseline ICE message.
+    let mut default_ice_dump = OnceCell::new();
+    run_in_tmpdir(|| {
+        rustc().env("RUSTC_ICE", cwd()).input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail();
+        let dump = extract_exactly_one_ice_file("baseline", cwd());
+        // Ensure that the ICE dump path doesn't contain `:`, because they cause problems on
+        // Windows.
+        assert!(!filename_contains(&dump.path, ":"), "{} contains `:`", dump.path.display());
+        // Some of the expected strings in an ICE file should appear.
+        assert!(dump.message.contains("thread 'rustc' panicked at"));
+        assert!(dump.message.contains("stack backtrace:"));
+        default_ice_dump.set(dump).unwrap();
     });
-    assert!(ice_files.is_empty()); // There should be 0 ICE files.
+    let default_ice_dump = default_ice_dump.get().unwrap();
 
-    metrics_dir(default);
-}
+    test_backtrace_short(default_ice_dump);
+    test_backtrace_full(default_ice_dump);
+    test_backtrace_disabled(default_ice_dump);
+    test_ice_dump_disabled();
 
-fn test_backtrace_short(baseline: usize) {
-    clear_ice_files();
-    rustc()
-        .env("RUSTC_ICE", cwd())
-        .input("lib.rs")
-        .env("RUST_BACKTRACE", "short")
-        .arg("-Ztreat-err-as-bug=1")
-        .run_fail();
-    let short = get_text_from_ice(cwd()).lines().count();
-    // backtrace length in dump shouldn't be changed by RUST_BACKTRACE
-    assert_eq!(short, baseline);
+    test_metrics_dir(default_ice_dump);
 }
 
-fn test_backtrace_full(baseline: usize) {
-    clear_ice_files();
-    rustc()
-        .env("RUSTC_ICE", cwd())
-        .input("lib.rs")
-        .env("RUST_BACKTRACE", "full")
-        .arg("-Ztreat-err-as-bug=1")
-        .run_fail();
-    let full = get_text_from_ice(cwd()).lines().count();
-    // backtrace length in dump shouldn't be changed by RUST_BACKTRACE
-    assert_eq!(full, baseline);
+#[track_caller]
+fn test_backtrace_short(baseline: &IceDump) {
+    run_in_tmpdir(|| {
+        rustc()
+            .env("RUSTC_ICE", cwd())
+            .input("lib.rs")
+            .env("RUST_BACKTRACE", "short")
+            .arg("-Ztreat-err-as-bug=1")
+            .run_fail();
+        let dump = extract_exactly_one_ice_file("RUST_BACKTRACE=short", cwd());
+        // Backtrace length in dump shouldn't be changed by `RUST_BACKTRACE`.
+        assert_ice_len_equals(baseline, &dump);
+    });
 }
 
-fn test_backtrace_disabled(baseline: usize) {
-    clear_ice_files();
-    rustc()
-        .env("RUSTC_ICE", cwd())
-        .input("lib.rs")
-        .env("RUST_BACKTRACE", "0")
-        .arg("-Ztreat-err-as-bug=1")
-        .run_fail();
-    let disabled = get_text_from_ice(cwd()).lines().count();
-    // backtrace length in dump shouldn't be changed by RUST_BACKTRACE
-    assert_eq!(disabled, baseline);
+#[track_caller]
+fn test_backtrace_full(baseline: &IceDump) {
+    run_in_tmpdir(|| {
+        rustc()
+            .env("RUSTC_ICE", cwd())
+            .input("lib.rs")
+            .env("RUST_BACKTRACE", "full")
+            .arg("-Ztreat-err-as-bug=1")
+            .run_fail();
+        let dump = extract_exactly_one_ice_file("RUST_BACKTRACE=full", cwd());
+        // Backtrace length in dump shouldn't be changed by `RUST_BACKTRACE`.
+        assert_ice_len_equals(baseline, &dump);
+    });
 }
 
-fn metrics_dir(baseline: usize) {
-    test_flag_only(baseline);
-    test_flag_and_env(baseline);
+#[track_caller]
+fn test_backtrace_disabled(baseline: &IceDump) {
+    run_in_tmpdir(|| {
+        rustc()
+            .env("RUSTC_ICE", cwd())
+            .input("lib.rs")
+            .env("RUST_BACKTRACE", "0")
+            .arg("-Ztreat-err-as-bug=1")
+            .run_fail();
+        let dump = extract_exactly_one_ice_file("RUST_BACKTRACE=disabled", cwd());
+        // Backtrace length in dump shouldn't be changed by `RUST_BACKTRACE`.
+        assert_ice_len_equals(baseline, &dump);
+    });
 }
 
-fn test_flag_only(baseline: usize) {
-    clear_ice_files();
-    let metrics_arg = format!("-Zmetrics-dir={}", cwd().display());
-    rustc().input("lib.rs").arg("-Ztreat-err-as-bug=1").arg(metrics_arg).run_fail();
-    let output = get_text_from_ice(cwd()).lines().count();
-    assert_eq!(output, baseline);
+#[track_caller]
+fn test_ice_dump_disabled() {
+    // The ICE dump is explicitly disabled. Therefore, this should produce no files.
+    run_in_tmpdir(|| {
+        rustc().env("RUSTC_ICE", "0").input("lib.rs").arg("-Ztreat-err-as-bug=1").run_fail();
+        let ice_files = find_ice_dumps_in_dir(cwd());
+        assert!(ice_files.is_empty(), "there should be no ICE files if `RUSTC_ICE=0` is set");
+    });
 }
 
-fn test_flag_and_env(baseline: usize) {
-    clear_ice_files();
-    let metrics_arg = format!("-Zmetrics-dir={}", cwd().display());
-    let real_dir = cwd().join("actually_put_ice_here");
-    rfs::create_dir(real_dir.clone());
-    rustc()
-        .input("lib.rs")
-        .env("RUSTC_ICE", real_dir.clone())
-        .arg("-Ztreat-err-as-bug=1")
-        .arg(metrics_arg)
-        .run_fail();
-    let output = get_text_from_ice(real_dir).lines().count();
-    assert_eq!(output, baseline);
+#[track_caller]
+fn test_metrics_dir(baseline: &IceDump) {
+    test_flag_only(baseline);
+    test_flag_and_env(baseline);
 }
 
-fn clear_ice_files() {
-    let ice_files = shallow_find_files(cwd(), |path| {
-        has_prefix(path, "rustc-ice") && has_extension(path, "txt")
+#[track_caller]
+fn test_flag_only(baseline: &IceDump) {
+    run_in_tmpdir(|| {
+        let metrics_arg = format!("-Zmetrics-dir={}", cwd().display());
+        rustc()
+            .env_remove("RUSTC_ICE") // prevent interference from environment
+            .input("lib.rs")
+            .arg("-Ztreat-err-as-bug=1")
+            .arg(metrics_arg)
+            .run_fail();
+        let dump = extract_exactly_one_ice_file("-Zmetrics-dir only", cwd());
+        assert_ice_len_equals(baseline, &dump);
     });
-    for file in ice_files {
-        rfs::remove_file(file);
-    }
 }
 
 #[track_caller]
-fn get_text_from_ice(dir: impl AsRef<std::path::Path>) -> String {
-    let ice_files =
-        shallow_find_files(dir, |path| has_prefix(path, "rustc-ice") && has_extension(path, "txt"));
-    assert_eq!(ice_files.len(), 1); // There should only be 1 ICE file.
-    let ice_file = ice_files.get(0).unwrap();
-    let output = rfs::read_to_string(ice_file);
-    output
+fn test_flag_and_env(baseline: &IceDump) {
+    run_in_tmpdir(|| {
+        let metrics_arg = format!("-Zmetrics-dir={}", cwd().display());
+        let real_dir = cwd().join("actually_put_ice_here");
+        rfs::create_dir(&real_dir);
+        rustc()
+            .input("lib.rs")
+            .env("RUSTC_ICE", &real_dir)
+            .arg("-Ztreat-err-as-bug=1")
+            .arg(metrics_arg)
+            .run_fail();
+
+        let cwd_ice_files = find_ice_dumps_in_dir(cwd());
+        assert!(cwd_ice_files.is_empty(), "RUSTC_ICE should override -Zmetrics-dir");
+
+        let dump = extract_exactly_one_ice_file("RUSTC_ICE overrides -Zmetrics-dir", real_dir);
+        assert_ice_len_equals(baseline, &dump);
+    });
 }
diff --git a/tests/run-make/fmt-write-bloat/main.rs b/tests/run-make/fmt-write-bloat/main.rs
index e86c48014c3..6f206d6515a 100644
--- a/tests/run-make/fmt-write-bloat/main.rs
+++ b/tests/run-make/fmt-write-bloat/main.rs
@@ -5,7 +5,7 @@
 use core::fmt;
 use core::fmt::Write;
 
-#[link(name = "c")]
+#[cfg_attr(not(windows), link(name = "c"))]
 extern "C" {}
 
 struct Dummy;
diff --git a/tests/run-make/fmt-write-bloat/rmake.rs b/tests/run-make/fmt-write-bloat/rmake.rs
index 4ae226ec0e2..6875ef9ddc0 100644
--- a/tests/run-make/fmt-write-bloat/rmake.rs
+++ b/tests/run-make/fmt-write-bloat/rmake.rs
@@ -15,9 +15,12 @@
 //! `NO_DEBUG_ASSERTIONS=1`). If debug assertions are disabled, then we can check for the absence of
 //! additional `usize` formatting and padding related symbols.
 
-// Reason: This test is `ignore-windows` because the `no_std` test (using `#[link(name = "c")])`
-// doesn't link on windows.
 //@ ignore-windows
+// Reason:
+// - MSVC targets really need to parse the .pdb file (aka the debug information).
+//   On Windows there's an API for that (dbghelp) which maybe we can use
+// - MinGW targets have a lot of symbols included in their runtime which we can't avoid.
+//   We would need to make the symbols we're looking for more specific for this test to work.
 //@ ignore-cross-compile
 
 use run_make_support::env::no_debug_assertions;
diff --git a/tests/rustdoc-gui/code-example-buttons.goml b/tests/rustdoc-gui/code-example-buttons.goml
index 57ea2970072..4f037ec79f5 100644
--- a/tests/rustdoc-gui/code-example-buttons.goml
+++ b/tests/rustdoc-gui/code-example-buttons.goml
@@ -1,5 +1,6 @@
 // This test ensures that code blocks buttons are displayed on hover and when you click on them.
 go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html"
+include: "utils.goml"
 
 // First we check we "hover".
 move-cursor-to: ".example-wrap"
@@ -19,3 +20,77 @@ click: ".example-wrap"
 move-cursor-to: ".search-input"
 assert-count: (".example-wrap:not(:hover) .button-holder.keep-visible", 0)
 assert-css: (".example-wrap .copy-button", { "visibility": "hidden" })
+
+// Clicking on the "copy code" button shouldn't make the buttons stick.
+click: ".example-wrap .copy-button"
+move-cursor-to: ".search-input"
+assert-count: (".example-wrap:not(:hover) .button-holder.keep-visible", 0)
+assert-css: (".example-wrap .copy-button", { "visibility": "hidden" })
+
+define-function: (
+    "check-buttons",
+    [theme, background, filter, filter_hover],
+    block {
+        call-function: ("switch-theme", {"theme": |theme|})
+
+        assert-css: (".example-wrap .test-arrow", {"visibility": "hidden"})
+        assert-css: (".example-wrap .copy-button", {"visibility": "hidden"})
+
+        move-cursor-to: ".example-wrap"
+        assert-css: (".example-wrap .test-arrow", {
+            "visibility": "visible",
+            "background-color": |background|,
+            "border-radius": "2px",
+        })
+        assert-css: (".example-wrap .test-arrow::before", {
+            "filter": |filter|,
+        })
+        assert-css: (".example-wrap .copy-button", {
+            "visibility": "visible",
+            "background-color": |background|,
+            "border-radius": "2px",
+        })
+        assert-css: (".example-wrap .copy-button::before", {
+            "filter": |filter|,
+        })
+
+        move-cursor-to: ".example-wrap .test-arrow"
+        assert-css: (".example-wrap .test-arrow:hover", {
+            "visibility": "visible",
+            "background-color": |background|,
+            "border-radius": "2px",
+        })
+        assert-css: (".example-wrap .test-arrow:hover::before", {
+            "filter": |filter_hover|,
+        })
+
+        move-cursor-to: ".example-wrap .copy-button"
+        assert-css: (".example-wrap .copy-button:hover", {
+            "visibility": "visible",
+            "background-color": |background|,
+            "border-radius": "2px",
+        })
+        assert-css: (".example-wrap .copy-button:hover::before", {
+            "filter": |filter_hover|,
+        })
+    },
+)
+
+call-function: ("check-buttons",{
+    "theme": "ayu",
+    "background": "#0f1419",
+    "filter": "invert(0.7)",
+    "filter_hover": "invert(1)",
+})
+call-function: ("check-buttons",{
+    "theme": "dark",
+    "background": "#353535",
+    "filter": "invert(0.5)",
+    "filter_hover": "invert(0.65)",
+})
+call-function: ("check-buttons",{
+    "theme": "light",
+    "background": "#fff",
+    "filter": "invert(0.5)",
+    "filter_hover": "invert(0.35)",
+})
diff --git a/tests/rustdoc-gui/copy-code.goml b/tests/rustdoc-gui/copy-code.goml
index 72a5bece175..9cc717bc67a 100644
--- a/tests/rustdoc-gui/copy-code.goml
+++ b/tests/rustdoc-gui/copy-code.goml
@@ -24,11 +24,11 @@ define-function: (
 )
 
 call-function: ("check-copy-button", {})
-// Checking that the run button and the copy button have the same height.
+// Checking that the run button and the copy button have the same height and same width.
 compare-elements-size: (
     ".example-wrap:nth-of-type(1) .test-arrow",
     ".example-wrap:nth-of-type(1) .copy-button",
-    ["height"],
+    ["height", "width"],
 )
 // ... and the same y position.
 compare-elements-position: (
diff --git a/tests/rustdoc-gui/run-on-hover.goml b/tests/rustdoc-gui/run-on-hover.goml
deleted file mode 100644
index b62da79b780..00000000000
--- a/tests/rustdoc-gui/run-on-hover.goml
+++ /dev/null
@@ -1,54 +0,0 @@
-// Example code blocks sometimes have a "Run" button to run them on the
-// Playground. That button is hidden until the user hovers over the code block.
-// This test checks that it is hidden, and that it shows on hover. It also
-// checks for its color.
-include: "utils.goml"
-go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html"
-show-text: true
-
-define-function: (
-    "check-run-button",
-    [theme, color, background, hover_color, hover_background],
-    block {
-        call-function: ("switch-theme", {"theme": |theme|})
-        assert-css: (".test-arrow", {"visibility": "hidden"})
-        move-cursor-to: ".example-wrap"
-        assert-css: (".test-arrow", {
-            "visibility": "visible",
-            "color": |color|,
-            "background-color": |background|,
-            "font-size": "16px",
-            "border-radius": "2px",
-        })
-        move-cursor-to: ".test-arrow"
-        assert-css: (".test-arrow:hover", {
-            "visibility": "visible",
-            "color": |hover_color|,
-            "background-color": |hover_background|,
-            "font-size": "16px",
-            "border-radius": "2px",
-        })
-    },
-)
-
-call-function: ("check-run-button", {
-    "theme": "ayu",
-    "color": "#788797",
-    "background": "rgba(57, 175, 215, 0.09)",
-    "hover_color": "#c5c5c5",
-    "hover_background": "rgba(57, 175, 215, 0.37)",
-})
-call-function: ("check-run-button", {
-    "theme": "dark",
-    "color": "#dedede",
-    "background": "rgba(78, 139, 202, 0.2)",
-    "hover_color": "#dedede",
-    "hover_background": "rgb(78, 139, 202)",
-})
-call-function: ("check-run-button", {
-    "theme": "light",
-    "color": "#f5f5f5",
-    "background": "rgba(78, 139, 202, 0.2)",
-    "hover_color": "#f5f5f5",
-    "hover_background": "rgb(78, 139, 202)",
-})
diff --git a/tests/rustdoc/negative-impl-no-items.rs b/tests/rustdoc/negative-impl-no-items.rs
new file mode 100644
index 00000000000..c628e542033
--- /dev/null
+++ b/tests/rustdoc/negative-impl-no-items.rs
@@ -0,0 +1,26 @@
+// This test ensures that negative impls don't have items listed inside them.
+
+#![feature(negative_impls)]
+#![crate_name = "foo"]
+
+pub struct Thing;
+
+//@ has 'foo/struct.Thing.html'
+// We check the full path to ensure there is no `<details>` element.
+//@ has - '//div[@id="trait-implementations-list"]/section[@id="impl-Iterator-for-Thing"]/h3' \
+// 'impl !Iterator for Thing'
+impl !Iterator for Thing {}
+
+// This struct will allow us to compare both paths.
+pub struct Witness;
+
+//@ has 'foo/struct.Witness.html'
+//@ has - '//div[@id="trait-implementations-list"]/details//section[@id="impl-Iterator-for-Witness"]/h3' \
+// 'impl Iterator for Witness'
+impl Iterator for Witness {
+    type Item = u8;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        None
+    }
+}
diff --git a/tests/rustdoc/playground-arg.rs b/tests/rustdoc/playground-arg.rs
index 5875451a859..e10a31017ef 100644
--- a/tests/rustdoc/playground-arg.rs
+++ b/tests/rustdoc/playground-arg.rs
@@ -10,4 +10,4 @@
 pub fn dummy() {}
 
 // ensure that `extern crate foo;` was inserted into code snips automatically:
-//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0A%23%5Ballow(unused_extern_crates)%5D%0Aextern+crate+r%23foo;%0Afn+main()+%7B%0A++++use+foo::dummy;%0A++++dummy();%0A%7D&edition=2015"]' "Run"
+//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0A%23%5Ballow(unused_extern_crates)%5D%0Aextern+crate+r%23foo;%0Afn+main()+%7B%0A++++use+foo::dummy;%0A++++dummy();%0A%7D&edition=2015"]' ""
diff --git a/tests/rustdoc/playground-syntax-error.rs b/tests/rustdoc/playground-syntax-error.rs
index f5067145e02..d989570bf58 100644
--- a/tests/rustdoc/playground-syntax-error.rs
+++ b/tests/rustdoc/playground-syntax-error.rs
@@ -17,5 +17,5 @@
 pub fn bar() {}
 
 //@ has foo/fn.bar.html
-//@ has - '//a[@class="test-arrow"]' "Run"
+//@ has - '//a[@class="test-arrow"]' ""
 //@ has - '//*[@class="docblock"]' 'foo_recursive'
diff --git a/tests/rustdoc/playground.rs b/tests/rustdoc/playground.rs
index 7880f779067..db2d1669df6 100644
--- a/tests/rustdoc/playground.rs
+++ b/tests/rustdoc/playground.rs
@@ -22,6 +22,6 @@
 //! }
 //! ```
 
-//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run"
-//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run"
-//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&version=nightly&edition=2015"]' "Run"
+//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' ""
+//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' ""
+//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&version=nightly&edition=2015"]' ""
diff --git a/tests/ui/async-await/async-closures/box-deref-in-debuginfo.rs b/tests/ui/async-await/async-closures/box-deref-in-debuginfo.rs
new file mode 100644
index 00000000000..8b2de578b24
--- /dev/null
+++ b/tests/ui/async-await/async-closures/box-deref-in-debuginfo.rs
@@ -0,0 +1,35 @@
+//@ aux-build:block-on.rs
+//@ edition:2021
+//@ run-pass
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+pub trait Trait {
+    fn callback(&mut self);
+}
+impl Trait for (i32,) {
+    fn callback(&mut self) {
+        println!("hi {}", self.0);
+        self.0 += 1;
+    }
+}
+
+async fn call_once(f: impl async FnOnce()) {
+    f().await;
+}
+
+async fn run(mut loader: Box<dyn Trait>) {
+    let f = async move || {
+        loader.callback();
+        loader.callback();
+    };
+    call_once(f).await;
+}
+
+fn main() {
+    block_on::block_on(async {
+        run(Box::new((42,))).await;
+    });
+}
diff --git a/tests/ui/async-await/in-trait/generics-mismatch.rs b/tests/ui/async-await/in-trait/generics-mismatch.rs
index d3d1284982a..a5c81a92998 100644
--- a/tests/ui/async-await/in-trait/generics-mismatch.rs
+++ b/tests/ui/async-await/in-trait/generics-mismatch.rs
@@ -6,7 +6,7 @@ trait Foo {
 
 impl Foo for () {
     async fn foo<const N: usize>() {}
-    //~^ ERROR: method `foo` has an incompatible generic parameter for trait `Foo` [E0053]
+    //~^ ERROR: associated function `foo` has an incompatible generic parameter for trait `Foo` [E0053]
 }
 
 fn main() {}
diff --git a/tests/ui/async-await/in-trait/generics-mismatch.stderr b/tests/ui/async-await/in-trait/generics-mismatch.stderr
index c0357dc7f3e..cb0f95e8d09 100644
--- a/tests/ui/async-await/in-trait/generics-mismatch.stderr
+++ b/tests/ui/async-await/in-trait/generics-mismatch.stderr
@@ -1,4 +1,4 @@
-error[E0053]: method `foo` has an incompatible generic parameter for trait `Foo`
+error[E0053]: associated function `foo` has an incompatible generic parameter for trait `Foo`
   --> $DIR/generics-mismatch.rs:8:18
    |
 LL | trait Foo {
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/multivariant.rs b/tests/ui/closures/2229_closure_analysis/run_pass/multivariant.rs
index 52ed008137f..74f37b514e4 100644
--- a/tests/ui/closures/2229_closure_analysis/run_pass/multivariant.rs
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/multivariant.rs
@@ -1,10 +1,9 @@
 // Test precise capture of a multi-variant enum (when remaining variants are
 // visibly uninhabited).
-//@ revisions: min_exhaustive_patterns exhaustive_patterns
+//@ revisions: normal exhaustive_patterns
 //@ edition:2021
 //@ run-pass
 #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
-#![cfg_attr(min_exhaustive_patterns, feature(min_exhaustive_patterns))]
 #![feature(never_type)]
 
 pub fn main() {
diff --git a/tests/ui/codemap_tests/huge_multispan_highlight.svg b/tests/ui/codemap_tests/huge_multispan_highlight.svg
index 7b6dbb17c6f..12058176dc0 100644
--- a/tests/ui/codemap_tests/huge_multispan_highlight.svg
+++ b/tests/ui/codemap_tests/huge_multispan_highlight.svg
@@ -1,4 +1,4 @@
-<svg width="740px" height="848px" xmlns="http://www.w3.org/2000/svg">
+<svg width="818px" height="848px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
     .bg { background: #000000 }
diff --git a/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs b/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs
index 5c9323261a9..9eb33acbb24 100644
--- a/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs
+++ b/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs
@@ -3,7 +3,7 @@ trait Trait {
 }
 impl Trait for () {
     fn foo<const M: u64>() {}
-    //~^ error: method `foo` has an incompatible generic parameter for trait
+    //~^ error: associated function `foo` has an incompatible generic parameter for trait
 }
 
 trait Other {
@@ -11,7 +11,7 @@ trait Other {
 }
 impl Other for () {
     fn bar<T>() {}
-    //~^ error: method `bar` has an incompatible generic parameter for trait
+    //~^ error: associated function `bar` has an incompatible generic parameter for trait
 }
 
 trait Uwu {
@@ -19,7 +19,7 @@ trait Uwu {
 }
 impl Uwu for () {
     fn baz<const N: i32>() {}
-    //~^ error: method `baz` has an incompatible generic parameter for trait
+    //~^ error: associated function `baz` has an incompatible generic parameter for trait
 }
 
 trait Aaaaaa {
@@ -27,7 +27,7 @@ trait Aaaaaa {
 }
 impl Aaaaaa for () {
     fn bbbb<T, const N: u32>() {}
-    //~^ error: method `bbbb` has an incompatible generic parameter for trait
+    //~^ error: associated function `bbbb` has an incompatible generic parameter for trait
 }
 
 trait Names {
@@ -35,7 +35,7 @@ trait Names {
 }
 impl Names for () {
     fn abcd<const N: u32, T>() {}
-    //~^ error: method `abcd` has an incompatible generic parameter for trait
+    //~^ error: associated function `abcd` has an incompatible generic parameter for trait
 }
 
 fn main() {}
diff --git a/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr b/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr
index 3455f2c8ea9..7ec162e1c29 100644
--- a/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr
+++ b/tests/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr
@@ -1,4 +1,4 @@
-error[E0053]: method `foo` has an incompatible generic parameter for trait `Trait`
+error[E0053]: associated function `foo` has an incompatible generic parameter for trait `Trait`
   --> $DIR/mismatched_ty_const_in_trait_impl.rs:5:12
    |
 LL | trait Trait {
@@ -11,7 +11,7 @@ LL | impl Trait for () {
 LL |     fn foo<const M: u64>() {}
    |            ^^^^^^^^^^^^ found const parameter of type `u64`
 
-error[E0053]: method `bar` has an incompatible generic parameter for trait `Other`
+error[E0053]: associated function `bar` has an incompatible generic parameter for trait `Other`
   --> $DIR/mismatched_ty_const_in_trait_impl.rs:13:12
    |
 LL | trait Other {
@@ -24,7 +24,7 @@ LL | impl Other for () {
 LL |     fn bar<T>() {}
    |            ^ found type parameter
 
-error[E0053]: method `baz` has an incompatible generic parameter for trait `Uwu`
+error[E0053]: associated function `baz` has an incompatible generic parameter for trait `Uwu`
   --> $DIR/mismatched_ty_const_in_trait_impl.rs:21:12
    |
 LL | trait Uwu {
@@ -37,7 +37,7 @@ LL | impl Uwu for () {
 LL |     fn baz<const N: i32>() {}
    |            ^^^^^^^^^^^^ found const parameter of type `i32`
 
-error[E0053]: method `bbbb` has an incompatible generic parameter for trait `Aaaaaa`
+error[E0053]: associated function `bbbb` has an incompatible generic parameter for trait `Aaaaaa`
   --> $DIR/mismatched_ty_const_in_trait_impl.rs:29:13
    |
 LL | trait Aaaaaa {
@@ -50,7 +50,7 @@ LL | impl Aaaaaa for () {
 LL |     fn bbbb<T, const N: u32>() {}
    |             ^ found type parameter
 
-error[E0053]: method `abcd` has an incompatible generic parameter for trait `Names`
+error[E0053]: associated function `abcd` has an incompatible generic parameter for trait `Names`
   --> $DIR/mismatched_ty_const_in_trait_impl.rs:37:13
    |
 LL | trait Names {
diff --git a/tests/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs b/tests/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs
index 5628ae1be36..f4130319eea 100644
--- a/tests/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs
+++ b/tests/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs
@@ -1,8 +1,8 @@
 //@ run-pass
-
+#![allow(unreachable_patterns)]
 #![allow(dead_code)]
 
-enum Empty { }
+enum Empty {}
 enum Test1 {
     A(u8),
     B(Empty),
diff --git a/tests/ui/coroutine/gen_block.none.stderr b/tests/ui/coroutine/gen_block.none.stderr
index 64fa2be003d..15123a49e48 100644
--- a/tests/ui/coroutine/gen_block.none.stderr
+++ b/tests/ui/coroutine/gen_block.none.stderr
@@ -73,7 +73,6 @@ LL |     let _ = || yield true;
    = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
    = help: add `#![feature(coroutines)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
   --> $DIR/gen_block.rs:16:16
@@ -95,7 +94,6 @@ LL |     let _ = #[coroutine] || yield true;
    = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
    = help: add `#![feature(coroutines)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 11 previous errors
 
diff --git a/tests/ui/delegation/not-supported.rs b/tests/ui/delegation/not-supported.rs
index 5701cc6055d..d5ac68ecf1b 100644
--- a/tests/ui/delegation/not-supported.rs
+++ b/tests/ui/delegation/not-supported.rs
@@ -53,7 +53,7 @@ mod generics {
         //~| ERROR method `foo2` has 0 type parameters but its trait declaration has 1 type parameter
         reuse <F as Trait>::foo3;
         //~^ ERROR early bound generics are not supported for associated delegation items
-        //~| ERROR lifetime parameters or bounds on method `foo3` do not match the trait declaration
+        //~| ERROR lifetime parameters or bounds on associated function `foo3` do not match the trait declaration
     }
 
     struct GenericS<T>(T);
diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr
index e7ba9fc6719..14d6b374bd2 100644
--- a/tests/ui/delegation/not-supported.stderr
+++ b/tests/ui/delegation/not-supported.stderr
@@ -84,14 +84,14 @@ LL |         fn foo3<'a: 'a>(_: &'a u32) {}
 LL |         reuse <F as Trait>::foo3;
    |                             ^^^^
 
-error[E0195]: lifetime parameters or bounds on method `foo3` do not match the trait declaration
+error[E0195]: lifetime parameters or bounds on associated function `foo3` do not match the trait declaration
   --> $DIR/not-supported.rs:54:29
    |
 LL |         fn foo3<'a: 'a>(_: &'a u32) {}
-   |                -------- lifetimes in impl do not match this method in trait
+   |                -------- lifetimes in impl do not match this associated function in trait
 ...
 LL |         reuse <F as Trait>::foo3;
-   |                             ^^^^ lifetimes do not match method in trait
+   |                             ^^^^ lifetimes do not match associated function in trait
 
 error: delegation to a function with effect parameter is not supported yet
   --> $DIR/not-supported.rs:112:18
diff --git a/tests/ui/enum-discriminant/issue-61696.rs b/tests/ui/enum-discriminant/issue-61696.rs
index d200b4410ff..e93fd0e07f6 100644
--- a/tests/ui/enum-discriminant/issue-61696.rs
+++ b/tests/ui/enum-discriminant/issue-61696.rs
@@ -1,4 +1,5 @@
 //@ run-pass
+#![allow(unreachable_patterns)]
 
 pub enum Infallible {}
 
diff --git a/tests/ui/enum-discriminant/niche.rs b/tests/ui/enum-discriminant/niche.rs
index 15d227fd826..f9c4a135a6f 100644
--- a/tests/ui/enum-discriminant/niche.rs
+++ b/tests/ui/enum-discriminant/niche.rs
@@ -1,4 +1,5 @@
 //@ run-pass
+#![allow(unreachable_patterns)]
 
 //! Make sure that we read and write enum discriminants correctly for corner cases caused
 //! by layout optimizations.
diff --git a/tests/ui/error-codes/E0049.stderr b/tests/ui/error-codes/E0049.stderr
index c0cd31faa90..83a30aa0a78 100644
--- a/tests/ui/error-codes/E0049.stderr
+++ b/tests/ui/error-codes/E0049.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `foo` has 0 type parameters but its trait declaration has 1 type parameter
+error[E0049]: associated function `foo` has 0 type parameters but its trait declaration has 1 type parameter
   --> $DIR/E0049.rs:8:11
    |
 LL |     fn foo<T: Default>(x: T) -> Self;
@@ -7,7 +7,7 @@ LL |     fn foo<T: Default>(x: T) -> Self;
 LL |     fn foo(x: bool) -> Self { Bar }
    |           ^ found 0 type parameters
 
-error[E0049]: method `fuzz` has 0 type parameters but its trait declaration has 2 type parameters
+error[E0049]: associated function `fuzz` has 0 type parameters but its trait declaration has 2 type parameters
   --> $DIR/E0049.rs:18:12
    |
 LL |     fn fuzz<A: Default, B>(x: A, y: B) -> Self;
diff --git a/tests/ui/error-codes/E0195.rs b/tests/ui/error-codes/E0195.rs
index f712ee42b8c..a7e51dff2f3 100644
--- a/tests/ui/error-codes/E0195.rs
+++ b/tests/ui/error-codes/E0195.rs
@@ -1,13 +1,13 @@
 trait Trait {
     fn bar<'a,'b:'a>(x: &'a str, y: &'b str);
-    //~^ NOTE lifetimes in impl do not match this method in trait
+    //~^ NOTE lifetimes in impl do not match this associated function in trait
 }
 
 struct Foo;
 
 impl Trait for Foo {
     fn bar<'a,'b>(x: &'a str, y: &'b str) { //~ ERROR E0195
-    //~^ NOTE lifetimes do not match method in trait
+    //~^ NOTE lifetimes do not match associated function in trait
     }
 }
 
diff --git a/tests/ui/error-codes/E0195.stderr b/tests/ui/error-codes/E0195.stderr
index b88064b7f90..9767dee9aec 100644
--- a/tests/ui/error-codes/E0195.stderr
+++ b/tests/ui/error-codes/E0195.stderr
@@ -1,11 +1,11 @@
-error[E0195]: lifetime parameters or bounds on method `bar` do not match the trait declaration
+error[E0195]: lifetime parameters or bounds on associated function `bar` do not match the trait declaration
   --> $DIR/E0195.rs:9:11
    |
 LL |     fn bar<'a,'b:'a>(x: &'a str, y: &'b str);
-   |           ---------- lifetimes in impl do not match this method in trait
+   |           ---------- lifetimes in impl do not match this associated function in trait
 ...
 LL |     fn bar<'a,'b>(x: &'a str, y: &'b str) {
-   |           ^^^^^^^ lifetimes do not match method in trait
+   |           ^^^^^^^ lifetimes do not match associated function in trait
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/feature-gates/feature-gate-coroutines.none.stderr b/tests/ui/feature-gates/feature-gate-coroutines.none.stderr
index 65e7737ef84..032d7adf77a 100644
--- a/tests/ui/feature-gates/feature-gate-coroutines.none.stderr
+++ b/tests/ui/feature-gates/feature-gate-coroutines.none.stderr
@@ -47,7 +47,6 @@ LL |     yield true;
    = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
    = help: add `#![feature(coroutines)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
   --> $DIR/feature-gate-coroutines.rs:5:5
@@ -69,7 +68,6 @@ LL |     let _ = || yield true;
    = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
    = help: add `#![feature(coroutines)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
   --> $DIR/feature-gate-coroutines.rs:10:16
diff --git a/tests/ui/feature-gates/feature-gate-exhaustive-patterns.rs b/tests/ui/feature-gates/feature-gate-exhaustive-patterns.rs
index f0cc9ea7055..79891593692 100644
--- a/tests/ui/feature-gates/feature-gate-exhaustive-patterns.rs
+++ b/tests/ui/feature-gates/feature-gate-exhaustive-patterns.rs
@@ -5,5 +5,5 @@ fn foo() -> Result<u32, !> {
 }
 
 fn main() {
-    let Ok(_x) = foo(); //~ ERROR refutable pattern in local binding
+    let Ok(_x) = &foo(); //~ ERROR refutable pattern in local binding
 }
diff --git a/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr b/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
index d34f257c8d9..4836ffe1723 100644
--- a/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
+++ b/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
@@ -1,16 +1,16 @@
 error[E0005]: refutable pattern in local binding
   --> $DIR/feature-gate-exhaustive-patterns.rs:8:9
    |
-LL |     let Ok(_x) = foo();
-   |         ^^^^^^ pattern `Err(_)` not covered
+LL |     let Ok(_x) = &foo();
+   |         ^^^^^^ pattern `&Err(_)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-   = note: the matched value is of type `Result<u32, !>`
+   = note: the matched value is of type `&Result<u32, !>`
 help: you might want to use `let else` to handle the variant that isn't matched
    |
-LL |     let Ok(_x) = foo() else { todo!() };
-   |                        ++++++++++++++++
+LL |     let Ok(_x) = &foo() else { todo!() };
+   |                         ++++++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs b/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs
index 285493132b6..946cb1a62b7 100644
--- a/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs
+++ b/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs
@@ -8,7 +8,7 @@ impl<T> X for T { //~ ERROR: not all trait items implemented
   fn foo<'a, T1: X<Y = T1>>(t : T1) -> T1::Y<'a> {
     //~^ ERROR missing generics for associated type
     //~^^ ERROR missing generics for associated type
-    //~| ERROR method `foo` has 1 type parameter but its trait declaration has 0 type parameters
+    //~| ERROR associated function `foo` has 1 type parameter but its trait declaration has 0 type parameters
     t
   }
 }
diff --git a/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr b/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr
index 6a600aee11f..72c2bdc72a2 100644
--- a/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr
+++ b/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters
+error[E0049]: associated function `foo` has 1 type parameter but its trait declaration has 0 type parameters
   --> $DIR/gat-trait-path-missing-lifetime.rs:8:10
    |
 LL |   fn foo<'a>(t : Self::Y<'a>) -> Self::Y<'a> { t }
diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs
index d9fac0238e1..0477de3315a 100644
--- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs
+++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs
@@ -6,7 +6,7 @@ trait Foo {
 
 impl Foo for S {
     fn bar() -> impl Sized {}
-    //~^ ERROR method `bar` has 0 type parameters but its trait declaration has 1 type parameter
+    //~^ ERROR associated function `bar` has 0 type parameters but its trait declaration has 1 type parameter
 }
 
 fn main() {
diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr
index eed4c07710e..ca67db40362 100644
--- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr
+++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `bar` has 0 type parameters but its trait declaration has 1 type parameter
+error[E0049]: associated function `bar` has 0 type parameters but its trait declaration has 1 type parameter
   --> $DIR/trait-more-generics-than-impl.rs:8:11
    |
 LL |     fn bar<T>() -> impl Sized;
diff --git a/tests/ui/never_type/never-result.rs b/tests/ui/never_type/never-result.rs
index bdd06ec5bd1..98ad1404666 100644
--- a/tests/ui/never_type/never-result.rs
+++ b/tests/ui/never_type/never-result.rs
@@ -2,9 +2,8 @@
 
 #![allow(unused_variables)]
 #![allow(unreachable_code)]
-
+#![allow(unreachable_patterns)]
 // Test that we can extract a ! through pattern matching then use it as several different types.
-
 #![feature(never_type)]
 
 fn main() {
@@ -16,6 +15,6 @@ fn main() {
             let w: i32 = y;
             let e: String = y;
             y
-        },
+        }
     }
 }
diff --git a/tests/ui/pattern/usefulness/always-inhabited-union-ref.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/always-inhabited-union-ref.exhaustive_patterns.stderr
index d6304a0b997..bc74069b3e7 100644
--- a/tests/ui/pattern/usefulness/always-inhabited-union-ref.exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/always-inhabited-union-ref.exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `&!` is non-empty
-  --> $DIR/always-inhabited-union-ref.rs:25:11
+  --> $DIR/always-inhabited-union-ref.rs:24:11
    |
 LL |     match uninhab_ref() {
    |           ^^^^^^^^^^^^^
@@ -14,13 +14,13 @@ LL +     }
    |
 
 error[E0004]: non-exhaustive patterns: type `Foo` is non-empty
-  --> $DIR/always-inhabited-union-ref.rs:29:11
+  --> $DIR/always-inhabited-union-ref.rs:28:11
    |
 LL |     match uninhab_union() {
    |           ^^^^^^^^^^^^^^^
    |
 note: `Foo` defined here
-  --> $DIR/always-inhabited-union-ref.rs:12:11
+  --> $DIR/always-inhabited-union-ref.rs:11:11
    |
 LL | pub union Foo {
    |           ^^^
diff --git a/tests/ui/pattern/usefulness/always-inhabited-union-ref.min_exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/always-inhabited-union-ref.normal.stderr
index d6304a0b997..bc74069b3e7 100644
--- a/tests/ui/pattern/usefulness/always-inhabited-union-ref.min_exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/always-inhabited-union-ref.normal.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `&!` is non-empty
-  --> $DIR/always-inhabited-union-ref.rs:25:11
+  --> $DIR/always-inhabited-union-ref.rs:24:11
    |
 LL |     match uninhab_ref() {
    |           ^^^^^^^^^^^^^
@@ -14,13 +14,13 @@ LL +     }
    |
 
 error[E0004]: non-exhaustive patterns: type `Foo` is non-empty
-  --> $DIR/always-inhabited-union-ref.rs:29:11
+  --> $DIR/always-inhabited-union-ref.rs:28:11
    |
 LL |     match uninhab_union() {
    |           ^^^^^^^^^^^^^^^
    |
 note: `Foo` defined here
-  --> $DIR/always-inhabited-union-ref.rs:12:11
+  --> $DIR/always-inhabited-union-ref.rs:11:11
    |
 LL | pub union Foo {
    |           ^^^
diff --git a/tests/ui/pattern/usefulness/always-inhabited-union-ref.rs b/tests/ui/pattern/usefulness/always-inhabited-union-ref.rs
index 5088098d0ae..335eff425ab 100644
--- a/tests/ui/pattern/usefulness/always-inhabited-union-ref.rs
+++ b/tests/ui/pattern/usefulness/always-inhabited-union-ref.rs
@@ -1,10 +1,9 @@
-//@ revisions: min_exhaustive_patterns exhaustive_patterns
+//@ revisions: normal exhaustive_patterns
 
 // The precise semantics of inhabitedness with respect to unions and references is currently
 // undecided. This test file currently checks a conservative choice.
 
 #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
-#![cfg_attr(min_exhaustive_patterns, feature(min_exhaustive_patterns))]
 #![feature(never_type)]
 #![allow(dead_code)]
 #![allow(unreachable_code)]
diff --git a/tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr
index 9e700ee55ef..1b65ff7aa57 100644
--- a/tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr
@@ -38,7 +38,7 @@ LL |         _ if false => {}
 error[E0005]: refutable pattern in local binding
   --> $DIR/empty-match-check-notes.rs:39:9
    |
-LL |     let None = x;
+LL |     let None = *x;
    |         ^^^^ pattern `Some(_)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
@@ -47,8 +47,8 @@ LL |     let None = x;
    = note: the matched value is of type `Option<SecretlyUninhabitedForeignStruct>`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let None = x { todo!() };
-   |     ++              +++++++++++
+LL |     if let None = *x { todo!() };
+   |     ++               +++++++++++
 
 error[E0004]: non-exhaustive patterns: `0_u8..=u8::MAX` not covered
   --> $DIR/empty-match-check-notes.rs:49:11
diff --git a/tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr b/tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr
index 480ae7095a6..1b65ff7aa57 100644
--- a/tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr
+++ b/tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr
@@ -38,16 +38,17 @@ LL |         _ if false => {}
 error[E0005]: refutable pattern in local binding
   --> $DIR/empty-match-check-notes.rs:39:9
    |
-LL |     let None = x;
+LL |     let None = *x;
    |         ^^^^ pattern `Some(_)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+   = note: pattern `Some(_)` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
    = note: the matched value is of type `Option<SecretlyUninhabitedForeignStruct>`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let None = x { todo!() };
-   |     ++              +++++++++++
+LL |     if let None = *x { todo!() };
+   |     ++               +++++++++++
 
 error[E0004]: non-exhaustive patterns: `0_u8..=u8::MAX` not covered
   --> $DIR/empty-match-check-notes.rs:49:11
diff --git a/tests/ui/pattern/usefulness/empty-match-check-notes.rs b/tests/ui/pattern/usefulness/empty-match-check-notes.rs
index 2eef283a21e..61a75e6c801 100644
--- a/tests/ui/pattern/usefulness/empty-match-check-notes.rs
+++ b/tests/ui/pattern/usefulness/empty-match-check-notes.rs
@@ -35,14 +35,14 @@ fn empty_foreign_enum(x: empty::EmptyForeignEnum) {
     }
 }
 
-fn empty_foreign_enum_private(x: Option<empty::SecretlyUninhabitedForeignStruct>) {
-    let None = x;
+fn empty_foreign_enum_private(x: &Option<empty::SecretlyUninhabitedForeignStruct>) {
+    let None = *x;
     //~^ ERROR refutable pattern in local binding
     //~| NOTE `let` bindings require an "irrefutable pattern"
     //~| NOTE for more information, visit
     //~| NOTE the matched value is of type
     //~| NOTE pattern `Some(_)` not covered
-    //[exhaustive_patterns]~| NOTE currently uninhabited, but this variant contains private fields
+    //~| NOTE currently uninhabited, but this variant contains private fields
 }
 
 fn main() {
diff --git a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
index 5f895fab0fb..f2067f0341f 100644
--- a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `u8` is non-empty
-  --> $DIR/empty-match.rs:46:20
+  --> $DIR/empty-match.rs:47:20
    |
 LL |     match_no_arms!(0u8);
    |                    ^^^
@@ -8,7 +8,7 @@ LL |     match_no_arms!(0u8);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `i8` is non-empty
-  --> $DIR/empty-match.rs:47:20
+  --> $DIR/empty-match.rs:48:20
    |
 LL |     match_no_arms!(0i8);
    |                    ^^^
@@ -17,7 +17,7 @@ LL |     match_no_arms!(0i8);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `usize` is non-empty
-  --> $DIR/empty-match.rs:48:20
+  --> $DIR/empty-match.rs:49:20
    |
 LL |     match_no_arms!(0usize);
    |                    ^^^^^^
@@ -26,7 +26,7 @@ LL |     match_no_arms!(0usize);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `isize` is non-empty
-  --> $DIR/empty-match.rs:49:20
+  --> $DIR/empty-match.rs:50:20
    |
 LL |     match_no_arms!(0isize);
    |                    ^^^^^^
@@ -35,7 +35,7 @@ LL |     match_no_arms!(0isize);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
-  --> $DIR/empty-match.rs:50:20
+  --> $DIR/empty-match.rs:51:20
    |
 LL |     match_no_arms!(NonEmptyStruct1);
    |                    ^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL |     struct NonEmptyStruct1;
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
-  --> $DIR/empty-match.rs:51:20
+  --> $DIR/empty-match.rs:52:20
    |
 LL |     match_no_arms!(NonEmptyStruct2(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^
@@ -63,7 +63,7 @@ LL |     struct NonEmptyStruct2(bool);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
-  --> $DIR/empty-match.rs:52:20
+  --> $DIR/empty-match.rs:53:20
    |
 LL |     match_no_arms!((NonEmptyUnion1 { foo: () }));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@ LL |     union NonEmptyUnion1 {
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
-  --> $DIR/empty-match.rs:53:20
+  --> $DIR/empty-match.rs:54:20
    |
 LL |     match_no_arms!((NonEmptyUnion2 { foo: () }));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -91,7 +91,7 @@ LL |     union NonEmptyUnion2 {
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
-  --> $DIR/empty-match.rs:54:20
+  --> $DIR/empty-match.rs:55:20
    |
 LL |     match_no_arms!(NonEmptyEnum1::Foo(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
@@ -107,7 +107,7 @@ LL |         Foo(bool),
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
-  --> $DIR/empty-match.rs:55:20
+  --> $DIR/empty-match.rs:56:20
    |
 LL |     match_no_arms!(NonEmptyEnum2::Foo(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
@@ -125,7 +125,7 @@ LL |         Bar,
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
-  --> $DIR/empty-match.rs:56:20
+  --> $DIR/empty-match.rs:57:20
    |
 LL |     match_no_arms!(NonEmptyEnum5::V1);
    |                    ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
@@ -148,8 +148,26 @@ LL |         V5,
    = note: the matched value is of type `NonEmptyEnum5`
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
+error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty
+  --> $DIR/empty-match.rs:58:20
+   |
+LL |     match_no_arms!(array0_of_empty);
+   |                    ^^^^^^^^^^^^^^^
+   |
+   = note: the matched value is of type `[!; 0]`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+error[E0004]: non-exhaustive patterns: type `[!; N]` is non-empty
+  --> $DIR/empty-match.rs:59:20
+   |
+LL |     match_no_arms!(arrayN_of_empty);
+   |                    ^^^^^^^^^^^^^^^
+   |
+   = note: the matched value is of type `[!; N]`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
 error[E0004]: non-exhaustive patterns: `0_u8..=u8::MAX` not covered
-  --> $DIR/empty-match.rs:58:24
+  --> $DIR/empty-match.rs:61:24
    |
 LL |     match_guarded_arm!(0u8);
    |                        ^^^ pattern `0_u8..=u8::MAX` not covered
@@ -163,7 +181,7 @@ LL +                 0_u8..=u8::MAX => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `i8::MIN..=i8::MAX` not covered
-  --> $DIR/empty-match.rs:59:24
+  --> $DIR/empty-match.rs:62:24
    |
 LL |     match_guarded_arm!(0i8);
    |                        ^^^ pattern `i8::MIN..=i8::MAX` not covered
@@ -177,7 +195,7 @@ LL +                 i8::MIN..=i8::MAX => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `0_usize..` not covered
-  --> $DIR/empty-match.rs:60:24
+  --> $DIR/empty-match.rs:63:24
    |
 LL |     match_guarded_arm!(0usize);
    |                        ^^^^^^ pattern `0_usize..` not covered
@@ -191,7 +209,7 @@ LL +                 0_usize.. => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/empty-match.rs:61:24
+  --> $DIR/empty-match.rs:64:24
    |
 LL |     match_guarded_arm!(0isize);
    |                        ^^^^^^ pattern `_` not covered
@@ -205,7 +223,7 @@ LL +                 _ => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
-  --> $DIR/empty-match.rs:62:24
+  --> $DIR/empty-match.rs:65:24
    |
 LL |     match_guarded_arm!(NonEmptyStruct1);
    |                        ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
@@ -224,7 +242,7 @@ LL +                 NonEmptyStruct1 => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
-  --> $DIR/empty-match.rs:63:24
+  --> $DIR/empty-match.rs:66:24
    |
 LL |     match_guarded_arm!(NonEmptyStruct2(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
@@ -243,7 +261,7 @@ LL +                 NonEmptyStruct2(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
-  --> $DIR/empty-match.rs:64:24
+  --> $DIR/empty-match.rs:67:24
    |
 LL |     match_guarded_arm!((NonEmptyUnion1 { foo: () }));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
@@ -262,7 +280,7 @@ LL +                 NonEmptyUnion1 { .. } => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
-  --> $DIR/empty-match.rs:65:24
+  --> $DIR/empty-match.rs:68:24
    |
 LL |     match_guarded_arm!((NonEmptyUnion2 { foo: () }));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
@@ -273,6 +291,7 @@ note: `NonEmptyUnion2` defined here
 LL |     union NonEmptyUnion2 {
    |           ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion2`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
    = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
@@ -281,7 +300,7 @@ LL +                 NonEmptyUnion2 { .. } => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
-  --> $DIR/empty-match.rs:66:24
+  --> $DIR/empty-match.rs:69:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum1::Foo(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
@@ -302,7 +321,7 @@ LL +                 NonEmptyEnum1::Foo(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
-  --> $DIR/empty-match.rs:67:24
+  --> $DIR/empty-match.rs:70:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum2::Foo(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
@@ -325,7 +344,7 @@ LL +                 NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
-  --> $DIR/empty-match.rs:68:24
+  --> $DIR/empty-match.rs:71:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum5::V1);
    |                        ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
@@ -353,6 +372,34 @@ LL ~                 _ if false => {},
 LL +                 _ => todo!()
    |
 
-error: aborting due to 22 previous errors
+error[E0004]: non-exhaustive patterns: `[]` not covered
+  --> $DIR/empty-match.rs:72:24
+   |
+LL |     match_guarded_arm!(array0_of_empty);
+   |                        ^^^^^^^^^^^^^^^ pattern `[]` not covered
+   |
+   = note: the matched value is of type `[!; 0]`
+   = note: match arms with guards don't count towards exhaustivity
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~                 _ if false => {},
+LL +                 [] => todo!()
+   |
+
+error[E0004]: non-exhaustive patterns: `[]` not covered
+  --> $DIR/empty-match.rs:73:24
+   |
+LL |     match_guarded_arm!(arrayN_of_empty);
+   |                        ^^^^^^^^^^^^^^^ pattern `[]` not covered
+   |
+   = note: the matched value is of type `[!; N]`
+   = note: match arms with guards don't count towards exhaustivity
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~                 _ if false => {},
+LL +                 [] => todo!()
+   |
+
+error: aborting due to 26 previous errors
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-match.normal.stderr b/tests/ui/pattern/usefulness/empty-match.normal.stderr
index 5f895fab0fb..f2067f0341f 100644
--- a/tests/ui/pattern/usefulness/empty-match.normal.stderr
+++ b/tests/ui/pattern/usefulness/empty-match.normal.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `u8` is non-empty
-  --> $DIR/empty-match.rs:46:20
+  --> $DIR/empty-match.rs:47:20
    |
 LL |     match_no_arms!(0u8);
    |                    ^^^
@@ -8,7 +8,7 @@ LL |     match_no_arms!(0u8);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `i8` is non-empty
-  --> $DIR/empty-match.rs:47:20
+  --> $DIR/empty-match.rs:48:20
    |
 LL |     match_no_arms!(0i8);
    |                    ^^^
@@ -17,7 +17,7 @@ LL |     match_no_arms!(0i8);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `usize` is non-empty
-  --> $DIR/empty-match.rs:48:20
+  --> $DIR/empty-match.rs:49:20
    |
 LL |     match_no_arms!(0usize);
    |                    ^^^^^^
@@ -26,7 +26,7 @@ LL |     match_no_arms!(0usize);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `isize` is non-empty
-  --> $DIR/empty-match.rs:49:20
+  --> $DIR/empty-match.rs:50:20
    |
 LL |     match_no_arms!(0isize);
    |                    ^^^^^^
@@ -35,7 +35,7 @@ LL |     match_no_arms!(0isize);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
-  --> $DIR/empty-match.rs:50:20
+  --> $DIR/empty-match.rs:51:20
    |
 LL |     match_no_arms!(NonEmptyStruct1);
    |                    ^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL |     struct NonEmptyStruct1;
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
-  --> $DIR/empty-match.rs:51:20
+  --> $DIR/empty-match.rs:52:20
    |
 LL |     match_no_arms!(NonEmptyStruct2(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^
@@ -63,7 +63,7 @@ LL |     struct NonEmptyStruct2(bool);
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
-  --> $DIR/empty-match.rs:52:20
+  --> $DIR/empty-match.rs:53:20
    |
 LL |     match_no_arms!((NonEmptyUnion1 { foo: () }));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@ LL |     union NonEmptyUnion1 {
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
-  --> $DIR/empty-match.rs:53:20
+  --> $DIR/empty-match.rs:54:20
    |
 LL |     match_no_arms!((NonEmptyUnion2 { foo: () }));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -91,7 +91,7 @@ LL |     union NonEmptyUnion2 {
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
-  --> $DIR/empty-match.rs:54:20
+  --> $DIR/empty-match.rs:55:20
    |
 LL |     match_no_arms!(NonEmptyEnum1::Foo(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
@@ -107,7 +107,7 @@ LL |         Foo(bool),
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
-  --> $DIR/empty-match.rs:55:20
+  --> $DIR/empty-match.rs:56:20
    |
 LL |     match_no_arms!(NonEmptyEnum2::Foo(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
@@ -125,7 +125,7 @@ LL |         Bar,
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
-  --> $DIR/empty-match.rs:56:20
+  --> $DIR/empty-match.rs:57:20
    |
 LL |     match_no_arms!(NonEmptyEnum5::V1);
    |                    ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
@@ -148,8 +148,26 @@ LL |         V5,
    = note: the matched value is of type `NonEmptyEnum5`
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
+error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty
+  --> $DIR/empty-match.rs:58:20
+   |
+LL |     match_no_arms!(array0_of_empty);
+   |                    ^^^^^^^^^^^^^^^
+   |
+   = note: the matched value is of type `[!; 0]`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+error[E0004]: non-exhaustive patterns: type `[!; N]` is non-empty
+  --> $DIR/empty-match.rs:59:20
+   |
+LL |     match_no_arms!(arrayN_of_empty);
+   |                    ^^^^^^^^^^^^^^^
+   |
+   = note: the matched value is of type `[!; N]`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
 error[E0004]: non-exhaustive patterns: `0_u8..=u8::MAX` not covered
-  --> $DIR/empty-match.rs:58:24
+  --> $DIR/empty-match.rs:61:24
    |
 LL |     match_guarded_arm!(0u8);
    |                        ^^^ pattern `0_u8..=u8::MAX` not covered
@@ -163,7 +181,7 @@ LL +                 0_u8..=u8::MAX => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `i8::MIN..=i8::MAX` not covered
-  --> $DIR/empty-match.rs:59:24
+  --> $DIR/empty-match.rs:62:24
    |
 LL |     match_guarded_arm!(0i8);
    |                        ^^^ pattern `i8::MIN..=i8::MAX` not covered
@@ -177,7 +195,7 @@ LL +                 i8::MIN..=i8::MAX => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `0_usize..` not covered
-  --> $DIR/empty-match.rs:60:24
+  --> $DIR/empty-match.rs:63:24
    |
 LL |     match_guarded_arm!(0usize);
    |                        ^^^^^^ pattern `0_usize..` not covered
@@ -191,7 +209,7 @@ LL +                 0_usize.. => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/empty-match.rs:61:24
+  --> $DIR/empty-match.rs:64:24
    |
 LL |     match_guarded_arm!(0isize);
    |                        ^^^^^^ pattern `_` not covered
@@ -205,7 +223,7 @@ LL +                 _ => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
-  --> $DIR/empty-match.rs:62:24
+  --> $DIR/empty-match.rs:65:24
    |
 LL |     match_guarded_arm!(NonEmptyStruct1);
    |                        ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
@@ -224,7 +242,7 @@ LL +                 NonEmptyStruct1 => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
-  --> $DIR/empty-match.rs:63:24
+  --> $DIR/empty-match.rs:66:24
    |
 LL |     match_guarded_arm!(NonEmptyStruct2(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
@@ -243,7 +261,7 @@ LL +                 NonEmptyStruct2(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
-  --> $DIR/empty-match.rs:64:24
+  --> $DIR/empty-match.rs:67:24
    |
 LL |     match_guarded_arm!((NonEmptyUnion1 { foo: () }));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
@@ -262,7 +280,7 @@ LL +                 NonEmptyUnion1 { .. } => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
-  --> $DIR/empty-match.rs:65:24
+  --> $DIR/empty-match.rs:68:24
    |
 LL |     match_guarded_arm!((NonEmptyUnion2 { foo: () }));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
@@ -273,6 +291,7 @@ note: `NonEmptyUnion2` defined here
 LL |     union NonEmptyUnion2 {
    |           ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion2`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
    = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
@@ -281,7 +300,7 @@ LL +                 NonEmptyUnion2 { .. } => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
-  --> $DIR/empty-match.rs:66:24
+  --> $DIR/empty-match.rs:69:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum1::Foo(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
@@ -302,7 +321,7 @@ LL +                 NonEmptyEnum1::Foo(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
-  --> $DIR/empty-match.rs:67:24
+  --> $DIR/empty-match.rs:70:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum2::Foo(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
@@ -325,7 +344,7 @@ LL +                 NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
-  --> $DIR/empty-match.rs:68:24
+  --> $DIR/empty-match.rs:71:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum5::V1);
    |                        ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
@@ -353,6 +372,34 @@ LL ~                 _ if false => {},
 LL +                 _ => todo!()
    |
 
-error: aborting due to 22 previous errors
+error[E0004]: non-exhaustive patterns: `[]` not covered
+  --> $DIR/empty-match.rs:72:24
+   |
+LL |     match_guarded_arm!(array0_of_empty);
+   |                        ^^^^^^^^^^^^^^^ pattern `[]` not covered
+   |
+   = note: the matched value is of type `[!; 0]`
+   = note: match arms with guards don't count towards exhaustivity
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~                 _ if false => {},
+LL +                 [] => todo!()
+   |
+
+error[E0004]: non-exhaustive patterns: `[]` not covered
+  --> $DIR/empty-match.rs:73:24
+   |
+LL |     match_guarded_arm!(arrayN_of_empty);
+   |                        ^^^^^^^^^^^^^^^ pattern `[]` not covered
+   |
+   = note: the matched value is of type `[!; N]`
+   = note: match arms with guards don't count towards exhaustivity
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~                 _ if false => {},
+LL +                 [] => todo!()
+   |
+
+error: aborting due to 26 previous errors
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-match.rs b/tests/ui/pattern/usefulness/empty-match.rs
index 9b22b47a12b..b34427a7c23 100644
--- a/tests/ui/pattern/usefulness/empty-match.rs
+++ b/tests/ui/pattern/usefulness/empty-match.rs
@@ -5,7 +5,7 @@
 #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
 #![deny(unreachable_patterns)]
 
-fn nonempty() {
+fn nonempty<const N: usize>(arrayN_of_empty: [!; N]) {
     macro_rules! match_no_arms {
         ($e:expr) => {
             match $e {}
@@ -42,6 +42,7 @@ fn nonempty() {
         V4,
         V5,
     }
+    let array0_of_empty: [!; 0] = [];
 
     match_no_arms!(0u8); //~ ERROR type `u8` is non-empty
     match_no_arms!(0i8); //~ ERROR type `i8` is non-empty
@@ -54,6 +55,8 @@ fn nonempty() {
     match_no_arms!(NonEmptyEnum1::Foo(true)); //~ ERROR `NonEmptyEnum1::Foo(_)` not covered
     match_no_arms!(NonEmptyEnum2::Foo(true)); //~ ERROR `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
     match_no_arms!(NonEmptyEnum5::V1); //~ ERROR `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
+    match_no_arms!(array0_of_empty); //~ ERROR type `[!; 0]` is non-empty
+    match_no_arms!(arrayN_of_empty); //~ ERROR type `[!; N]` is non-empty
 
     match_guarded_arm!(0u8); //~ ERROR `0_u8..=u8::MAX` not covered
     match_guarded_arm!(0i8); //~ ERROR `i8::MIN..=i8::MAX` not covered
@@ -66,6 +69,8 @@ fn nonempty() {
     match_guarded_arm!(NonEmptyEnum1::Foo(true)); //~ ERROR `NonEmptyEnum1::Foo(_)` not covered
     match_guarded_arm!(NonEmptyEnum2::Foo(true)); //~ ERROR `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
     match_guarded_arm!(NonEmptyEnum5::V1); //~ ERROR `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
+    match_guarded_arm!(array0_of_empty); //~ ERROR `[]` not covered
+    match_guarded_arm!(arrayN_of_empty); //~ ERROR `[]` not covered
 }
 
 fn main() {}
diff --git a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr
index 416a50b87b5..17cb6fbd94b 100644
--- a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr
@@ -1,18 +1,18 @@
 error: unreachable pattern
-  --> $DIR/empty-types.rs:51:9
+  --> $DIR/empty-types.rs:49:9
    |
 LL |         _ => {}
    |         ^
    |
    = note: this pattern matches no values because `!` is uninhabited
 note: the lint level is defined here
-  --> $DIR/empty-types.rs:17:9
+  --> $DIR/empty-types.rs:15:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:54:9
+  --> $DIR/empty-types.rs:52:9
    |
 LL |         _x => {}
    |         ^^
@@ -20,7 +20,7 @@ LL |         _x => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `&!` is non-empty
-  --> $DIR/empty-types.rs:58:11
+  --> $DIR/empty-types.rs:56:11
    |
 LL |     match ref_never {}
    |           ^^^^^^^^^
@@ -35,7 +35,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:73:9
+  --> $DIR/empty-types.rs:70:9
    |
 LL |         (_, _) => {}
    |         ^^^^^^
@@ -43,7 +43,7 @@ LL |         (_, _) => {}
    = note: this pattern matches no values because `(u32, !)` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:80:9
+  --> $DIR/empty-types.rs:76:9
    |
 LL |         _ => {}
    |         ^
@@ -51,7 +51,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `(!, !)` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:83:9
+  --> $DIR/empty-types.rs:79:9
    |
 LL |         (_, _) => {}
    |         ^^^^^^
@@ -59,7 +59,7 @@ LL |         (_, _) => {}
    = note: this pattern matches no values because `(!, !)` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:87:9
+  --> $DIR/empty-types.rs:83:9
    |
 LL |         _ => {}
    |         ^
@@ -67,7 +67,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: `Ok(_)` not covered
-  --> $DIR/empty-types.rs:91:11
+  --> $DIR/empty-types.rs:87:11
    |
 LL |     match res_u32_never {}
    |           ^^^^^^^^^^^^^ pattern `Ok(_)` not covered
@@ -86,7 +86,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:99:9
+  --> $DIR/empty-types.rs:94:9
    |
 LL |         Err(_) => {}
    |         ^^^^^^
@@ -94,7 +94,7 @@ LL |         Err(_) => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:104:9
+  --> $DIR/empty-types.rs:99:9
    |
 LL |         Err(_) => {}
    |         ^^^^^^
@@ -102,7 +102,7 @@ LL |         Err(_) => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered
-  --> $DIR/empty-types.rs:101:11
+  --> $DIR/empty-types.rs:96:11
    |
 LL |     match res_u32_never {
    |           ^^^^^^^^^^^^^ pattern `Ok(1_u32..=u32::MAX)` not covered
@@ -120,7 +120,7 @@ LL ~         Ok(1_u32..=u32::MAX) => todo!()
    |
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/empty-types.rs:108:9
+  --> $DIR/empty-types.rs:102:9
    |
 LL |     let Ok(_x) = res_u32_never.as_ref();
    |         ^^^^^^ pattern `Err(_)` not covered
@@ -134,7 +134,7 @@ LL |     let Ok(_x) = res_u32_never.as_ref() else { todo!() };
    |                                         ++++++++++++++++
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:119:9
+  --> $DIR/empty-types.rs:112:9
    |
 LL |         _ => {}
    |         ^
@@ -142,7 +142,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:123:9
+  --> $DIR/empty-types.rs:115:9
    |
 LL |         Ok(_) => {}
    |         ^^^^^
@@ -150,7 +150,7 @@ LL |         Ok(_) => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:126:9
+  --> $DIR/empty-types.rs:118:9
    |
 LL |         Ok(_) => {}
    |         ^^^^^
@@ -158,7 +158,7 @@ LL |         Ok(_) => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:127:9
+  --> $DIR/empty-types.rs:119:9
    |
 LL |         _ => {}
    |         ^
@@ -166,7 +166,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:130:9
+  --> $DIR/empty-types.rs:122:9
    |
 LL |         Ok(_) => {}
    |         ^^^^^
@@ -174,7 +174,7 @@ LL |         Ok(_) => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:131:9
+  --> $DIR/empty-types.rs:123:9
    |
 LL |         Err(_) => {}
    |         ^^^^^^
@@ -182,7 +182,7 @@ LL |         Err(_) => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:140:13
+  --> $DIR/empty-types.rs:132:13
    |
 LL |             _ => {}
    |             ^
@@ -190,7 +190,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:143:13
+  --> $DIR/empty-types.rs:135:13
    |
 LL |             _ if false => {}
    |             ^
@@ -198,7 +198,7 @@ LL |             _ if false => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:152:13
+  --> $DIR/empty-types.rs:143:13
    |
 LL |             Some(_) => {}
    |             ^^^^^^^
@@ -206,7 +206,7 @@ LL |             Some(_) => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:156:13
+  --> $DIR/empty-types.rs:147:13
    |
 LL |             None => {}
    |             ---- matches all the values already
@@ -214,7 +214,7 @@ LL |             _ => {}
    |             ^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:208:13
+  --> $DIR/empty-types.rs:199:13
    |
 LL |             _ => {}
    |             ^
@@ -222,7 +222,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:213:13
+  --> $DIR/empty-types.rs:204:13
    |
 LL |             _ => {}
    |             ^
@@ -230,7 +230,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:218:13
+  --> $DIR/empty-types.rs:209:13
    |
 LL |             _ => {}
    |             ^
@@ -238,7 +238,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:223:13
+  --> $DIR/empty-types.rs:214:13
    |
 LL |             _ => {}
    |             ^
@@ -246,7 +246,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:229:13
+  --> $DIR/empty-types.rs:220:13
    |
 LL |             _ => {}
    |             ^
@@ -254,7 +254,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:288:9
+  --> $DIR/empty-types.rs:279:9
    |
 LL |         _ => {}
    |         ^
@@ -262,7 +262,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:291:9
+  --> $DIR/empty-types.rs:282:9
    |
 LL |         (_, _) => {}
    |         ^^^^^^
@@ -270,7 +270,7 @@ LL |         (_, _) => {}
    = note: this pattern matches no values because `(!, !)` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:294:9
+  --> $DIR/empty-types.rs:285:9
    |
 LL |         Ok(_) => {}
    |         ^^^^^
@@ -278,7 +278,7 @@ LL |         Ok(_) => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:295:9
+  --> $DIR/empty-types.rs:286:9
    |
 LL |         Err(_) => {}
    |         ^^^^^^
@@ -286,7 +286,7 @@ LL |         Err(_) => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty
-  --> $DIR/empty-types.rs:327:11
+  --> $DIR/empty-types.rs:318:11
    |
 LL |     match slice_never {}
    |           ^^^^^^^^^^^
@@ -300,7 +300,7 @@ LL +     }
    |
 
 error[E0004]: non-exhaustive patterns: `&[]` not covered
-  --> $DIR/empty-types.rs:338:11
+  --> $DIR/empty-types.rs:329:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ pattern `&[]` not covered
@@ -313,7 +313,7 @@ LL +         &[] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[]` not covered
-  --> $DIR/empty-types.rs:352:11
+  --> $DIR/empty-types.rs:343:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ pattern `&[]` not covered
@@ -327,7 +327,7 @@ LL +         &[] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: type `[!]` is non-empty
-  --> $DIR/empty-types.rs:359:11
+  --> $DIR/empty-types.rs:350:11
    |
 LL |     match *slice_never {}
    |           ^^^^^^^^^^^^
@@ -341,7 +341,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:369:9
+  --> $DIR/empty-types.rs:359:9
    |
 LL |         _ => {}
    |         ^
@@ -349,7 +349,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:372:9
+  --> $DIR/empty-types.rs:362:9
    |
 LL |         [_, _, _] => {}
    |         ^^^^^^^^^
@@ -357,7 +357,7 @@ LL |         [_, _, _] => {}
    = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:375:9
+  --> $DIR/empty-types.rs:365:9
    |
 LL |         [_, ..] => {}
    |         ^^^^^^^
@@ -365,7 +365,7 @@ LL |         [_, ..] => {}
    = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty
-  --> $DIR/empty-types.rs:389:11
+  --> $DIR/empty-types.rs:379:11
    |
 LL |     match array_0_never {}
    |           ^^^^^^^^^^^^^
@@ -379,7 +379,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:396:9
+  --> $DIR/empty-types.rs:386:9
    |
 LL |         [] => {}
    |         -- matches all the values already
@@ -387,7 +387,7 @@ LL |         _ => {}
    |         ^ unreachable pattern
 
 error[E0004]: non-exhaustive patterns: `[]` not covered
-  --> $DIR/empty-types.rs:398:11
+  --> $DIR/empty-types.rs:388:11
    |
 LL |     match array_0_never {
    |           ^^^^^^^^^^^^^ pattern `[]` not covered
@@ -401,7 +401,7 @@ LL +         [] => todo!()
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:417:9
+  --> $DIR/empty-types.rs:407:9
    |
 LL |         Some(_) => {}
    |         ^^^^^^^
@@ -409,7 +409,7 @@ LL |         Some(_) => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:422:9
+  --> $DIR/empty-types.rs:412:9
    |
 LL |         Some(_a) => {}
    |         ^^^^^^^^
@@ -417,7 +417,7 @@ LL |         Some(_a) => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:427:9
+  --> $DIR/empty-types.rs:417:9
    |
 LL |         None => {}
    |         ---- matches all the values already
@@ -426,7 +426,7 @@ LL |         _ => {}
    |         ^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:432:9
+  --> $DIR/empty-types.rs:422:9
    |
 LL |         None => {}
    |         ---- matches all the values already
@@ -435,7 +435,7 @@ LL |         _a => {}
    |         ^^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:604:9
+  --> $DIR/empty-types.rs:594:9
    |
 LL |         _ => {}
    |         ^
@@ -443,7 +443,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:607:9
+  --> $DIR/empty-types.rs:597:9
    |
 LL |         _x => {}
    |         ^^
@@ -451,7 +451,7 @@ LL |         _x => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:610:9
+  --> $DIR/empty-types.rs:600:9
    |
 LL |         _ if false => {}
    |         ^
@@ -459,7 +459,7 @@ LL |         _ if false => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:613:9
+  --> $DIR/empty-types.rs:603:9
    |
 LL |         _x if false => {}
    |         ^^
diff --git a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr
index 4856a2f8e08..1ecb15f2cae 100644
--- a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr
+++ b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr
@@ -1,5 +1,5 @@
 warning: the feature `never_patterns` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/empty-types.rs:14:33
+  --> $DIR/empty-types.rs:12:33
    |
 LL | #![cfg_attr(never_pats, feature(never_patterns))]
    |                                 ^^^^^^^^^^^^^^
@@ -8,20 +8,20 @@ LL | #![cfg_attr(never_pats, feature(never_patterns))]
    = note: `#[warn(incomplete_features)]` on by default
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:51:9
+  --> $DIR/empty-types.rs:49:9
    |
 LL |         _ => {}
    |         ^
    |
    = note: this pattern matches no values because `!` is uninhabited
 note: the lint level is defined here
-  --> $DIR/empty-types.rs:17:9
+  --> $DIR/empty-types.rs:15:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:54:9
+  --> $DIR/empty-types.rs:52:9
    |
 LL |         _x => {}
    |         ^^
@@ -29,7 +29,7 @@ LL |         _x => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `&!` is non-empty
-  --> $DIR/empty-types.rs:58:11
+  --> $DIR/empty-types.rs:56:11
    |
 LL |     match ref_never {}
    |           ^^^^^^^^^
@@ -43,84 +43,75 @@ LL +         _ => todo!(),
 LL +     }
    |
 
-error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
-  --> $DIR/empty-types.rs:70:11
-   |
-LL |     match tuple_half_never {}
-   |           ^^^^^^^^^^^^^^^^
-   |
-   = note: the matched value is of type `(u32, !)`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+error: unreachable pattern
+  --> $DIR/empty-types.rs:70:9
    |
-LL ~     match tuple_half_never {
-LL +         _ => todo!(),
-LL +     }
+LL |         (_, _) => {}
+   |         ^^^^^^
    |
+   = note: this pattern matches no values because `(u32, !)` is uninhabited
 
-error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty
-  --> $DIR/empty-types.rs:77:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:76:9
    |
-LL |     match tuple_never {}
-   |           ^^^^^^^^^^^
+LL |         _ => {}
+   |         ^
    |
-   = note: the matched value is of type `(!, !)`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   = note: this pattern matches no values because `(!, !)` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:79:9
    |
-LL ~     match tuple_never {
-LL +         _ => todo!(),
-LL +     }
+LL |         (_, _) => {}
+   |         ^^^^^^
    |
+   = note: this pattern matches no values because `(!, !)` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:87:9
+  --> $DIR/empty-types.rs:83:9
    |
 LL |         _ => {}
    |         ^
    |
    = note: this pattern matches no values because `!` is uninhabited
 
-error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(!)` not covered
-  --> $DIR/empty-types.rs:91:11
+error[E0004]: non-exhaustive patterns: `Ok(_)` not covered
+  --> $DIR/empty-types.rs:87:11
    |
 LL |     match res_u32_never {}
-   |           ^^^^^^^^^^^^^ patterns `Ok(_)` and `Err(!)` not covered
+   |           ^^^^^^^^^^^^^ pattern `Ok(_)` not covered
    |
 note: `Result<u32, !>` defined here
   --> $SRC_DIR/core/src/result.rs:LL:COL
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
    = note: not covered
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-   = note: not covered
    = note: the matched value is of type `Result<u32, !>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~     match res_u32_never {
-LL +         Ok(_) | Err(!) => todo!(),
+LL +         Ok(_) => todo!(),
 LL +     }
    |
 
-error[E0004]: non-exhaustive patterns: `Err(!)` not covered
-  --> $DIR/empty-types.rs:93:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:94:9
    |
-LL |     match res_u32_never {
-   |           ^^^^^^^^^^^^^ pattern `Err(!)` not covered
+LL |         Err(_) => {}
+   |         ^^^^^^
    |
-note: `Result<u32, !>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-   = note: not covered
-   = note: the matched value is of type `Result<u32, !>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   = note: this pattern matches no values because `!` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:99:9
    |
-LL ~         Ok(_) => {},
-LL +         Err(!)
+LL |         Err(_) => {}
+   |         ^^^^^^
    |
+   = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered
-  --> $DIR/empty-types.rs:101:11
+  --> $DIR/empty-types.rs:96:11
    |
 LL |     match res_u32_never {
    |           ^^^^^^^^^^^^^ pattern `Ok(1_u32..=u32::MAX)` not covered
@@ -138,21 +129,7 @@ LL ~         Ok(1_u32..=u32::MAX) => todo!()
    |
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/empty-types.rs:106:9
-   |
-LL |     let Ok(_x) = res_u32_never;
-   |         ^^^^^^ pattern `Err(!)` not covered
-   |
-   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
-   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-   = note: the matched value is of type `Result<u32, !>`
-help: you might want to use `let else` to handle the variant that isn't matched
-   |
-LL |     let Ok(_x) = res_u32_never else { todo!() };
-   |                                ++++++++++++++++
-
-error[E0005]: refutable pattern in local binding
-  --> $DIR/empty-types.rs:108:9
+  --> $DIR/empty-types.rs:102:9
    |
 LL |     let Ok(_x) = res_u32_never.as_ref();
    |         ^^^^^^ pattern `Err(_)` not covered
@@ -166,7 +143,7 @@ LL |     let Ok(_x) = res_u32_never.as_ref() else { todo!() };
    |                                         ++++++++++++++++
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/empty-types.rs:112:9
+  --> $DIR/empty-types.rs:106:9
    |
 LL |     let Ok(_x) = &res_u32_never;
    |         ^^^^^^ pattern `&Err(!)` not covered
@@ -179,47 +156,56 @@ help: you might want to use `let else` to handle the variant that isn't matched
 LL |     let Ok(_x) = &res_u32_never else { todo!() };
    |                                 ++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `Ok(!)` and `Err(!)` not covered
-  --> $DIR/empty-types.rs:116:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:112:9
    |
-LL |     match result_never {}
-   |           ^^^^^^^^^^^^ patterns `Ok(!)` and `Err(!)` not covered
+LL |         _ => {}
+   |         ^
    |
-note: `Result<!, !>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:115:9
    |
-   = note: not covered
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+LL |         Ok(_) => {}
+   |         ^^^^^
    |
-   = note: not covered
-   = note: the matched value is of type `Result<!, !>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:118:9
    |
-LL ~     match result_never {
-LL +         Ok(!) | Err(!),
-LL +     }
+LL |         Ok(_) => {}
+   |         ^^^^^
    |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
-error[E0004]: non-exhaustive patterns: `Err(!)` not covered
-  --> $DIR/empty-types.rs:121:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:119:9
    |
-LL |     match result_never {
-   |           ^^^^^^^^^^^^ pattern `Err(!)` not covered
+LL |         _ => {}
+   |         ^
    |
-note: `Result<!, !>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:122:9
    |
-   = note: not covered
-   = note: the matched value is of type `Result<!, !>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+LL |         Ok(_) => {}
+   |         ^^^^^
    |
-LL |         Ok(_) => {}, Err(!)
-   |                    ++++++++
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:140:13
+  --> $DIR/empty-types.rs:123:9
+   |
+LL |         Err(_) => {}
+   |         ^^^^^^
+   |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:132:13
    |
 LL |             _ => {}
    |             ^
@@ -227,33 +213,31 @@ LL |             _ => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:143:13
+  --> $DIR/empty-types.rs:135:13
    |
 LL |             _ if false => {}
    |             ^
    |
    = note: this pattern matches no values because `Void` is uninhabited
 
-error[E0004]: non-exhaustive patterns: `Some(!)` not covered
-  --> $DIR/empty-types.rs:146:15
-   |
-LL |         match opt_void {
-   |               ^^^^^^^^ pattern `Some(!)` not covered
+error: unreachable pattern
+  --> $DIR/empty-types.rs:143:13
    |
-note: `Option<Void>` defined here
-  --> $SRC_DIR/core/src/option.rs:LL:COL
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
+LL |             Some(_) => {}
+   |             ^^^^^^^
    |
-   = note: not covered
-   = note: the matched value is of type `Option<Void>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
-   |
-LL ~             None => {},
-LL +             Some(!)
+   = note: this pattern matches no values because `Void` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:147:13
    |
+LL |             None => {}
+   |             ---- matches all the values already
+LL |             _ => {}
+   |             ^ unreachable pattern
 
 error[E0004]: non-exhaustive patterns: `Some(!)` not covered
-  --> $DIR/empty-types.rs:165:15
+  --> $DIR/empty-types.rs:156:15
    |
 LL |         match *ref_opt_void {
    |               ^^^^^^^^^^^^^ pattern `Some(!)` not covered
@@ -264,6 +248,7 @@ note: `Option<Void>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<Void>`
+   = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~             None => {},
@@ -271,7 +256,7 @@ LL +             Some(!)
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:208:13
+  --> $DIR/empty-types.rs:199:13
    |
 LL |             _ => {}
    |             ^
@@ -279,7 +264,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:213:13
+  --> $DIR/empty-types.rs:204:13
    |
 LL |             _ => {}
    |             ^
@@ -287,7 +272,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:218:13
+  --> $DIR/empty-types.rs:209:13
    |
 LL |             _ => {}
    |             ^
@@ -295,7 +280,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:223:13
+  --> $DIR/empty-types.rs:214:13
    |
 LL |             _ => {}
    |             ^
@@ -303,7 +288,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:229:13
+  --> $DIR/empty-types.rs:220:13
    |
 LL |             _ => {}
    |             ^
@@ -311,15 +296,39 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:288:9
+  --> $DIR/empty-types.rs:279:9
    |
 LL |         _ => {}
    |         ^
    |
    = note: this pattern matches no values because `!` is uninhabited
 
+error: unreachable pattern
+  --> $DIR/empty-types.rs:282:9
+   |
+LL |         (_, _) => {}
+   |         ^^^^^^
+   |
+   = note: this pattern matches no values because `(!, !)` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:285:9
+   |
+LL |         Ok(_) => {}
+   |         ^^^^^
+   |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:286:9
+   |
+LL |         Err(_) => {}
+   |         ^^^^^^
+   |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
 error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
-  --> $DIR/empty-types.rs:316:11
+  --> $DIR/empty-types.rs:307:11
    |
 LL |     match *x {}
    |           ^^
@@ -333,7 +342,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty
-  --> $DIR/empty-types.rs:318:11
+  --> $DIR/empty-types.rs:309:11
    |
 LL |     match *x {}
    |           ^^
@@ -347,7 +356,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: `Ok(!)` and `Err(!)` not covered
-  --> $DIR/empty-types.rs:320:11
+  --> $DIR/empty-types.rs:311:11
    |
 LL |     match *x {}
    |           ^^ patterns `Ok(!)` and `Err(!)` not covered
@@ -369,7 +378,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty
-  --> $DIR/empty-types.rs:322:11
+  --> $DIR/empty-types.rs:313:11
    |
 LL |     match *x {}
    |           ^^
@@ -383,7 +392,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty
-  --> $DIR/empty-types.rs:327:11
+  --> $DIR/empty-types.rs:318:11
    |
 LL |     match slice_never {}
    |           ^^^^^^^^^^^
@@ -397,12 +406,13 @@ LL +     }
    |
 
 error[E0004]: non-exhaustive patterns: `&[!, ..]` not covered
-  --> $DIR/empty-types.rs:329:11
+  --> $DIR/empty-types.rs:320:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ pattern `&[!, ..]` not covered
    |
    = note: the matched value is of type `&[!]`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         [] => {},
@@ -410,7 +420,7 @@ LL +         &[!, ..]
    |
 
 error[E0004]: non-exhaustive patterns: `&[]`, `&[!]` and `&[!, !]` not covered
-  --> $DIR/empty-types.rs:338:11
+  --> $DIR/empty-types.rs:329:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ patterns `&[]`, `&[!]` and `&[!, !]` not covered
@@ -423,7 +433,7 @@ LL +         &[] | &[!] | &[!, !] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[!, ..]` not covered
-  --> $DIR/empty-types.rs:352:11
+  --> $DIR/empty-types.rs:343:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ patterns `&[]` and `&[!, ..]` not covered
@@ -437,7 +447,7 @@ LL +         &[] | &[!, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: type `[!]` is non-empty
-  --> $DIR/empty-types.rs:359:11
+  --> $DIR/empty-types.rs:350:11
    |
 LL |     match *slice_never {}
    |           ^^^^^^^^^^^^
@@ -450,22 +460,32 @@ LL +         _ => todo!(),
 LL +     }
    |
 
-error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty
-  --> $DIR/empty-types.rs:366:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:359:9
    |
-LL |     match array_3_never {}
-   |           ^^^^^^^^^^^^^
+LL |         _ => {}
+   |         ^
    |
-   = note: the matched value is of type `[!; 3]`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   = note: this pattern matches no values because `[!; 3]` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:362:9
    |
-LL ~     match array_3_never {
-LL +         _ => todo!(),
-LL +     }
+LL |         [_, _, _] => {}
+   |         ^^^^^^^^^
    |
+   = note: this pattern matches no values because `[!; 3]` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:365:9
+   |
+LL |         [_, ..] => {}
+   |         ^^^^^^^
+   |
+   = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty
-  --> $DIR/empty-types.rs:389:11
+  --> $DIR/empty-types.rs:379:11
    |
 LL |     match array_0_never {}
    |           ^^^^^^^^^^^^^
@@ -479,7 +499,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:396:9
+  --> $DIR/empty-types.rs:386:9
    |
 LL |         [] => {}
    |         -- matches all the values already
@@ -487,7 +507,7 @@ LL |         _ => {}
    |         ^ unreachable pattern
 
 error[E0004]: non-exhaustive patterns: `[]` not covered
-  --> $DIR/empty-types.rs:398:11
+  --> $DIR/empty-types.rs:388:11
    |
 LL |     match array_0_never {
    |           ^^^^^^^^^^^^^ pattern `[]` not covered
@@ -500,8 +520,42 @@ LL ~         [..] if false => {},
 LL +         [] => todo!()
    |
 
+error: unreachable pattern
+  --> $DIR/empty-types.rs:407:9
+   |
+LL |         Some(_) => {}
+   |         ^^^^^^^
+   |
+   = note: this pattern matches no values because `!` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:412:9
+   |
+LL |         Some(_a) => {}
+   |         ^^^^^^^^
+   |
+   = note: this pattern matches no values because `!` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:417:9
+   |
+LL |         None => {}
+   |         ---- matches all the values already
+LL |         // !useful, !reachable
+LL |         _ => {}
+   |         ^ unreachable pattern
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:422:9
+   |
+LL |         None => {}
+   |         ---- matches all the values already
+LL |         // !useful, !reachable
+LL |         _a => {}
+   |         ^^ unreachable pattern
+
 error[E0004]: non-exhaustive patterns: `&Some(!)` not covered
-  --> $DIR/empty-types.rs:452:11
+  --> $DIR/empty-types.rs:442:11
    |
 LL |     match ref_opt_never {
    |           ^^^^^^^^^^^^^ pattern `&Some(!)` not covered
@@ -512,6 +566,7 @@ note: `Option<!>` defined here
    |
    = note: not covered
    = note: the matched value is of type `&Option<!>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         &None => {},
@@ -519,7 +574,7 @@ LL +         &Some(!)
    |
 
 error[E0004]: non-exhaustive patterns: `Some(!)` not covered
-  --> $DIR/empty-types.rs:493:11
+  --> $DIR/empty-types.rs:483:11
    |
 LL |     match *ref_opt_never {
    |           ^^^^^^^^^^^^^^ pattern `Some(!)` not covered
@@ -530,6 +585,7 @@ note: `Option<!>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<!>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None => {},
@@ -537,7 +593,7 @@ LL +         Some(!)
    |
 
 error[E0004]: non-exhaustive patterns: `Err(!)` not covered
-  --> $DIR/empty-types.rs:541:11
+  --> $DIR/empty-types.rs:531:11
    |
 LL |     match *ref_res_never {
    |           ^^^^^^^^^^^^^^ pattern `Err(!)` not covered
@@ -548,6 +604,7 @@ note: `Result<!, !>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Ok(_) => {},
@@ -555,7 +612,7 @@ LL +         Err(!)
    |
 
 error[E0004]: non-exhaustive patterns: `Err(!)` not covered
-  --> $DIR/empty-types.rs:552:11
+  --> $DIR/empty-types.rs:542:11
    |
 LL |     match *ref_res_never {
    |           ^^^^^^^^^^^^^^ pattern `Err(!)` not covered
@@ -566,6 +623,7 @@ note: `Result<!, !>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Ok(_a) => {},
@@ -573,7 +631,7 @@ LL +         Err(!)
    |
 
 error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
-  --> $DIR/empty-types.rs:571:11
+  --> $DIR/empty-types.rs:561:11
    |
 LL |     match *ref_tuple_half_never {}
    |           ^^^^^^^^^^^^^^^^^^^^^
@@ -587,7 +645,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:604:9
+  --> $DIR/empty-types.rs:594:9
    |
 LL |         _ => {}
    |         ^
@@ -595,7 +653,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:607:9
+  --> $DIR/empty-types.rs:597:9
    |
 LL |         _x => {}
    |         ^^
@@ -603,7 +661,7 @@ LL |         _x => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:610:9
+  --> $DIR/empty-types.rs:600:9
    |
 LL |         _ if false => {}
    |         ^
@@ -611,7 +669,7 @@ LL |         _ if false => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:613:9
+  --> $DIR/empty-types.rs:603:9
    |
 LL |         _x if false => {}
    |         ^^
@@ -619,12 +677,13 @@ LL |         _x if false => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: `&!` not covered
-  --> $DIR/empty-types.rs:638:11
+  --> $DIR/empty-types.rs:628:11
    |
 LL |     match ref_never {
    |           ^^^^^^^^^ pattern `&!` not covered
    |
    = note: the matched value is of type `&!`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
    = note: references are always considered inhabited
    = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
@@ -634,7 +693,7 @@ LL +         &!
    |
 
 error[E0004]: non-exhaustive patterns: `Ok(!)` not covered
-  --> $DIR/empty-types.rs:654:11
+  --> $DIR/empty-types.rs:644:11
    |
 LL |     match *ref_result_never {
    |           ^^^^^^^^^^^^^^^^^ pattern `Ok(!)` not covered
@@ -645,6 +704,7 @@ note: `Result<!, !>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Err(_) => {},
@@ -652,7 +712,7 @@ LL +         Ok(!)
    |
 
 error[E0004]: non-exhaustive patterns: `Some(!)` not covered
-  --> $DIR/empty-types.rs:674:11
+  --> $DIR/empty-types.rs:664:11
    |
 LL |     match *x {
    |           ^^ pattern `Some(!)` not covered
@@ -663,13 +723,14 @@ note: `Option<Result<!, !>>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<Result<!, !>>`
+   = note: `Result<!, !>` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None => {},
 LL +         Some(!)
    |
 
-error: aborting due to 49 previous errors; 1 warning emitted
+error: aborting due to 64 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0004, E0005.
 For more information about an error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-types.normal.stderr b/tests/ui/pattern/usefulness/empty-types.normal.stderr
index 78db9ee349b..c3421cd592e 100644
--- a/tests/ui/pattern/usefulness/empty-types.normal.stderr
+++ b/tests/ui/pattern/usefulness/empty-types.normal.stderr
@@ -1,18 +1,18 @@
 error: unreachable pattern
-  --> $DIR/empty-types.rs:51:9
+  --> $DIR/empty-types.rs:49:9
    |
 LL |         _ => {}
    |         ^
    |
    = note: this pattern matches no values because `!` is uninhabited
 note: the lint level is defined here
-  --> $DIR/empty-types.rs:17:9
+  --> $DIR/empty-types.rs:15:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:54:9
+  --> $DIR/empty-types.rs:52:9
    |
 LL |         _x => {}
    |         ^^
@@ -20,7 +20,7 @@ LL |         _x => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `&!` is non-empty
-  --> $DIR/empty-types.rs:58:11
+  --> $DIR/empty-types.rs:56:11
    |
 LL |     match ref_never {}
    |           ^^^^^^^^^
@@ -34,84 +34,75 @@ LL +         _ => todo!(),
 LL +     }
    |
 
-error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
-  --> $DIR/empty-types.rs:70:11
-   |
-LL |     match tuple_half_never {}
-   |           ^^^^^^^^^^^^^^^^
-   |
-   = note: the matched value is of type `(u32, !)`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+error: unreachable pattern
+  --> $DIR/empty-types.rs:70:9
    |
-LL ~     match tuple_half_never {
-LL +         _ => todo!(),
-LL +     }
+LL |         (_, _) => {}
+   |         ^^^^^^
    |
+   = note: this pattern matches no values because `(u32, !)` is uninhabited
 
-error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty
-  --> $DIR/empty-types.rs:77:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:76:9
    |
-LL |     match tuple_never {}
-   |           ^^^^^^^^^^^
+LL |         _ => {}
+   |         ^
    |
-   = note: the matched value is of type `(!, !)`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   = note: this pattern matches no values because `(!, !)` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:79:9
    |
-LL ~     match tuple_never {
-LL +         _ => todo!(),
-LL +     }
+LL |         (_, _) => {}
+   |         ^^^^^^
    |
+   = note: this pattern matches no values because `(!, !)` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:87:9
+  --> $DIR/empty-types.rs:83:9
    |
 LL |         _ => {}
    |         ^
    |
    = note: this pattern matches no values because `!` is uninhabited
 
-error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(_)` not covered
-  --> $DIR/empty-types.rs:91:11
+error[E0004]: non-exhaustive patterns: `Ok(_)` not covered
+  --> $DIR/empty-types.rs:87:11
    |
 LL |     match res_u32_never {}
-   |           ^^^^^^^^^^^^^ patterns `Ok(_)` and `Err(_)` not covered
+   |           ^^^^^^^^^^^^^ pattern `Ok(_)` not covered
    |
 note: `Result<u32, !>` defined here
   --> $SRC_DIR/core/src/result.rs:LL:COL
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
    = note: not covered
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-   = note: not covered
    = note: the matched value is of type `Result<u32, !>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~     match res_u32_never {
-LL +         Ok(_) | Err(_) => todo!(),
+LL +         Ok(_) => todo!(),
 LL +     }
    |
 
-error[E0004]: non-exhaustive patterns: `Err(_)` not covered
-  --> $DIR/empty-types.rs:93:11
-   |
-LL |     match res_u32_never {
-   |           ^^^^^^^^^^^^^ pattern `Err(_)` not covered
+error: unreachable pattern
+  --> $DIR/empty-types.rs:94:9
    |
-note: `Result<u32, !>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+LL |         Err(_) => {}
+   |         ^^^^^^
    |
-   = note: not covered
-   = note: the matched value is of type `Result<u32, !>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   = note: this pattern matches no values because `!` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:99:9
    |
-LL ~         Ok(_) => {},
-LL +         Err(_) => todo!()
+LL |         Err(_) => {}
+   |         ^^^^^^
    |
+   = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered
-  --> $DIR/empty-types.rs:101:11
+  --> $DIR/empty-types.rs:96:11
    |
 LL |     match res_u32_never {
    |           ^^^^^^^^^^^^^ pattern `Ok(1_u32..=u32::MAX)` not covered
@@ -129,21 +120,7 @@ LL ~         Ok(1_u32..=u32::MAX) => todo!()
    |
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/empty-types.rs:106:9
-   |
-LL |     let Ok(_x) = res_u32_never;
-   |         ^^^^^^ pattern `Err(_)` not covered
-   |
-   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
-   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-   = note: the matched value is of type `Result<u32, !>`
-help: you might want to use `let else` to handle the variant that isn't matched
-   |
-LL |     let Ok(_x) = res_u32_never else { todo!() };
-   |                                ++++++++++++++++
-
-error[E0005]: refutable pattern in local binding
-  --> $DIR/empty-types.rs:108:9
+  --> $DIR/empty-types.rs:102:9
    |
 LL |     let Ok(_x) = res_u32_never.as_ref();
    |         ^^^^^^ pattern `Err(_)` not covered
@@ -157,7 +134,7 @@ LL |     let Ok(_x) = res_u32_never.as_ref() else { todo!() };
    |                                         ++++++++++++++++
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/empty-types.rs:112:9
+  --> $DIR/empty-types.rs:106:9
    |
 LL |     let Ok(_x) = &res_u32_never;
    |         ^^^^^^ pattern `&Err(_)` not covered
@@ -170,47 +147,56 @@ help: you might want to use `let else` to handle the variant that isn't matched
 LL |     let Ok(_x) = &res_u32_never else { todo!() };
    |                                 ++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(_)` not covered
-  --> $DIR/empty-types.rs:116:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:112:9
    |
-LL |     match result_never {}
-   |           ^^^^^^^^^^^^ patterns `Ok(_)` and `Err(_)` not covered
+LL |         _ => {}
+   |         ^
    |
-note: `Result<!, !>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:115:9
    |
-   = note: not covered
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+LL |         Ok(_) => {}
+   |         ^^^^^
    |
-   = note: not covered
-   = note: the matched value is of type `Result<!, !>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:118:9
    |
-LL ~     match result_never {
-LL +         Ok(_) | Err(_) => todo!(),
-LL +     }
+LL |         Ok(_) => {}
+   |         ^^^^^
    |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
-error[E0004]: non-exhaustive patterns: `Err(_)` not covered
-  --> $DIR/empty-types.rs:121:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:119:9
    |
-LL |     match result_never {
-   |           ^^^^^^^^^^^^ pattern `Err(_)` not covered
+LL |         _ => {}
+   |         ^
    |
-note: `Result<!, !>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:122:9
    |
-   = note: not covered
-   = note: the matched value is of type `Result<!, !>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+LL |         Ok(_) => {}
+   |         ^^^^^
+   |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:123:9
    |
-LL |         Ok(_) => {}, Err(_) => todo!()
-   |                    +++++++++++++++++++
+LL |         Err(_) => {}
+   |         ^^^^^^
+   |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:140:13
+  --> $DIR/empty-types.rs:132:13
    |
 LL |             _ => {}
    |             ^
@@ -218,33 +204,31 @@ LL |             _ => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:143:13
+  --> $DIR/empty-types.rs:135:13
    |
 LL |             _ if false => {}
    |             ^
    |
    = note: this pattern matches no values because `Void` is uninhabited
 
-error[E0004]: non-exhaustive patterns: `Some(_)` not covered
-  --> $DIR/empty-types.rs:146:15
-   |
-LL |         match opt_void {
-   |               ^^^^^^^^ pattern `Some(_)` not covered
-   |
-note: `Option<Void>` defined here
-  --> $SRC_DIR/core/src/option.rs:LL:COL
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
+error: unreachable pattern
+  --> $DIR/empty-types.rs:143:13
    |
-   = note: not covered
-   = note: the matched value is of type `Option<Void>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+LL |             Some(_) => {}
+   |             ^^^^^^^
    |
-LL ~             None => {},
-LL +             Some(_) => todo!()
+   = note: this pattern matches no values because `Void` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:147:13
    |
+LL |             None => {}
+   |             ---- matches all the values already
+LL |             _ => {}
+   |             ^ unreachable pattern
 
 error[E0004]: non-exhaustive patterns: `Some(_)` not covered
-  --> $DIR/empty-types.rs:165:15
+  --> $DIR/empty-types.rs:156:15
    |
 LL |         match *ref_opt_void {
    |               ^^^^^^^^^^^^^ pattern `Some(_)` not covered
@@ -255,6 +239,7 @@ note: `Option<Void>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<Void>`
+   = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~             None => {},
@@ -262,7 +247,7 @@ LL +             Some(_) => todo!()
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:208:13
+  --> $DIR/empty-types.rs:199:13
    |
 LL |             _ => {}
    |             ^
@@ -270,7 +255,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:213:13
+  --> $DIR/empty-types.rs:204:13
    |
 LL |             _ => {}
    |             ^
@@ -278,7 +263,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:218:13
+  --> $DIR/empty-types.rs:209:13
    |
 LL |             _ => {}
    |             ^
@@ -286,7 +271,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:223:13
+  --> $DIR/empty-types.rs:214:13
    |
 LL |             _ => {}
    |             ^
@@ -294,7 +279,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:229:13
+  --> $DIR/empty-types.rs:220:13
    |
 LL |             _ => {}
    |             ^
@@ -302,15 +287,39 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:288:9
+  --> $DIR/empty-types.rs:279:9
    |
 LL |         _ => {}
    |         ^
    |
    = note: this pattern matches no values because `!` is uninhabited
 
+error: unreachable pattern
+  --> $DIR/empty-types.rs:282:9
+   |
+LL |         (_, _) => {}
+   |         ^^^^^^
+   |
+   = note: this pattern matches no values because `(!, !)` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:285:9
+   |
+LL |         Ok(_) => {}
+   |         ^^^^^
+   |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:286:9
+   |
+LL |         Err(_) => {}
+   |         ^^^^^^
+   |
+   = note: this pattern matches no values because `Result<!, !>` is uninhabited
+
 error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
-  --> $DIR/empty-types.rs:316:11
+  --> $DIR/empty-types.rs:307:11
    |
 LL |     match *x {}
    |           ^^
@@ -324,7 +333,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty
-  --> $DIR/empty-types.rs:318:11
+  --> $DIR/empty-types.rs:309:11
    |
 LL |     match *x {}
    |           ^^
@@ -338,7 +347,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(_)` not covered
-  --> $DIR/empty-types.rs:320:11
+  --> $DIR/empty-types.rs:311:11
    |
 LL |     match *x {}
    |           ^^ patterns `Ok(_)` and `Err(_)` not covered
@@ -360,7 +369,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty
-  --> $DIR/empty-types.rs:322:11
+  --> $DIR/empty-types.rs:313:11
    |
 LL |     match *x {}
    |           ^^
@@ -374,7 +383,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty
-  --> $DIR/empty-types.rs:327:11
+  --> $DIR/empty-types.rs:318:11
    |
 LL |     match slice_never {}
    |           ^^^^^^^^^^^
@@ -388,12 +397,13 @@ LL +     }
    |
 
 error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
-  --> $DIR/empty-types.rs:329:11
+  --> $DIR/empty-types.rs:320:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ pattern `&[_, ..]` not covered
    |
    = note: the matched value is of type `&[!]`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         [] => {},
@@ -401,7 +411,7 @@ LL +         &[_, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[]`, `&[_]` and `&[_, _]` not covered
-  --> $DIR/empty-types.rs:338:11
+  --> $DIR/empty-types.rs:329:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ patterns `&[]`, `&[_]` and `&[_, _]` not covered
@@ -414,7 +424,7 @@ LL +         &[] | &[_] | &[_, _] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[_, ..]` not covered
-  --> $DIR/empty-types.rs:352:11
+  --> $DIR/empty-types.rs:343:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ patterns `&[]` and `&[_, ..]` not covered
@@ -428,7 +438,7 @@ LL +         &[] | &[_, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: type `[!]` is non-empty
-  --> $DIR/empty-types.rs:359:11
+  --> $DIR/empty-types.rs:350:11
    |
 LL |     match *slice_never {}
    |           ^^^^^^^^^^^^
@@ -441,22 +451,32 @@ LL +         _ => todo!(),
 LL +     }
    |
 
-error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty
-  --> $DIR/empty-types.rs:366:11
+error: unreachable pattern
+  --> $DIR/empty-types.rs:359:9
    |
-LL |     match array_3_never {}
-   |           ^^^^^^^^^^^^^
+LL |         _ => {}
+   |         ^
    |
-   = note: the matched value is of type `[!; 3]`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   = note: this pattern matches no values because `[!; 3]` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:362:9
    |
-LL ~     match array_3_never {
-LL +         _ => todo!(),
-LL +     }
+LL |         [_, _, _] => {}
+   |         ^^^^^^^^^
+   |
+   = note: this pattern matches no values because `[!; 3]` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:365:9
+   |
+LL |         [_, ..] => {}
+   |         ^^^^^^^
    |
+   = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty
-  --> $DIR/empty-types.rs:389:11
+  --> $DIR/empty-types.rs:379:11
    |
 LL |     match array_0_never {}
    |           ^^^^^^^^^^^^^
@@ -470,7 +490,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:396:9
+  --> $DIR/empty-types.rs:386:9
    |
 LL |         [] => {}
    |         -- matches all the values already
@@ -478,7 +498,7 @@ LL |         _ => {}
    |         ^ unreachable pattern
 
 error[E0004]: non-exhaustive patterns: `[]` not covered
-  --> $DIR/empty-types.rs:398:11
+  --> $DIR/empty-types.rs:388:11
    |
 LL |     match array_0_never {
    |           ^^^^^^^^^^^^^ pattern `[]` not covered
@@ -491,8 +511,42 @@ LL ~         [..] if false => {},
 LL +         [] => todo!()
    |
 
+error: unreachable pattern
+  --> $DIR/empty-types.rs:407:9
+   |
+LL |         Some(_) => {}
+   |         ^^^^^^^
+   |
+   = note: this pattern matches no values because `!` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:412:9
+   |
+LL |         Some(_a) => {}
+   |         ^^^^^^^^
+   |
+   = note: this pattern matches no values because `!` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:417:9
+   |
+LL |         None => {}
+   |         ---- matches all the values already
+LL |         // !useful, !reachable
+LL |         _ => {}
+   |         ^ unreachable pattern
+
+error: unreachable pattern
+  --> $DIR/empty-types.rs:422:9
+   |
+LL |         None => {}
+   |         ---- matches all the values already
+LL |         // !useful, !reachable
+LL |         _a => {}
+   |         ^^ unreachable pattern
+
 error[E0004]: non-exhaustive patterns: `&Some(_)` not covered
-  --> $DIR/empty-types.rs:452:11
+  --> $DIR/empty-types.rs:442:11
    |
 LL |     match ref_opt_never {
    |           ^^^^^^^^^^^^^ pattern `&Some(_)` not covered
@@ -503,6 +557,7 @@ note: `Option<!>` defined here
    |
    = note: not covered
    = note: the matched value is of type `&Option<!>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         &None => {},
@@ -510,7 +565,7 @@ LL +         &Some(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Some(_)` not covered
-  --> $DIR/empty-types.rs:493:11
+  --> $DIR/empty-types.rs:483:11
    |
 LL |     match *ref_opt_never {
    |           ^^^^^^^^^^^^^^ pattern `Some(_)` not covered
@@ -521,6 +576,7 @@ note: `Option<!>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<!>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None => {},
@@ -528,7 +584,7 @@ LL +         Some(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Err(_)` not covered
-  --> $DIR/empty-types.rs:541:11
+  --> $DIR/empty-types.rs:531:11
    |
 LL |     match *ref_res_never {
    |           ^^^^^^^^^^^^^^ pattern `Err(_)` not covered
@@ -539,6 +595,7 @@ note: `Result<!, !>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Ok(_) => {},
@@ -546,7 +603,7 @@ LL +         Err(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Err(_)` not covered
-  --> $DIR/empty-types.rs:552:11
+  --> $DIR/empty-types.rs:542:11
    |
 LL |     match *ref_res_never {
    |           ^^^^^^^^^^^^^^ pattern `Err(_)` not covered
@@ -557,6 +614,7 @@ note: `Result<!, !>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Ok(_a) => {},
@@ -564,7 +622,7 @@ LL +         Err(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
-  --> $DIR/empty-types.rs:571:11
+  --> $DIR/empty-types.rs:561:11
    |
 LL |     match *ref_tuple_half_never {}
    |           ^^^^^^^^^^^^^^^^^^^^^
@@ -578,7 +636,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:604:9
+  --> $DIR/empty-types.rs:594:9
    |
 LL |         _ => {}
    |         ^
@@ -586,7 +644,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:607:9
+  --> $DIR/empty-types.rs:597:9
    |
 LL |         _x => {}
    |         ^^
@@ -594,7 +652,7 @@ LL |         _x => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:610:9
+  --> $DIR/empty-types.rs:600:9
    |
 LL |         _ if false => {}
    |         ^
@@ -602,7 +660,7 @@ LL |         _ if false => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:613:9
+  --> $DIR/empty-types.rs:603:9
    |
 LL |         _x if false => {}
    |         ^^
@@ -610,12 +668,13 @@ LL |         _x if false => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: `&_` not covered
-  --> $DIR/empty-types.rs:638:11
+  --> $DIR/empty-types.rs:628:11
    |
 LL |     match ref_never {
    |           ^^^^^^^^^ pattern `&_` not covered
    |
    = note: the matched value is of type `&!`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
    = note: references are always considered inhabited
    = note: match arms with guards don't count towards exhaustivity
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
@@ -625,7 +684,7 @@ LL +         &_ => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Ok(_)` not covered
-  --> $DIR/empty-types.rs:654:11
+  --> $DIR/empty-types.rs:644:11
    |
 LL |     match *ref_result_never {
    |           ^^^^^^^^^^^^^^^^^ pattern `Ok(_)` not covered
@@ -636,6 +695,7 @@ note: `Result<!, !>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Result<!, !>`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         Err(_) => {},
@@ -643,7 +703,7 @@ LL +         Ok(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Some(_)` not covered
-  --> $DIR/empty-types.rs:674:11
+  --> $DIR/empty-types.rs:664:11
    |
 LL |     match *x {
    |           ^^ pattern `Some(_)` not covered
@@ -654,13 +714,14 @@ note: `Option<Result<!, !>>` defined here
    |
    = note: not covered
    = note: the matched value is of type `Option<Result<!, !>>`
+   = note: `Result<!, !>` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None => {},
 LL +         Some(_) => todo!()
    |
 
-error: aborting due to 49 previous errors
+error: aborting due to 64 previous errors
 
 Some errors have detailed explanations: E0004, E0005.
 For more information about an error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-types.rs b/tests/ui/pattern/usefulness/empty-types.rs
index cc71f67831d..639c48cea12 100644
--- a/tests/ui/pattern/usefulness/empty-types.rs
+++ b/tests/ui/pattern/usefulness/empty-types.rs
@@ -1,5 +1,4 @@
-//@ revisions: normal min_exh_pats exhaustive_patterns never_pats
-// gate-test-min_exhaustive_patterns
+//@ revisions: normal exhaustive_patterns never_pats
 //
 // This tests correct handling of empty types in exhaustiveness checking.
 //
@@ -10,7 +9,6 @@
 // This feature is useful to avoid `!` falling back to `()` all the time.
 #![feature(never_type_fallback)]
 #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
-#![cfg_attr(min_exh_pats, feature(min_exhaustive_patterns))]
 #![cfg_attr(never_pats, feature(never_patterns))]
 //[never_pats]~^ WARN the feature `never_patterns` is incomplete
 #![allow(dead_code, unreachable_code)]
@@ -68,19 +66,17 @@ fn basic(x: NeverBundle) {
 
     let tuple_half_never: (u32, !) = x.tuple_half_never;
     match tuple_half_never {}
-    //[normal,never_pats]~^ ERROR non-empty
     match tuple_half_never {
-        (_, _) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        (_, _) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
 
     let tuple_never: (!, !) = x.tuple_never;
     match tuple_never {}
-    //[normal,never_pats]~^ ERROR non-empty
     match tuple_never {
-        _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        _ => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match tuple_never {
-        (_, _) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        (_, _) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match tuple_never.0 {}
     match tuple_never.0 {
@@ -91,44 +87,40 @@ fn basic(x: NeverBundle) {
     match res_u32_never {}
     //~^ ERROR non-exhaustive
     match res_u32_never {
-        //[normal,never_pats]~^ ERROR non-exhaustive
         Ok(_) => {}
     }
     match res_u32_never {
         Ok(_) => {}
-        Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        Err(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match res_u32_never {
         //~^ ERROR non-exhaustive
         Ok(0) => {}
-        Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        Err(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     let Ok(_x) = res_u32_never;
-    //[normal,never_pats]~^ ERROR refutable
     let Ok(_x) = res_u32_never.as_ref();
     //~^ ERROR refutable
     // Non-obvious difference: here there's an implicit dereference in the patterns, which makes the
     // inner place !known_valid. `exhaustive_patterns` ignores this.
     let Ok(_x) = &res_u32_never;
-    //[normal,min_exh_pats,never_pats]~^ ERROR refutable
+    //[normal,never_pats]~^ ERROR refutable
 
     let result_never: Result<!, !> = x.result_never;
     match result_never {}
-    //[normal,never_pats]~^ ERROR non-exhaustive
     match result_never {
-        _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        _ => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match result_never {
-        //[normal,never_pats]~^ ERROR non-exhaustive
-        Ok(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        Ok(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match result_never {
-        Ok(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
-        _ => {}     //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        Ok(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
+        _ => {}     //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match result_never {
-        Ok(_) => {}  //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
-        Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        Ok(_) => {}  //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
+        Err(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
 }
 
@@ -144,16 +136,15 @@ fn void_same_as_never(x: NeverBundle) {
         }
         let opt_void: Option<Void> = None;
         match opt_void {
-            //[normal,never_pats]~^ ERROR non-exhaustive
             None => {}
         }
         match opt_void {
             None => {}
-            Some(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+            Some(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
         }
         match opt_void {
             None => {}
-            _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+            _ => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
         }
 
         let ref_void: &Void = &x.void;
@@ -163,7 +154,7 @@ fn void_same_as_never(x: NeverBundle) {
         }
         let ref_opt_void: &Option<Void> = &None;
         match *ref_opt_void {
-            //[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
+            //[normal,never_pats]~^ ERROR non-exhaustive
             None => {}
         }
         match *ref_opt_void {
@@ -288,11 +279,11 @@ fn nested_validity_tracking(bundle: NeverBundle) {
         _ => {} //~ ERROR unreachable pattern
     }
     match tuple_never {
-        (_, _) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        (_, _) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match result_never {
-        Ok(_) => {}  //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
-        Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        Ok(_) => {}  //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
+        Err(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
 
     // These should be considered !known_valid and not warn unreachable.
@@ -313,13 +304,13 @@ fn invalid_empty_match(bundle: NeverBundle) {
     match *x {}
 
     let x: &(u32, !) = &bundle.tuple_half_never;
-    match *x {} //[normal,min_exh_pats,never_pats]~ ERROR non-exhaustive
+    match *x {} //[normal,never_pats]~ ERROR non-exhaustive
     let x: &(!, !) = &bundle.tuple_never;
-    match *x {} //[normal,min_exh_pats,never_pats]~ ERROR non-exhaustive
+    match *x {} //[normal,never_pats]~ ERROR non-exhaustive
     let x: &Result<!, !> = &bundle.result_never;
-    match *x {} //[normal,min_exh_pats,never_pats]~ ERROR non-exhaustive
+    match *x {} //[normal,never_pats]~ ERROR non-exhaustive
     let x: &[!; 3] = &bundle.array_3_never;
-    match *x {} //[normal,min_exh_pats,never_pats]~ ERROR non-exhaustive
+    match *x {} //[normal,never_pats]~ ERROR non-exhaustive
 }
 
 fn arrays_and_slices(x: NeverBundle) {
@@ -327,7 +318,7 @@ fn arrays_and_slices(x: NeverBundle) {
     match slice_never {}
     //~^ ERROR non-empty
     match slice_never {
-        //[normal,min_exh_pats,never_pats]~^ ERROR not covered
+        //[normal,never_pats]~^ ERROR not covered
         [] => {}
     }
     match slice_never {
@@ -336,7 +327,7 @@ fn arrays_and_slices(x: NeverBundle) {
         [_, _, ..] => {}
     }
     match slice_never {
-        //[normal,min_exh_pats]~^ ERROR `&[]`, `&[_]` and `&[_, _]` not covered
+        //[normal]~^ ERROR `&[]`, `&[_]` and `&[_, _]` not covered
         //[exhaustive_patterns]~^^ ERROR `&[]` not covered
         //[never_pats]~^^^ ERROR `&[]`, `&[!]` and `&[!, !]` not covered
         [_, _, _, ..] => {}
@@ -350,7 +341,7 @@ fn arrays_and_slices(x: NeverBundle) {
         _x => {}
     }
     match slice_never {
-        //[normal,min_exh_pats]~^ ERROR `&[]` and `&[_, ..]` not covered
+        //[normal]~^ ERROR `&[]` and `&[_, ..]` not covered
         //[exhaustive_patterns]~^^ ERROR `&[]` not covered
         //[never_pats]~^^^ ERROR `&[]` and `&[!, ..]` not covered
         &[..] if false => {}
@@ -364,15 +355,14 @@ fn arrays_and_slices(x: NeverBundle) {
 
     let array_3_never: [!; 3] = x.array_3_never;
     match array_3_never {}
-    //[normal,never_pats]~^ ERROR non-empty
     match array_3_never {
-        _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        _ => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match array_3_never {
-        [_, _, _] => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        [_, _, _] => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match array_3_never {
-        [_, ..] => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        [_, ..] => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
 
     let ref_array_3_never: &[!; 3] = &array_3_never;
@@ -414,22 +404,22 @@ fn bindings(x: NeverBundle) {
     match opt_never {
         None => {}
         // !useful, !reachable
-        Some(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        Some(_) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match opt_never {
         None => {}
         // !useful, !reachable
-        Some(_a) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        Some(_a) => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match opt_never {
         None => {}
         // !useful, !reachable
-        _ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        _ => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
     match opt_never {
         None => {}
         // !useful, !reachable
-        _a => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
+        _a => {} //[exhaustive_patterns,normal,never_pats]~ ERROR unreachable pattern
     }
 
     // The scrutinee is known_valid, but under the `&` isn't anymore.
@@ -450,7 +440,7 @@ fn bindings(x: NeverBundle) {
         &_a => {}
     }
     match ref_opt_never {
-        //[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
+        //[normal,never_pats]~^ ERROR non-exhaustive
         &None => {}
     }
     match ref_opt_never {
@@ -491,7 +481,7 @@ fn bindings(x: NeverBundle) {
         ref _a => {}
     }
     match *ref_opt_never {
-        //[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
+        //[normal,never_pats]~^ ERROR non-exhaustive
         None => {}
     }
     match *ref_opt_never {
@@ -539,7 +529,7 @@ fn bindings(x: NeverBundle) {
 
     let ref_res_never: &Result<!, !> = &x.result_never;
     match *ref_res_never {
-        //[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
+        //[normal,never_pats]~^ ERROR non-exhaustive
         // useful, reachable
         Ok(_) => {}
     }
@@ -550,7 +540,7 @@ fn bindings(x: NeverBundle) {
         _ => {}
     }
     match *ref_res_never {
-        //[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
+        //[normal,never_pats]~^ ERROR non-exhaustive
         // useful, !reachable
         Ok(_a) => {}
     }
@@ -569,7 +559,7 @@ fn bindings(x: NeverBundle) {
 
     let ref_tuple_half_never: &(u32, !) = &x.tuple_half_never;
     match *ref_tuple_half_never {}
-    //[normal,min_exh_pats,never_pats]~^ ERROR non-empty
+    //[normal,never_pats]~^ ERROR non-empty
     match *ref_tuple_half_never {
         // useful, reachable
         (_, _) => {}
@@ -636,7 +626,7 @@ fn guards_and_validity(x: NeverBundle) {
         _a if false => {}
     }
     match ref_never {
-        //[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
+        //[normal,never_pats]~^ ERROR non-exhaustive
         // useful, !reachable
         &_a if false => {}
     }
@@ -652,7 +642,7 @@ fn guards_and_validity(x: NeverBundle) {
         Err(_) => {}
     }
     match *ref_result_never {
-        //[normal,min_exh_pats]~^ ERROR `Ok(_)` not covered
+        //[normal]~^ ERROR `Ok(_)` not covered
         //[never_pats]~^^ ERROR `Ok(!)` not covered
         // useful, reachable
         Ok(_) if false => {}
@@ -672,7 +662,7 @@ fn diagnostics_subtlety(x: NeverBundle) {
     // Regression test for diagnostics: don't report `Some(Ok(_))` and `Some(Err(_))`.
     let x: &Option<Result<!, !>> = &None;
     match *x {
-        //[normal,min_exh_pats]~^ ERROR `Some(_)` not covered
+        //[normal]~^ ERROR `Some(_)` not covered
         //[never_pats]~^^ ERROR `Some(!)` not covered
         None => {}
     }
diff --git a/tests/ui/pattern/usefulness/explain-unreachable-pats.rs b/tests/ui/pattern/usefulness/explain-unreachable-pats.rs
index 98f781b6a09..44d194055d9 100644
--- a/tests/ui/pattern/usefulness/explain-unreachable-pats.rs
+++ b/tests/ui/pattern/usefulness/explain-unreachable-pats.rs
@@ -1,5 +1,4 @@
 #![feature(never_type)]
-#![feature(min_exhaustive_patterns)]
 #![deny(unreachable_patterns)]
 //~^ NOTE lint level is defined here
 
diff --git a/tests/ui/pattern/usefulness/explain-unreachable-pats.stderr b/tests/ui/pattern/usefulness/explain-unreachable-pats.stderr
index e2eecf4a9f3..105d4f73f66 100644
--- a/tests/ui/pattern/usefulness/explain-unreachable-pats.stderr
+++ b/tests/ui/pattern/usefulness/explain-unreachable-pats.stderr
@@ -1,5 +1,5 @@
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:11:9
+  --> $DIR/explain-unreachable-pats.rs:10:9
    |
 LL |         (1 | 2,) => {}
    |         -------- matches all the values already
@@ -8,19 +8,19 @@ LL |         (2,) => {}
    |         ^^^^ unreachable pattern
    |
 note: the lint level is defined here
-  --> $DIR/explain-unreachable-pats.rs:3:9
+  --> $DIR/explain-unreachable-pats.rs:2:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:22:9
+  --> $DIR/explain-unreachable-pats.rs:21:9
    |
 LL |         (1 | 2,) => {}
    |         ^^^^^^^^ unreachable pattern
    |
 note: these patterns collectively make the last one unreachable
-  --> $DIR/explain-unreachable-pats.rs:22:9
+  --> $DIR/explain-unreachable-pats.rs:21:9
    |
 LL |         (1,) => {}
    |         ---- matches some of the same values
@@ -32,7 +32,7 @@ LL |         (1 | 2,) => {}
    |         ^^^^^^^^ collectively making this unreachable
 
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:33:9
+  --> $DIR/explain-unreachable-pats.rs:32:9
    |
 LL |         Err(_) => {}
    |         ^^^^^^
@@ -40,7 +40,7 @@ LL |         Err(_) => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:46:9
+  --> $DIR/explain-unreachable-pats.rs:45:9
    |
 LL |         (Err(_), Err(_)) => {}
    |         ^^^^^^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL |         (Err(_), Err(_)) => {}
    = note: this pattern matches no values because `Void2` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:52:9
+  --> $DIR/explain-unreachable-pats.rs:51:9
    |
 LL |         (Err(_), Err(_)) => {}
    |         ^^^^^^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL |         (Err(_), Err(_)) => {}
    = note: this pattern matches no values because `Void1` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:61:11
+  --> $DIR/explain-unreachable-pats.rs:60:11
    |
 LL |     if let (0
    |             - matches all the values already
@@ -65,13 +65,13 @@ LL |         | 0, _) = (0, 0) {}
    |           ^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:71:9
+  --> $DIR/explain-unreachable-pats.rs:70:9
    |
 LL |         (_, true) => {}
    |         ^^^^^^^^^ unreachable pattern
    |
 note: these patterns collectively make the last one unreachable
-  --> $DIR/explain-unreachable-pats.rs:71:9
+  --> $DIR/explain-unreachable-pats.rs:70:9
    |
 LL |         (true, _) => {}
    |         --------- matches some of the same values
@@ -83,7 +83,7 @@ LL |         (_, true) => {}
    |         ^^^^^^^^^ collectively making this unreachable
 
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:84:9
+  --> $DIR/explain-unreachable-pats.rs:83:9
    |
 LL |         (true, _) => {}
    |         --------- matches all the values already
@@ -92,7 +92,7 @@ LL |         (true, true) => {}
    |         ^^^^^^^^^^^^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/explain-unreachable-pats.rs:96:9
+  --> $DIR/explain-unreachable-pats.rs:95:9
    |
 LL |         (_, true, 0..10) => {}
    |         ---------------- matches all the values already
diff --git a/tests/ui/pattern/usefulness/impl-trait.rs b/tests/ui/pattern/usefulness/impl-trait.rs
index 1fec9a2633e..c1cc279f74c 100644
--- a/tests/ui/pattern/usefulness/impl-trait.rs
+++ b/tests/ui/pattern/usefulness/impl-trait.rs
@@ -1,5 +1,4 @@
 #![feature(never_type)]
-#![feature(min_exhaustive_patterns)]
 #![feature(type_alias_impl_trait)]
 #![feature(non_exhaustive_omitted_patterns_lint)]
 #![deny(unreachable_patterns)]
diff --git a/tests/ui/pattern/usefulness/impl-trait.stderr b/tests/ui/pattern/usefulness/impl-trait.stderr
index c079f5a259d..92932e48538 100644
--- a/tests/ui/pattern/usefulness/impl-trait.stderr
+++ b/tests/ui/pattern/usefulness/impl-trait.stderr
@@ -1,18 +1,18 @@
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:17:13
+  --> $DIR/impl-trait.rs:16:13
    |
 LL |             _ => {}
    |             ^
    |
    = note: this pattern matches no values because `Void` is uninhabited
 note: the lint level is defined here
-  --> $DIR/impl-trait.rs:5:9
+  --> $DIR/impl-trait.rs:4:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:31:13
+  --> $DIR/impl-trait.rs:30:13
    |
 LL |             _ => {}
    |             ^
@@ -20,7 +20,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:45:13
+  --> $DIR/impl-trait.rs:44:13
    |
 LL |             Some(_) => {}
    |             ^^^^^^^
@@ -28,7 +28,7 @@ LL |             Some(_) => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:49:13
+  --> $DIR/impl-trait.rs:48:13
    |
 LL |             None => {}
    |             ---- matches all the values already
@@ -36,7 +36,7 @@ LL |             _ => {}
    |             ^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:59:13
+  --> $DIR/impl-trait.rs:58:13
    |
 LL |             Some(_) => {}
    |             ^^^^^^^
@@ -44,7 +44,7 @@ LL |             Some(_) => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:63:13
+  --> $DIR/impl-trait.rs:62:13
    |
 LL |             None => {}
    |             ---- matches all the values already
@@ -52,7 +52,7 @@ LL |             _ => {}
    |             ^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:76:9
+  --> $DIR/impl-trait.rs:75:9
    |
 LL |         _ => {}
    |         ^
@@ -60,7 +60,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:86:9
+  --> $DIR/impl-trait.rs:85:9
    |
 LL |         _ => {}
    |         - matches any value
@@ -68,7 +68,7 @@ LL |         Some((a, b)) => {}
    |         ^^^^^^^^^^^^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:94:13
+  --> $DIR/impl-trait.rs:93:13
    |
 LL |             _ => {}
    |             ^
@@ -76,7 +76,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:105:9
+  --> $DIR/impl-trait.rs:104:9
    |
 LL |         Some((a, b)) => {}
    |         ------------ matches all the values already
@@ -84,7 +84,7 @@ LL |         Some((mut x, mut y)) => {
    |         ^^^^^^^^^^^^^^^^^^^^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:124:13
+  --> $DIR/impl-trait.rs:123:13
    |
 LL |             _ => {}
    |             - matches any value
@@ -92,7 +92,7 @@ LL |             Rec { n: 0, w: Some(Rec { n: 0, w: _ }) } => {}
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:138:13
+  --> $DIR/impl-trait.rs:137:13
    |
 LL |             _ => {}
    |             ^
@@ -100,7 +100,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `SecretelyVoid` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/impl-trait.rs:151:13
+  --> $DIR/impl-trait.rs:150:13
    |
 LL |             _ => {}
    |             ^
@@ -108,7 +108,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `SecretelyDoubleVoid` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `impl Copy` is non-empty
-  --> $DIR/impl-trait.rs:23:11
+  --> $DIR/impl-trait.rs:22:11
    |
 LL |     match return_never_rpit(x) {}
    |           ^^^^^^^^^^^^^^^^^^^^
@@ -122,7 +122,7 @@ LL +     }
    |
 
 error[E0004]: non-exhaustive patterns: type `T` is non-empty
-  --> $DIR/impl-trait.rs:37:11
+  --> $DIR/impl-trait.rs:36:11
    |
 LL |     match return_never_tait(x) {}
    |           ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/pattern/usefulness/match-privately-empty.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/match-privately-empty.exhaustive_patterns.stderr
index 261a4b3353f..463e104f970 100644
--- a/tests/ui/pattern/usefulness/match-privately-empty.exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/match-privately-empty.exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered
-  --> $DIR/match-privately-empty.rs:15:11
+  --> $DIR/match-privately-empty.rs:14:11
    |
 LL |     match private::DATA {
    |           ^^^^^^^^^^^^^ pattern `Some(Private { misc: true, .. })` not covered
diff --git a/tests/ui/pattern/usefulness/match-privately-empty.normal.stderr b/tests/ui/pattern/usefulness/match-privately-empty.normal.stderr
new file mode 100644
index 00000000000..463e104f970
--- /dev/null
+++ b/tests/ui/pattern/usefulness/match-privately-empty.normal.stderr
@@ -0,0 +1,21 @@
+error[E0004]: non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered
+  --> $DIR/match-privately-empty.rs:14:11
+   |
+LL |     match private::DATA {
+   |           ^^^^^^^^^^^^^ pattern `Some(Private { misc: true, .. })` not covered
+   |
+note: `Option<Private>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+  ::: $SRC_DIR/core/src/option.rs:LL:COL
+   |
+   = note: not covered
+   = note: the matched value is of type `Option<Private>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Some(private::Private { misc: false, .. }) => {},
+LL +         Some(Private { misc: true, .. }) => todo!()
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/match-privately-empty.rs b/tests/ui/pattern/usefulness/match-privately-empty.rs
index 7e1d0dc48f2..bfea15af180 100644
--- a/tests/ui/pattern/usefulness/match-privately-empty.rs
+++ b/tests/ui/pattern/usefulness/match-privately-empty.rs
@@ -1,6 +1,5 @@
-//@ revisions: min_exhaustive_patterns exhaustive_patterns
+//@ revisions: normal exhaustive_patterns
 #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
-#![cfg_attr(min_exhaustive_patterns, feature(min_exhaustive_patterns))]
 #![feature(never_type)]
 
 mod private {
diff --git a/tests/ui/pattern/usefulness/slice_of_empty.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/slice_of_empty.exhaustive_patterns.stderr
index e5e581447e6..c4fcd67cfdb 100644
--- a/tests/ui/pattern/usefulness/slice_of_empty.exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/slice_of_empty.exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: `&[]` not covered
-  --> $DIR/slice_of_empty.rs:21:11
+  --> $DIR/slice_of_empty.rs:20:11
    |
 LL |     match nevers {
    |           ^^^^^^ pattern `&[]` not covered
diff --git a/tests/ui/pattern/usefulness/slice_of_empty.normal.stderr b/tests/ui/pattern/usefulness/slice_of_empty.normal.stderr
new file mode 100644
index 00000000000..c9afd1bfc90
--- /dev/null
+++ b/tests/ui/pattern/usefulness/slice_of_empty.normal.stderr
@@ -0,0 +1,30 @@
+error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
+  --> $DIR/slice_of_empty.rs:9:11
+   |
+LL |     match nevers {
+   |           ^^^^^^ pattern `&[_, ..]` not covered
+   |
+   = note: the matched value is of type `&[!]`
+   = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         &[] => (),
+LL ~         &[_, ..] => todo!(),
+   |
+
+error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
+  --> $DIR/slice_of_empty.rs:20:11
+   |
+LL |     match nevers {
+   |           ^^^^^^ patterns `&[]` and `&[_, _, ..]` not covered
+   |
+   = note: the matched value is of type `&[!]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         &[_] => (),
+LL ~         &[] | &[_, _, ..] => todo!(),
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/slice_of_empty.rs b/tests/ui/pattern/usefulness/slice_of_empty.rs
index 785fccaabf7..e186ba5134d 100644
--- a/tests/ui/pattern/usefulness/slice_of_empty.rs
+++ b/tests/ui/pattern/usefulness/slice_of_empty.rs
@@ -1,6 +1,5 @@
-//@ revisions: min_exhaustive_patterns exhaustive_patterns
+//@ revisions: normal exhaustive_patterns
 #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
-#![cfg_attr(min_exhaustive_patterns, feature(min_exhaustive_patterns))]
 #![feature(never_type)]
 #![deny(unreachable_patterns)]
 
@@ -8,7 +7,7 @@ fn main() {}
 
 fn foo(nevers: &[!]) {
     match nevers {
-        //[min_exhaustive_patterns]~^ ERROR non-exhaustive patterns: `&[_, ..]` not covered
+        //[normal]~^ ERROR non-exhaustive patterns: `&[_, ..]` not covered
         &[] => (),
     };
 
@@ -20,7 +19,7 @@ fn foo(nevers: &[!]) {
 
     match nevers {
         //[exhaustive_patterns]~^ ERROR non-exhaustive patterns: `&[]` not covered
-        //[min_exhaustive_patterns]~^^ ERROR non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
+        //[normal]~^^ ERROR non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
         &[_] => (),
     };
 }
diff --git a/tests/ui/pattern/usefulness/uninhabited.rs b/tests/ui/pattern/usefulness/uninhabited.rs
index 72e602ee8d2..5c774b7874a 100644
--- a/tests/ui/pattern/usefulness/uninhabited.rs
+++ b/tests/ui/pattern/usefulness/uninhabited.rs
@@ -5,7 +5,6 @@
 // `Ty::is_inhabited_from` function.
 #![feature(never_type)]
 #![feature(never_type_fallback)]
-#![feature(min_exhaustive_patterns)]
 #![deny(unreachable_patterns)]
 
 macro_rules! assert_empty {
diff --git a/tests/ui/reachable/unreachable-loop-patterns.rs b/tests/ui/reachable/unreachable-loop-patterns.rs
index 4294a18ba44..d074e3a6ece 100644
--- a/tests/ui/reachable/unreachable-loop-patterns.rs
+++ b/tests/ui/reachable/unreachable-loop-patterns.rs
@@ -1,6 +1,4 @@
 #![feature(never_type, never_type_fallback)]
-#![feature(min_exhaustive_patterns)]
-
 #![allow(unreachable_code)]
 #![deny(unreachable_patterns)]
 
diff --git a/tests/ui/reachable/unreachable-loop-patterns.stderr b/tests/ui/reachable/unreachable-loop-patterns.stderr
index bdd9b5ee411..9b7c2ba4acd 100644
--- a/tests/ui/reachable/unreachable-loop-patterns.stderr
+++ b/tests/ui/reachable/unreachable-loop-patterns.stderr
@@ -1,12 +1,12 @@
 error: unreachable pattern
-  --> $DIR/unreachable-loop-patterns.rs:18:9
+  --> $DIR/unreachable-loop-patterns.rs:16:9
    |
 LL |     for _ in unimplemented!() as Void {}
    |         ^
    |
    = note: this pattern matches no values because `Void` is uninhabited
 note: the lint level is defined here
-  --> $DIR/unreachable-loop-patterns.rs:5:9
+  --> $DIR/unreachable-loop-patterns.rs:3:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/check.rs b/tests/ui/rfcs/rfc-0000-never_patterns/check.rs
index dc13dd05fa6..77f79003edc 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/check.rs
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/check.rs
@@ -11,22 +11,22 @@ macro_rules! never {
 }
 
 fn no_arms_or_guards(x: Void) {
-    match None::<Void> {
+    match &None::<Void> {
         Some(!) => {}
         //~^ ERROR a never pattern is always unreachable
         None => {}
     }
-    match None::<Void> { //~ ERROR: `Some(!)` not covered
+    match &None::<Void> { //~ ERROR: `&Some(!)` not covered
         Some(!) if true,
         //~^ ERROR guard on a never pattern
         None => {}
     }
-    match None::<Void> { //~ ERROR: `Some(!)` not covered
+    match &None::<Void> { //~ ERROR: `&Some(!)` not covered
         Some(!) if true => {}
         //~^ ERROR a never pattern is always unreachable
         None => {}
     }
-    match None::<Void> {
+    match &None::<Void> {
         Some(never!()) => {}
         //~^ ERROR a never pattern is always unreachable
         None => {}
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr
index fbf7aa02ac2..4622ea59b54 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr
@@ -31,40 +31,42 @@ LL |         Some(never!()) => {}
    |                           this will never be executed
    |                           help: remove this expression
 
-error[E0004]: non-exhaustive patterns: `Some(!)` not covered
+error[E0004]: non-exhaustive patterns: `&Some(!)` not covered
   --> $DIR/check.rs:19:11
    |
-LL |     match None::<Void> {
-   |           ^^^^^^^^^^^^ pattern `Some(!)` not covered
+LL |     match &None::<Void> {
+   |           ^^^^^^^^^^^^^ pattern `&Some(!)` not covered
    |
 note: `Option<Void>` defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
   ::: $SRC_DIR/core/src/option.rs:LL:COL
    |
    = note: not covered
-   = note: the matched value is of type `Option<Void>`
+   = note: the matched value is of type `&Option<Void>`
+   = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None => {},
-LL +         Some(!)
+LL +         &Some(!)
    |
 
-error[E0004]: non-exhaustive patterns: `Some(!)` not covered
+error[E0004]: non-exhaustive patterns: `&Some(!)` not covered
   --> $DIR/check.rs:24:11
    |
-LL |     match None::<Void> {
-   |           ^^^^^^^^^^^^ pattern `Some(!)` not covered
+LL |     match &None::<Void> {
+   |           ^^^^^^^^^^^^^ pattern `&Some(!)` not covered
    |
 note: `Option<Void>` defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
   ::: $SRC_DIR/core/src/option.rs:LL:COL
    |
    = note: not covered
-   = note: the matched value is of type `Option<Void>`
+   = note: the matched value is of type `&Option<Void>`
+   = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         None => {},
-LL +         Some(!)
+LL +         &Some(!)
    |
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/typeck.fail.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/typeck.fail.stderr
index 013a8b53a55..9e2ae2846d5 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/typeck.fail.stderr
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/typeck.fail.stderr
@@ -1,5 +1,5 @@
 error: mismatched types
-  --> $DIR/typeck.rs:25:9
+  --> $DIR/typeck.rs:24:9
    |
 LL |         !,
    |         ^ a never pattern must be used on an uninhabited type
@@ -7,7 +7,7 @@ LL |         !,
    = note: the matched value is of type `()`
 
 error: mismatched types
-  --> $DIR/typeck.rs:29:9
+  --> $DIR/typeck.rs:28:9
    |
 LL |         !,
    |         ^ a never pattern must be used on an uninhabited type
@@ -15,7 +15,7 @@ LL |         !,
    = note: the matched value is of type `(i32, bool)`
 
 error: mismatched types
-  --> $DIR/typeck.rs:33:13
+  --> $DIR/typeck.rs:32:13
    |
 LL |         (_, !),
    |             ^ a never pattern must be used on an uninhabited type
@@ -23,7 +23,7 @@ LL |         (_, !),
    = note: the matched value is of type `bool`
 
 error: mismatched types
-  --> $DIR/typeck.rs:38:14
+  --> $DIR/typeck.rs:37:14
    |
 LL |         Some(!),
    |              ^ a never pattern must be used on an uninhabited type
@@ -31,7 +31,7 @@ LL |         Some(!),
    = note: the matched value is of type `i32`
 
 error: mismatched types
-  --> $DIR/typeck.rs:45:9
+  --> $DIR/typeck.rs:44:9
    |
 LL |         !,
    |         ^ a never pattern must be used on an uninhabited type
@@ -39,7 +39,7 @@ LL |         !,
    = note: the matched value is of type `()`
 
 error: mismatched types
-  --> $DIR/typeck.rs:52:9
+  --> $DIR/typeck.rs:51:9
    |
 LL |         !,
    |         ^ a never pattern must be used on an uninhabited type
@@ -47,7 +47,7 @@ LL |         !,
    = note: the matched value is of type `Option<Void>`
 
 error: mismatched types
-  --> $DIR/typeck.rs:57:9
+  --> $DIR/typeck.rs:56:9
    |
 LL |         !,
    |         ^ a never pattern must be used on an uninhabited type
@@ -55,7 +55,7 @@ LL |         !,
    = note: the matched value is of type `[Void]`
 
 error: mismatched types
-  --> $DIR/typeck.rs:63:9
+  --> $DIR/typeck.rs:62:9
    |
 LL |         !,
    |         ^ a never pattern must be used on an uninhabited type
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs b/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs
index 8300f953dc1..bf74b282f6c 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs
@@ -2,7 +2,6 @@
 //@[pass] check-pass
 //@[fail] check-fail
 #![feature(never_patterns)]
-#![feature(min_exhaustive_patterns)]
 #![allow(incomplete_features)]
 
 #[derive(Copy, Clone)]
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr
index a875041d89c..d78f4a5f6eb 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.exh_pats.stderr
@@ -1,18 +1,18 @@
 error: unreachable pattern
-  --> $DIR/unreachable.rs:17:9
+  --> $DIR/unreachable.rs:16:9
    |
 LL |         Err(!),
    |         ^^^^^^
    |
    = note: this pattern matches no values because `Void` is uninhabited
 note: the lint level is defined here
-  --> $DIR/unreachable.rs:7:9
+  --> $DIR/unreachable.rs:6:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/unreachable.rs:20:19
+  --> $DIR/unreachable.rs:19:19
    |
 LL |     let (Ok(_x) | Err(!)) = res_void;
    |                   ^^^^^^
@@ -20,7 +20,7 @@ LL |     let (Ok(_x) | Err(!)) = res_void;
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/unreachable.rs:22:12
+  --> $DIR/unreachable.rs:21:12
    |
 LL |     if let Err(!) = res_void {}
    |            ^^^^^^
@@ -28,7 +28,7 @@ LL |     if let Err(!) = res_void {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/unreachable.rs:24:24
+  --> $DIR/unreachable.rs:23:24
    |
 LL |     if let (Ok(true) | Err(!)) = res_void {}
    |                        ^^^^^^
@@ -36,7 +36,7 @@ LL |     if let (Ok(true) | Err(!)) = res_void {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/unreachable.rs:26:23
+  --> $DIR/unreachable.rs:25:23
    |
 LL |     for (Ok(mut _x) | Err(!)) in [res_void] {}
    |                       ^^^^^^
@@ -44,7 +44,7 @@ LL |     for (Ok(mut _x) | Err(!)) in [res_void] {}
    = note: this pattern matches no values because `Void` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/unreachable.rs:30:18
+  --> $DIR/unreachable.rs:29:18
    |
 LL | fn foo((Ok(_x) | Err(!)): Result<bool, Void>) {}
    |                  ^^^^^^
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.normal.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.normal.stderr
new file mode 100644
index 00000000000..a3bf8e80ece
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.normal.stderr
@@ -0,0 +1,44 @@
+error: unreachable pattern
+  --> $DIR/unreachable.rs:16:9
+   |
+LL |         Err(!),
+   |         ^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unreachable.rs:6:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:19:19
+   |
+LL |     let (Ok(_x) | Err(!)) = res_void;
+   |                   ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:21:12
+   |
+LL |     if let Err(!) = res_void {}
+   |            ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:23:24
+   |
+LL |     if let (Ok(true) | Err(!)) = res_void {}
+   |                        ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:25:23
+   |
+LL |     for (Ok(mut _x) | Err(!)) in [res_void] {}
+   |                       ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:29:18
+   |
+LL | fn foo((Ok(_x) | Err(!)): Result<bool, Void>) {}
+   |                  ^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs
index 4d20c67cf0f..f68da4aa173 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs
@@ -1,8 +1,5 @@
-//@ revisions: normal exh_pats
-//@[normal] check-pass
 #![feature(never_patterns)]
 #![allow(incomplete_features)]
-#![cfg_attr(exh_pats, feature(min_exhaustive_patterns))]
 #![allow(dead_code, unreachable_code)]
 #![deny(unreachable_patterns)]
 
@@ -15,17 +12,17 @@ fn main() {
     match res_void {
         Ok(_x) => {}
         Err(!),
-        //[exh_pats]~^ ERROR unreachable
+        //~^ ERROR unreachable
     }
     let (Ok(_x) | Err(!)) = res_void;
-    //[exh_pats]~^ ERROR unreachable
+    //~^ ERROR unreachable
     if let Err(!) = res_void {}
-    //[exh_pats]~^ ERROR unreachable
+    //~^ ERROR unreachable
     if let (Ok(true) | Err(!)) = res_void {}
-    //[exh_pats]~^ ERROR unreachable
+    //~^ ERROR unreachable
     for (Ok(mut _x) | Err(!)) in [res_void] {}
-    //[exh_pats]~^ ERROR unreachable
+    //~^ ERROR unreachable
 }
 
 fn foo((Ok(_x) | Err(!)): Result<bool, Void>) {}
-//[exh_pats]~^ ERROR unreachable
+//~^ ERROR unreachable
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.stderr
new file mode 100644
index 00000000000..79b640d9f41
--- /dev/null
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.stderr
@@ -0,0 +1,55 @@
+error: unreachable pattern
+  --> $DIR/unreachable.rs:14:9
+   |
+LL |         Err(!),
+   |         ^^^^^^
+   |
+   = note: this pattern matches no values because `Void` is uninhabited
+note: the lint level is defined here
+  --> $DIR/unreachable.rs:4:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:17:19
+   |
+LL |     let (Ok(_x) | Err(!)) = res_void;
+   |                   ^^^^^^
+   |
+   = note: this pattern matches no values because `Void` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:19:12
+   |
+LL |     if let Err(!) = res_void {}
+   |            ^^^^^^
+   |
+   = note: this pattern matches no values because `Void` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:21:24
+   |
+LL |     if let (Ok(true) | Err(!)) = res_void {}
+   |                        ^^^^^^
+   |
+   = note: this pattern matches no values because `Void` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:23:23
+   |
+LL |     for (Ok(mut _x) | Err(!)) in [res_void] {}
+   |                       ^^^^^^
+   |
+   = note: this pattern matches no values because `Void` is uninhabited
+
+error: unreachable pattern
+  --> $DIR/unreachable.rs:27:18
+   |
+LL | fn foo((Ok(_x) | Err(!)): Result<bool, Void>) {}
+   |                  ^^^^^^
+   |
+   = note: this pattern matches no values because `Void` is uninhabited
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs
index 8f090fe886a..d81896eba19 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs
@@ -1,3 +1,4 @@
+//@ check-pass
 #![feature(never_type)]
 
 #[non_exhaustive]
@@ -28,24 +29,24 @@ pub struct IndirectUninhabitedVariants(UninhabitedVariants);
 struct A;
 
 // This test checks that an empty match on a non-exhaustive uninhabited type through a level of
-// indirection from the defining crate will not compile without `#![feature(exhaustive_patterns)]`.
+// indirection from the defining crate compiles.
 
 fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A {
-    match x {} //~ ERROR non-exhaustive patterns
+    match x {}
 }
 
 fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A {
-    match x {} //~ ERROR non-exhaustive patterns
+    match x {}
 }
 
 fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A {
-    match x {} //~ ERROR non-exhaustive patterns
+    match x {}
 }
 
 fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(
     x: IndirectUninhabitedVariants,
 ) -> A {
-    match x {} //~ ERROR non-exhaustive patterns
+    match x {}
 }
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
deleted file mode 100644
index c1219054140..00000000000
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
+++ /dev/null
@@ -1,79 +0,0 @@
-error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty
-  --> $DIR/indirect_match_same_crate.rs:34:11
-   |
-LL |     match x {}
-   |           ^
-   |
-note: `IndirectUninhabitedEnum` defined here
-  --> $DIR/indirect_match_same_crate.rs:20:12
-   |
-LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
-   |            ^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `IndirectUninhabitedEnum`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match x {
-LL +         _ => todo!(),
-LL ~     }
-   |
-
-error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
-  --> $DIR/indirect_match_same_crate.rs:38:11
-   |
-LL |     match x {}
-   |           ^
-   |
-note: `IndirectUninhabitedStruct` defined here
-  --> $DIR/indirect_match_same_crate.rs:22:12
-   |
-LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `IndirectUninhabitedStruct`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match x {
-LL +         _ => todo!(),
-LL ~     }
-   |
-
-error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
-  --> $DIR/indirect_match_same_crate.rs:42:11
-   |
-LL |     match x {}
-   |           ^
-   |
-note: `IndirectUninhabitedTupleStruct` defined here
-  --> $DIR/indirect_match_same_crate.rs:24:12
-   |
-LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `IndirectUninhabitedTupleStruct`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match x {
-LL +         _ => todo!(),
-LL ~     }
-   |
-
-error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
-  --> $DIR/indirect_match_same_crate.rs:48:11
-   |
-LL |     match x {}
-   |           ^
-   |
-note: `IndirectUninhabitedVariants` defined here
-  --> $DIR/indirect_match_same_crate.rs:26:12
-   |
-LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `IndirectUninhabitedVariants`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match x {
-LL +         _ => todo!(),
-LL ~     }
-   |
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs
index c40a2676e84..dd9a570522a 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs
@@ -1,6 +1,5 @@
 //@ aux-build:uninhabited.rs
 #![deny(unreachable_patterns)]
-#![feature(min_exhaustive_patterns)]
 #![feature(never_type)]
 
 extern crate uninhabited;
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
index ef97c1fa17f..745b196a0e3 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty
-  --> $DIR/indirect_match_with_exhaustive_patterns.rs:23:11
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:22:11
    |
 LL |     match x {}
    |           ^
@@ -18,7 +18,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
-  --> $DIR/indirect_match_with_exhaustive_patterns.rs:27:11
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:26:11
    |
 LL |     match x {}
    |           ^
@@ -37,7 +37,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
-  --> $DIR/indirect_match_with_exhaustive_patterns.rs:31:11
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:30:11
    |
 LL |     match x {}
    |           ^
@@ -56,7 +56,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
-  --> $DIR/indirect_match_with_exhaustive_patterns.rs:37:11
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:36:11
    |
 LL |     match x {}
    |           ^
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs
index efaec0ebdbe..32f5f504136 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs
@@ -1,7 +1,6 @@
 //@ check-pass
 
 #![deny(unreachable_patterns)]
-#![feature(min_exhaustive_patterns)]
 #![feature(never_type)]
 
 #[non_exhaustive]
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs
index ebbdfba15f3..04f7fe26b5a 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs
@@ -1,3 +1,4 @@
+//@ check-pass
 #![feature(never_type)]
 
 #[non_exhaustive]
@@ -27,15 +28,15 @@ fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A {
 }
 
 fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
-    match x {} //~ ERROR non-exhaustive patterns
+    match x {}
 }
 
 fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
-    match x {} //~ ERROR non-exhaustive patterns
+    match x {}
 }
 
 fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
-    match x {} //~ ERROR non-exhaustive patterns
+    match x {}
 }
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
deleted file mode 100644
index 7a12aca8520..00000000000
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
+++ /dev/null
@@ -1,64 +0,0 @@
-error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
-  --> $DIR/match_same_crate.rs:30:11
-   |
-LL |     match x {}
-   |           ^
-   |
-note: `UninhabitedStruct` defined here
-  --> $DIR/match_same_crate.rs:8:12
-   |
-LL | pub struct UninhabitedStruct {
-   |            ^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `UninhabitedStruct`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match x {
-LL +         _ => todo!(),
-LL ~     }
-   |
-
-error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
-  --> $DIR/match_same_crate.rs:34:11
-   |
-LL |     match x {}
-   |           ^
-   |
-note: `UninhabitedTupleStruct` defined here
-  --> $DIR/match_same_crate.rs:13:12
-   |
-LL | pub struct UninhabitedTupleStruct(!);
-   |            ^^^^^^^^^^^^^^^^^^^^^^
-   = note: the matched value is of type `UninhabitedTupleStruct`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match x {
-LL +         _ => todo!(),
-LL ~     }
-   |
-
-error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
-  --> $DIR/match_same_crate.rs:38:11
-   |
-LL |     match x {}
-   |           ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
-   |
-note: `UninhabitedVariants` defined here
-  --> $DIR/match_same_crate.rs:15:10
-   |
-LL | pub enum UninhabitedVariants {
-   |          ^^^^^^^^^^^^^^^^^^^
-LL |     #[non_exhaustive] Tuple(!),
-   |                       ----- not covered
-LL |     #[non_exhaustive] Struct { x: ! }
-   |                       ------ not covered
-   = note: the matched value is of type `UninhabitedVariants`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
-   |
-LL ~     match x {
-LL +         UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(),
-LL ~     }
-   |
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs
index 69b15fca0b7..108cac7099e 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs
@@ -1,6 +1,5 @@
 //@ aux-build:uninhabited.rs
 #![deny(unreachable_patterns)]
-#![feature(min_exhaustive_patterns)]
 #![feature(never_type)]
 
 extern crate uninhabited;
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
index 19e2546b0da..0c8b14ab69d 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty
-  --> $DIR/match_with_exhaustive_patterns.rs:22:11
+  --> $DIR/match_with_exhaustive_patterns.rs:21:11
    |
 LL |     match x {}
    |           ^
@@ -18,7 +18,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
-  --> $DIR/match_with_exhaustive_patterns.rs:26:11
+  --> $DIR/match_with_exhaustive_patterns.rs:25:11
    |
 LL |     match x {}
    |           ^
@@ -37,7 +37,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
-  --> $DIR/match_with_exhaustive_patterns.rs:30:11
+  --> $DIR/match_with_exhaustive_patterns.rs:29:11
    |
 LL |     match x {}
    |           ^
@@ -56,7 +56,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
-  --> $DIR/match_with_exhaustive_patterns.rs:34:11
+  --> $DIR/match_with_exhaustive_patterns.rs:33:11
    |
 LL |     match x {}
    |           ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
index bbc5d03d612..468703c78e0 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
@@ -1,7 +1,6 @@
 //@ check-pass
 
 #![deny(unreachable_patterns)]
-#![feature(min_exhaustive_patterns)]
 #![feature(never_type)]
 
 #[non_exhaustive]
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs
index 0007614988c..be55ad51578 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns.rs
@@ -1,7 +1,6 @@
 //@ aux-build:uninhabited.rs
 //@ build-pass (FIXME(62277): could be check-pass?)
 #![deny(unreachable_patterns)]
-#![feature(min_exhaustive_patterns)]
 
 extern crate uninhabited;
 
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs
index 898be87ccca..1194d7b858d 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs
@@ -1,5 +1,4 @@
 #![deny(unreachable_patterns)]
-#![feature(min_exhaustive_patterns)]
 #![feature(never_type)]
 
 #[non_exhaustive]
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr
index d5192a70ed5..c399bb9083f 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr
@@ -1,5 +1,5 @@
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:52:9
+  --> $DIR/patterns_same_crate.rs:51:9
    |
 LL |         Some(_x) => (),
    |         ^^^^^^^^
@@ -12,7 +12,7 @@ LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:57:9
+  --> $DIR/patterns_same_crate.rs:56:9
    |
 LL |         Some(_x) => (),
    |         ^^^^^^^^
@@ -20,7 +20,7 @@ LL |         Some(_x) => (),
    = note: this pattern matches no values because `UninhabitedVariants` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:61:15
+  --> $DIR/patterns_same_crate.rs:60:15
    |
 LL |     while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -28,7 +28,7 @@ LL |     while let PartiallyInhabitedVariants::Struct { x } = partially_inhabite
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:65:15
+  --> $DIR/patterns_same_crate.rs:64:15
    |
 LL |     while let Some(_x) = uninhabited_struct() {
    |               ^^^^^^^^
@@ -36,7 +36,7 @@ LL |     while let Some(_x) = uninhabited_struct() {
    = note: this pattern matches no values because `UninhabitedStruct` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:68:15
+  --> $DIR/patterns_same_crate.rs:67:15
    |
 LL |     while let Some(_x) = uninhabited_tuple_struct() {
    |               ^^^^^^^^
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr
index 9d1ca5dbf2c..b451555ec3c 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr
@@ -40,7 +40,7 @@ error: `~const` can only be applied to `#[const_trait]` traits
 LL | const fn a<T: ~const Destruct>(_: T) {}
    |                      ^^^^^^^^
 
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-drop.rs:54:5
    |
 LL |     #[const_trait]
@@ -49,7 +49,7 @@ LL |     pub trait SomeTrait {
 LL |         fn foo();
    |               - expected 0 const parameters
 
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-drop.rs:54:5
    |
 LL |     #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr
index 2f93f9a6743..296614f7fd0 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr
@@ -40,7 +40,7 @@ error: `~const` can only be applied to `#[const_trait]` traits
 LL | const fn a<T: ~const Destruct>(_: T) {}
    |                      ^^^^^^^^
 
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-drop.rs:54:5
    |
 LL |     #[const_trait]
@@ -49,7 +49,7 @@ LL |     pub trait SomeTrait {
 LL |         fn foo();
    |               - expected 0 const parameters
 
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-drop.rs:54:5
    |
 LL |     #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr
index b4c4cf0a890..7643697874f 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `bar` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-default-bound-non-const-specialized-bound.rs:16:1
    |
 LL | #[const_trait]
@@ -16,7 +16,7 @@ LL | |     T: Foo, //FIXME ~ ERROR missing `~const` qualifier
 LL | |     T: Specialize,
    | |__________________^
 
-error[E0049]: method `baz` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-default-bound-non-const-specialized-bound.rs:36:1
    |
 LL | #[const_trait]
@@ -25,7 +25,7 @@ LL | trait Baz {
 LL |     fn baz();
    |           - expected 0 const parameters
 
-error[E0049]: method `baz` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-default-bound-non-const-specialized-bound.rs:36:1
    |
 LL | #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr
index cabf201405f..9b2ae8d739c 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/const-default-const-specialized.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `value` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-default-const-specialized.rs:10:1
    |
 LL | #[const_trait]
@@ -7,7 +7,7 @@ LL | trait Value {
 LL |     fn value() -> u32;
    |             - expected 0 const parameters
 
-error[E0049]: method `value` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const-default-const-specialized.rs:10:1
    |
 LL | #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr
index 52c8708f2c8..18a25045f4b 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/default-keyword.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/default-keyword.rs:7:1
    |
 LL | #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr
index 1aa34637ca4..ecdc7b930e6 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/issue-95186-specialize-on-tilde-const.rs:14:1
    |
 LL | #[const_trait]
@@ -7,7 +7,7 @@ LL | trait Foo {
 LL |     fn foo();
    |           - expected 0 const parameters
 
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/issue-95186-specialize-on-tilde-const.rs:14:1
    |
 LL | #[const_trait]
@@ -18,7 +18,7 @@ LL |     fn foo();
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0049]: method `bar` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/issue-95186-specialize-on-tilde-const.rs:30:1
    |
 LL | #[const_trait]
@@ -27,7 +27,7 @@ LL | trait Bar {
 LL |     fn bar() {}
    |           - expected 0 const parameters
 
-error[E0049]: method `bar` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/issue-95186-specialize-on-tilde-const.rs:30:1
    |
 LL | #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr
index 0e0f391b086..6679bb46537 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `bar` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/issue-95187-same-trait-bound-different-constness.rs:18:1
    |
 LL | #[const_trait]
@@ -7,7 +7,7 @@ LL | trait Bar {
 LL |     fn bar();
    |           - expected 0 const parameters
 
-error[E0049]: method `bar` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/issue-95187-same-trait-bound-different-constness.rs:18:1
    |
 LL | #[const_trait]
@@ -18,7 +18,7 @@ LL |     fn bar();
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0049]: method `baz` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/issue-95187-same-trait-bound-different-constness.rs:38:1
    |
 LL | #[const_trait]
@@ -27,7 +27,7 @@ LL | trait Baz {
 LL |     fn baz();
    |           - expected 0 const parameters
 
-error[E0049]: method `baz` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/issue-95187-same-trait-bound-different-constness.rs:38:1
    |
 LL | #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr
index d49beb93259..7f363922947 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specialization/non-const-default-const-specialized.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `value` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/non-const-default-const-specialized.rs:9:1
    |
 LL | #[const_trait]
@@ -7,7 +7,7 @@ LL | trait Value {
 LL |     fn value() -> u32;
    |             - expected 0 const parameters
 
-error[E0049]: method `value` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/non-const-default-const-specialized.rs:9:1
    |
 LL | #[const_trait]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr
index d082cd6de60..bf273f349b4 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/specializing-constness-2.rs:9:1
    |
 LL | #[const_trait]
@@ -7,7 +7,7 @@ LL | pub trait A {
 LL |     fn a() -> u32;
    |         - expected 0 const parameters
 
-error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/specializing-constness-2.rs:9:1
    |
 LL | #[const_trait]
diff --git a/tests/ui/rust-2018/auxiliary/edition-lint-infer-outlives-macro.rs b/tests/ui/rust-2018/edition-lint-inter-outlives/auxiliary/edition-lint-infer-outlives-macro.rs
index d45fa10f022..d45fa10f022 100644
--- a/tests/ui/rust-2018/auxiliary/edition-lint-infer-outlives-macro.rs
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/auxiliary/edition-lint-infer-outlives-macro.rs
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.fixed b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.fixed
index 435857224ac..435857224ac 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.fixed
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.fixed
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.rs b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.rs
index 6c879231a16..6c879231a16 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.rs
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.rs
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.stderr b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.stderr
index d684911be39..d684911be39 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives-macro.stderr
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-macro.stderr
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives-multispan.rs b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-multispan.rs
index d2254acb33f..d2254acb33f 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives-multispan.rs
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-multispan.rs
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives-multispan.stderr b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-multispan.stderr
index 1f4190665b9..1f4190665b9 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives-multispan.stderr
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives-multispan.stderr
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives.fixed b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.fixed
index c4948051c18..c4948051c18 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives.fixed
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.fixed
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives.rs b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.rs
index c80e91ca12c..c80e91ca12c 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives.rs
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.rs
diff --git a/tests/ui/rust-2018/edition-lint-infer-outlives.stderr b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.stderr
index dbf301fd8a1..dbf301fd8a1 100644
--- a/tests/ui/rust-2018/edition-lint-infer-outlives.stderr
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/edition-lint-infer-outlives.stderr
diff --git a/tests/ui/rust-2018/edition-lint-inter-outlives/explicit-outlives-recursive-119228.fixed b/tests/ui/rust-2018/edition-lint-inter-outlives/explicit-outlives-recursive-119228.fixed
new file mode 100644
index 00000000000..7b9fac8f408
--- /dev/null
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/explicit-outlives-recursive-119228.fixed
@@ -0,0 +1,41 @@
+//@ run-rustfix
+//@ check-pass
+#![deny(explicit_outlives_requirements)]
+
+pub trait TypeCx {
+    type Ty;
+}
+
+pub struct Pat<Cx: TypeCx> {
+    pub ty: Cx::Ty,
+}
+
+// Simple recursive case: no warning
+pub struct MyTypeContextSimpleRecursive<'thir, 'tcx: 'thir> {
+    pub pat: Pat<MyTypeContextSimpleRecursive<'thir, 'tcx>>,
+}
+impl<'thir, 'tcx: 'thir> TypeCx for MyTypeContextSimpleRecursive<'thir, 'tcx> {
+    type Ty = ();
+}
+
+// Non-recursive case: we want a warning
+pub struct MyTypeContextNotRecursive<'thir, 'tcx: 'thir> {
+    pub tcx: &'tcx (),
+    pub thir: &'thir (),
+}
+impl<'thir, 'tcx: 'thir> TypeCx for MyTypeContextNotRecursive<'thir, 'tcx> {
+    type Ty = ();
+}
+
+
+// Mixed-recursive case: we want a warning
+pub struct MyTypeContextMixedRecursive<'thir, 'tcx: 'thir> {
+    pub pat: Pat<MyTypeContextMixedRecursive<'thir, 'tcx>>,
+    pub tcx: &'tcx (),
+    pub thir: &'thir (),
+}
+impl<'thir, 'tcx: 'thir> TypeCx for MyTypeContextMixedRecursive<'thir, 'tcx> {
+    type Ty = ();
+}
+
+fn main() {}
diff --git a/tests/ui/rust-2018/edition-lint-inter-outlives/explicit-outlives-recursive-119228.rs b/tests/ui/rust-2018/edition-lint-inter-outlives/explicit-outlives-recursive-119228.rs
new file mode 100644
index 00000000000..7b9fac8f408
--- /dev/null
+++ b/tests/ui/rust-2018/edition-lint-inter-outlives/explicit-outlives-recursive-119228.rs
@@ -0,0 +1,41 @@
+//@ run-rustfix
+//@ check-pass
+#![deny(explicit_outlives_requirements)]
+
+pub trait TypeCx {
+    type Ty;
+}
+
+pub struct Pat<Cx: TypeCx> {
+    pub ty: Cx::Ty,
+}
+
+// Simple recursive case: no warning
+pub struct MyTypeContextSimpleRecursive<'thir, 'tcx: 'thir> {
+    pub pat: Pat<MyTypeContextSimpleRecursive<'thir, 'tcx>>,
+}
+impl<'thir, 'tcx: 'thir> TypeCx for MyTypeContextSimpleRecursive<'thir, 'tcx> {
+    type Ty = ();
+}
+
+// Non-recursive case: we want a warning
+pub struct MyTypeContextNotRecursive<'thir, 'tcx: 'thir> {
+    pub tcx: &'tcx (),
+    pub thir: &'thir (),
+}
+impl<'thir, 'tcx: 'thir> TypeCx for MyTypeContextNotRecursive<'thir, 'tcx> {
+    type Ty = ();
+}
+
+
+// Mixed-recursive case: we want a warning
+pub struct MyTypeContextMixedRecursive<'thir, 'tcx: 'thir> {
+    pub pat: Pat<MyTypeContextMixedRecursive<'thir, 'tcx>>,
+    pub tcx: &'tcx (),
+    pub thir: &'thir (),
+}
+impl<'thir, 'tcx: 'thir> TypeCx for MyTypeContextMixedRecursive<'thir, 'tcx> {
+    type Ty = ();
+}
+
+fn main() {}
diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr
index e39138983c6..643f1de3e8d 100644
--- a/tests/ui/specialization/const_trait_impl.stderr
+++ b/tests/ui/specialization/const_trait_impl.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const_trait_impl.rs:6:1
    |
 LL | #[const_trait]
@@ -7,7 +7,7 @@ LL | pub unsafe trait Sup {
 LL |     fn foo() -> u32;
    |           - expected 0 const parameters
 
-error[E0049]: method `foo` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const_trait_impl.rs:6:1
    |
 LL | #[const_trait]
@@ -36,7 +36,7 @@ error: `~const` can only be applied to `#[const_trait]` traits
 LL | impl<T: ~const Default + ~const Sub> const A for T {
    |                ^^^^^^^
 
-error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const_trait_impl.rs:29:1
    |
 LL | #[const_trait]
@@ -45,7 +45,7 @@ LL | pub trait A {
 LL |     fn a() -> u32;
    |         - expected 0 const parameters
 
-error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const_trait_impl.rs:29:1
    |
 LL | #[const_trait]
@@ -56,7 +56,7 @@ LL |     fn a() -> u32;
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters
+error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
   --> $DIR/const_trait_impl.rs:29:1
    |
 LL | #[const_trait]
diff --git a/tests/ui/try-trait/try-operator-custom.rs b/tests/ui/try-trait/try-operator-custom.rs
index ab0772dd228..936c0b0689a 100644
--- a/tests/ui/try-trait/try-operator-custom.rs
+++ b/tests/ui/try-trait/try-operator-custom.rs
@@ -31,7 +31,6 @@ impl<U, V> Try for MyResult<U, V> {
 impl<U, V, W> FromResidual<MyResult<Never, V>> for MyResult<U, W> where V: Into<W> {
     fn from_residual(x: MyResult<Never, V>) -> Self {
         match x {
-            MyResult::Awesome(u) => match u {},
             MyResult::Terrible(e) => MyResult::Terrible(e.into()),
         }
     }
@@ -42,7 +41,6 @@ type ResultResidual<E> = Result<std::convert::Infallible, E>;
 impl<U, V, W> FromResidual<ResultResidual<V>> for MyResult<U, W> where V: Into<W> {
     fn from_residual(x: ResultResidual<V>) -> Self {
         match x {
-            Ok(v) => match v {}
             Err(e) => MyResult::Terrible(e.into()),
         }
     }
@@ -51,7 +49,6 @@ impl<U, V, W> FromResidual<ResultResidual<V>> for MyResult<U, W> where V: Into<W
 impl<U, V, W> FromResidual<MyResult<Never, V>> for Result<U, W> where V: Into<W> {
     fn from_residual(x: MyResult<Never, V>) -> Self {
         match x {
-            MyResult::Awesome(u) => match u {},
             MyResult::Terrible(e) => Err(e.into()),
         }
     }
diff --git a/tests/ui/typeck/issue-36708.stderr b/tests/ui/typeck/issue-36708.stderr
index 3589796b6aa..0aca575320f 100644
--- a/tests/ui/typeck/issue-36708.stderr
+++ b/tests/ui/typeck/issue-36708.stderr
@@ -1,4 +1,4 @@
-error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters
+error[E0049]: associated function `foo` has 1 type parameter but its trait declaration has 0 type parameters
   --> $DIR/issue-36708.rs:8:12
    |
 LL |     fn foo<T>() {}
diff --git a/tests/ui/uninhabited/exhaustive-wo-nevertype-issue-51221.rs b/tests/ui/uninhabited/exhaustive-wo-nevertype-issue-51221.rs
index 3130fb3fe9e..722d9b4ed29 100644
--- a/tests/ui/uninhabited/exhaustive-wo-nevertype-issue-51221.rs
+++ b/tests/ui/uninhabited/exhaustive-wo-nevertype-issue-51221.rs
@@ -1,7 +1,5 @@
 //@ check-pass
 
-#![feature(min_exhaustive_patterns)]
-
 enum Void {}
 fn main() {
     let a: Option<Void> = None;
diff --git a/tests/ui/uninhabited/uninhabited-irrefutable.exhaustive_patterns.stderr b/tests/ui/uninhabited/uninhabited-irrefutable.exhaustive_patterns.stderr
index bc1a9fa4191..50f33607c06 100644
--- a/tests/ui/uninhabited/uninhabited-irrefutable.exhaustive_patterns.stderr
+++ b/tests/ui/uninhabited/uninhabited-irrefutable.exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0005]: refutable pattern in local binding
-  --> $DIR/uninhabited-irrefutable.rs:31:9
+  --> $DIR/uninhabited-irrefutable.rs:30:9
    |
 LL |     let Foo::D(_y, _z) = x;
    |         ^^^^^^^^^^^^^^ pattern `Foo::A(_)` not covered
@@ -7,7 +7,7 @@ LL |     let Foo::D(_y, _z) = x;
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
 note: `Foo` defined here
-  --> $DIR/uninhabited-irrefutable.rs:20:6
+  --> $DIR/uninhabited-irrefutable.rs:19:6
    |
 LL | enum Foo {
    |      ^^^
diff --git a/tests/ui/uninhabited/uninhabited-irrefutable.normal.stderr b/tests/ui/uninhabited/uninhabited-irrefutable.normal.stderr
new file mode 100644
index 00000000000..50f33607c06
--- /dev/null
+++ b/tests/ui/uninhabited/uninhabited-irrefutable.normal.stderr
@@ -0,0 +1,26 @@
+error[E0005]: refutable pattern in local binding
+  --> $DIR/uninhabited-irrefutable.rs:30:9
+   |
+LL |     let Foo::D(_y, _z) = x;
+   |         ^^^^^^^^^^^^^^ pattern `Foo::A(_)` not covered
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Foo` defined here
+  --> $DIR/uninhabited-irrefutable.rs:19:6
+   |
+LL | enum Foo {
+   |      ^^^
+LL |
+LL |     A(foo::SecretlyEmpty),
+   |     - not covered
+   = note: pattern `Foo::A(_)` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
+   = note: the matched value is of type `Foo`
+help: you might want to use `let else` to handle the variant that isn't matched
+   |
+LL |     let Foo::D(_y, _z) = x else { todo!() };
+   |                            ++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0005`.
diff --git a/tests/ui/uninhabited/uninhabited-irrefutable.rs b/tests/ui/uninhabited/uninhabited-irrefutable.rs
index c1f4e5f8e27..cbaa9896003 100644
--- a/tests/ui/uninhabited/uninhabited-irrefutable.rs
+++ b/tests/ui/uninhabited/uninhabited-irrefutable.rs
@@ -1,6 +1,5 @@
-//@ revisions: min_exhaustive_patterns exhaustive_patterns
+//@ revisions: normal exhaustive_patterns
 #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
-#![cfg_attr(min_exhaustive_patterns, feature(min_exhaustive_patterns))]
 #![feature(never_type)]
 
 mod foo {
diff --git a/tests/ui/uninhabited/uninhabited-matches-feature-gated.rs b/tests/ui/uninhabited/uninhabited-matches-feature-gated.rs
index e804afcf9ed..1b158dd48e9 100644
--- a/tests/ui/uninhabited/uninhabited-matches-feature-gated.rs
+++ b/tests/ui/uninhabited/uninhabited-matches-feature-gated.rs
@@ -15,10 +15,10 @@ fn main() {
     let _ = match x {}; //~ ERROR non-exhaustive
 
     let x: (Void,) = unsafe { zeroed() };
-    let _ = match x {}; //~ ERROR non-exhaustive
+    let _ = match x {};
 
     let x: [Void; 1] = unsafe { zeroed() };
-    let _ = match x {}; //~ ERROR non-exhaustive
+    let _ = match x {};
 
     let x: &[Void] = unsafe { zeroed() };
     let _ = match x {   //~ ERROR non-exhaustive
@@ -29,11 +29,10 @@ fn main() {
     let _ = match x {}; // okay
 
     let x: Result<u32, Void> = Ok(23);
-    let _ = match x {   //~ ERROR non-exhaustive
+    let _ = match x {
         Ok(x) => x,
     };
 
     let x: Result<u32, Void> = Ok(23);
     let Ok(x) = x;
-    //~^ ERROR refutable
 }
diff --git a/tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr b/tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr
index 466d7f2eadb..2cd3c9375d0 100644
--- a/tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr
+++ b/tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr
@@ -36,34 +36,6 @@ LL +         _ => todo!(),
 LL ~     };
    |
 
-error[E0004]: non-exhaustive patterns: type `(Void,)` is non-empty
-  --> $DIR/uninhabited-matches-feature-gated.rs:18:19
-   |
-LL |     let _ = match x {};
-   |                   ^
-   |
-   = note: the matched value is of type `(Void,)`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     let _ = match x {
-LL +         _ => todo!(),
-LL ~     };
-   |
-
-error[E0004]: non-exhaustive patterns: type `[Void; 1]` is non-empty
-  --> $DIR/uninhabited-matches-feature-gated.rs:21:19
-   |
-LL |     let _ = match x {};
-   |                   ^
-   |
-   = note: the matched value is of type `[Void; 1]`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     let _ = match x {
-LL +         _ => todo!(),
-LL ~     };
-   |
-
 error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
   --> $DIR/uninhabited-matches-feature-gated.rs:24:19
    |
@@ -71,45 +43,13 @@ LL |     let _ = match x {
    |                   ^ pattern `&[_, ..]` not covered
    |
    = note: the matched value is of type `&[Void]`
+   = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         &[] => (),
 LL ~         &[_, ..] => todo!(),
    |
 
-error[E0004]: non-exhaustive patterns: `Err(_)` not covered
-  --> $DIR/uninhabited-matches-feature-gated.rs:32:19
-   |
-LL |     let _ = match x {
-   |                   ^ pattern `Err(_)` not covered
-   |
-note: `Result<u32, Void>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-   = note: not covered
-   = note: the matched value is of type `Result<u32, Void>`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
-   |
-LL ~         Ok(x) => x,
-LL ~         Err(_) => todo!(),
-   |
-
-error[E0005]: refutable pattern in local binding
-  --> $DIR/uninhabited-matches-feature-gated.rs:37:9
-   |
-LL |     let Ok(x) = x;
-   |         ^^^^^ pattern `Err(_)` not covered
-   |
-   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
-   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-   = note: the matched value is of type `Result<u32, Void>`
-help: you might want to use `let else` to handle the variant that isn't matched
-   |
-LL |     let Ok(x) = x else { todo!() };
-   |                   ++++++++++++++++
-
-error: aborting due to 7 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0004, E0005.
-For more information about an error, try `rustc --explain E0004`.
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/uninhabited/uninhabited-patterns.rs b/tests/ui/uninhabited/uninhabited-patterns.rs
index ae12c0fc4af..988383e691b 100644
--- a/tests/ui/uninhabited/uninhabited-patterns.rs
+++ b/tests/ui/uninhabited/uninhabited-patterns.rs
@@ -1,6 +1,5 @@
 #![feature(box_patterns)]
 #![feature(never_type)]
-#![feature(min_exhaustive_patterns)]
 #![deny(unreachable_patterns)]
 
 mod foo {
diff --git a/tests/ui/uninhabited/uninhabited-patterns.stderr b/tests/ui/uninhabited/uninhabited-patterns.stderr
index ca62386d7ef..4e4aaa93f80 100644
--- a/tests/ui/uninhabited/uninhabited-patterns.stderr
+++ b/tests/ui/uninhabited/uninhabited-patterns.stderr
@@ -1,18 +1,18 @@
 error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:30:9
+  --> $DIR/uninhabited-patterns.rs:29:9
    |
 LL |         Ok(box _) => (),
    |         ^^^^^^^^^
    |
    = note: this pattern matches no values because `NotSoSecretlyEmpty` is uninhabited
 note: the lint level is defined here
-  --> $DIR/uninhabited-patterns.rs:4:9
+  --> $DIR/uninhabited-patterns.rs:3:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:39:9
+  --> $DIR/uninhabited-patterns.rs:38:9
    |
 LL |         Err(Ok(_y)) => (),
    |         ^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL |         Err(Ok(_y)) => (),
    = note: this pattern matches no values because `NotSoSecretlyEmpty` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:42:15
+  --> $DIR/uninhabited-patterns.rs:41:15
    |
 LL |     while let Some(_y) = foo() {
    |               ^^^^^^^^