summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/blank_issue.md4
-rw-r--r--.github/pull_request_template.md2
-rw-r--r--.github/workflows/ci.yml10
-rw-r--r--.github/workflows/dependencies.yml6
-rw-r--r--.gitignore9
-rw-r--r--Cargo.lock181
-rw-r--r--INSTALL.md20
-rw-r--r--compiler/rustc_ast/src/ast.rs28
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs10
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs8
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs114
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs30
-rw-r--r--compiler/rustc_attr/messages.ftl2
-rw-r--r--compiler/rustc_attr/src/builtin.rs67
-rw-r--r--compiler/rustc_attr/src/session_diagnostics.rs1
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs12
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs10
-rw-r--r--compiler/rustc_borrowck/src/lib.rs2
-rw-r--r--compiler/rustc_borrowck/src/polonius/loan_invalidations.rs1
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs8
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs2
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl24
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs128
-rw-r--r--compiler/rustc_builtin_macros/src/cfg.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs27
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/example/std_example.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch13
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs13
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/types.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/unsize.rs17
-rw-r--r--compiler/rustc_codegen_gcc/src/allocator.rs13
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs8
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/simd.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/type_of.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs22
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs31
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/utils.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs13
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs11
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/type_of.rs2
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml3
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs50
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs83
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs59
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs14
-rw-r--r--compiler/rustc_const_eval/src/const_eval/dummy_machine.rs7
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs53
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs68
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs20
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/call.rs58
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs30
-rw-r--r--compiler/rustc_const_eval/src/interpret/discriminant.rs19
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs49
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs34
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs51
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs148
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs116
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs37
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs79
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs24
-rw-r--r--compiler/rustc_const_eval/src/interpret/stack.rs26
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs28
-rw-r--r--compiler/rustc_const_eval/src/interpret/traits.rs14
-rw-r--r--compiler/rustc_const_eval/src/interpret/util.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs176
-rw-r--r--compiler/rustc_const_eval/src/interpret/visitor.rs10
-rw-r--r--compiler/rustc_const_eval/src/util/check_validity_requirement.rs3
-rw-r--r--compiler/rustc_data_structures/src/stack.rs4
-rw-r--r--compiler/rustc_driver_impl/README.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0607.md10
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0787.md5
-rw-r--r--compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs8
-rw-r--r--compiler/rustc_errors/src/emitter.rs14
-rw-r--r--compiler/rustc_errors/src/json.rs6
-rw-r--r--compiler/rustc_errors/src/lib.rs18
-rw-r--r--compiler/rustc_errors/src/tests.rs4
-rw-r--r--compiler/rustc_errors/src/translation.rs3
-rw-r--r--compiler/rustc_expand/messages.ftl6
-rw-r--r--compiler/rustc_expand/src/config.rs27
-rw-r--r--compiler/rustc_expand/src/errors.rs14
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs38
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs6
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/unstable.rs4
-rw-r--r--compiler/rustc_hir/src/hir.rs41
-rw-r--r--compiler/rustc_hir/src/intravisit.rs25
-rw-r--r--compiler/rustc_hir/src/target.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs44
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs34
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs67
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs50
-rw-r--r--compiler/rustc_hir_analysis/src/collect/dump.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs57
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs108
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs129
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs60
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs68
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs53
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/variance/dump.rs13
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs15
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl8
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs22
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs46
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/expectation.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs195
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs22
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs17
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs26
-rw-r--r--compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs32
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs91
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs36
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs10
-rw-r--r--compiler/rustc_infer/src/errors.rs (renamed from compiler/rustc_infer/src/errors/mod.rs)0
-rw-r--r--compiler/rustc_infer/src/infer/at.rs17
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs115
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/mod.rs37
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/table.rs4
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs12
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs6
-rw-r--r--compiler/rustc_infer/src/infer/relate/combine.rs36
-rw-r--r--compiler/rustc_infer/src/infer/relate/glb.rs159
-rw-r--r--compiler/rustc_infer/src/infer/relate/lattice.rs302
-rw-r--r--compiler/rustc_infer/src/infer/relate/lub.rs158
-rw-r--r--compiler/rustc_infer/src/infer/relate/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/relate/type_relating.rs47
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs28
-rw-r--r--compiler/rustc_infer/src/infer/snapshot/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/type_variable.rs45
-rw-r--r--compiler/rustc_infer/src/lib.rs4
-rw-r--r--compiler/rustc_interface/src/interface.rs7
-rw-r--r--compiler/rustc_interface/src/lib.rs1
-rw-r--r--compiler/rustc_interface/src/passes.rs107
-rw-r--r--compiler/rustc_interface/src/tests.rs4
-rw-r--r--compiler/rustc_lint/messages.ftl6
-rw-r--r--compiler/rustc_lint/src/async_fn_in_trait.rs7
-rw-r--r--compiler/rustc_lint/src/context/diagnostics.rs6
-rw-r--r--compiler/rustc_lint/src/if_let_rescope.rs32
-rw-r--r--compiler/rustc_lint/src/impl_trait_overcaptures.rs6
-rw-r--r--compiler/rustc_lint/src/late.rs5
-rw-r--r--compiler/rustc_lint/src/lib.rs6
-rw-r--r--compiler/rustc_lint/src/lints.rs10
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs16
-rw-r--r--compiler/rustc_lint/src/types.rs23
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs78
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs2
-rw-r--r--compiler/rustc_llvm/Cargo.toml2
-rw-r--r--compiler/rustc_metadata/src/lib.rs2
-rw-r--r--compiler/rustc_metadata/src/locator.rs20
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs9
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs107
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs6
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs37
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs12
-rw-r--r--compiler/rustc_middle/src/lib.rs2
-rw-r--r--compiler/rustc_middle/src/macros.rs2
-rw-r--r--compiler/rustc_middle/src/middle/resolve_bound_vars.rs10
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs2
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs20
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs15
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs194
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs38
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs11
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs6
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs30
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs1
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs26
-rw-r--r--compiler/rustc_middle/src/thir.rs3
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs8
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs6
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs24
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs10
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs28
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs14
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs6
-rw-r--r--compiler/rustc_middle/src/ty/predicate.rs4
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs46
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs10
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs16
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs10
-rw-r--r--compiler/rustc_middle/src/values.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs19
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs19
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/engine.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs1
-rw-r--r--compiler/rustc_mir_transform/messages.ftl5
-rw-r--r--compiler/rustc_mir_transform/src/check_undefined_transmutes.rs77
-rw-r--r--compiler/rustc_mir_transform/src/coroutine/by_move_body.rs10
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs42
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs11
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs3
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs45
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs7
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs120
-rw-r--r--compiler/rustc_mir_transform/src/jump_threading.rs51
-rw-r--r--compiler/rustc_mir_transform/src/known_panics_lint.rs57
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs2
-rw-r--r--compiler/rustc_mir_transform/src/single_use_consts.rs5
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs8
-rw-r--r--compiler/rustc_monomorphize/src/partitioning.rs34
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs249
-rw-r--r--compiler/rustc_next_trait_solver/src/resolve.rs13
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs52
-rw-r--r--compiler/rustc_parse/messages.ftl10
-rw-r--r--compiler/rustc_parse/src/errors.rs20
-rw-r--r--compiler/rustc_parse/src/lib.rs4
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs8
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs54
-rw-r--r--compiler/rustc_passes/messages.ftl20
-rw-r--r--compiler/rustc_passes/src/check_attr.rs2
-rw-r--r--compiler/rustc_passes/src/dead.rs10
-rw-r--r--compiler/rustc_passes/src/errors.rs22
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs1
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs94
-rw-r--r--compiler/rustc_passes/src/reachable.rs4
-rw-r--r--compiler/rustc_pattern_analysis/src/constructor.rs8
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs2
-rw-r--r--compiler/rustc_privacy/src/lib.rs73
-rw-r--r--compiler/rustc_query_impl/src/lib.rs2
-rw-r--r--compiler/rustc_query_system/src/ich/impls_syntax.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs6
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs13
-rw-r--r--compiler/rustc_resolve/src/lib.rs10
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs6
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs2
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs2
-rw-r--r--compiler/rustc_session/src/config.rs8
-rw-r--r--compiler/rustc_session/src/config/cfg.rs24
-rw-r--r--compiler/rustc_session/src/cstore.rs2
-rw-r--r--compiler/rustc_session/src/options.rs43
-rw-r--r--compiler/rustc_session/src/session.rs12
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs1
-rw-r--r--compiler/rustc_span/Cargo.toml1
-rw-r--r--compiler/rustc_span/src/lib.rs139
-rw-r--r--compiler/rustc_span/src/source_map.rs16
-rw-r--r--compiler/rustc_span/src/source_map/tests.rs4
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_span/src/tests.rs10
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs2
-rw-r--r--compiler/rustc_target/src/abi/mod.rs2
-rw-r--r--compiler/rustc_target/src/asm/mod.rs29
-rw-r--r--compiler/rustc_target/src/asm/s390x.rs111
-rw-r--r--compiler/rustc_target/src/spec/base/apple/mod.rs17
-rw-r--r--compiler/rustc_target/src/spec/base/avr_gnu.rs2
-rw-r--r--compiler/rustc_target/src/spec/mod.rs76
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs34
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs34
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs34
-rw-r--r--compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs38
-rw-r--r--compiler/rustc_target/src/target_features.rs5
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs9
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/region.rs13
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs120
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs1
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs10
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs18
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs90
-rw-r--r--compiler/rustc_transmute/src/layout/tree.rs5
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/mod.rs2
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs14
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs18
-rw-r--r--compiler/rustc_ty_utils/src/opaque_types.rs4
-rw-r--r--compiler/rustc_type_ir/src/data_structures/delayed_map.rs92
-rw-r--r--compiler/rustc_type_ir/src/data_structures/mod.rs (renamed from compiler/rustc_type_ir/src/data_structures.rs)3
-rw-r--r--compiler/rustc_type_ir/src/elaborate.rs105
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs2
-rw-r--r--compiler/rustc_type_ir/src/lang_items.rs2
-rw-r--r--compiler/rustc_type_ir/src/predicate.rs7
-rw-r--r--compiler/stable_mir/src/mir/body.rs12
-rw-r--r--compiler/stable_mir/src/mir/visit.rs4
-rw-r--r--config.example.toml10
-rw-r--r--library/Cargo.lock8
-rw-r--r--library/alloc/Cargo.toml2
-rw-r--r--library/alloc/benches/str.rs2
-rw-r--r--library/alloc/src/boxed.rs1
-rw-r--r--library/alloc/src/collections/binary_heap/mod.rs5
-rw-r--r--library/alloc/src/ffi/c_str.rs1
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/raw_vec.rs12
-rw-r--r--library/alloc/src/slice.rs67
-rw-r--r--library/alloc/src/str.rs129
-rw-r--r--library/alloc/src/string.rs38
-rw-r--r--library/alloc/src/sync.rs1
-rw-r--r--library/alloc/src/vec/mod.rs55
-rw-r--r--library/alloc/tests/lib.rs1
-rw-r--r--library/alloc/tests/str.rs3
-rw-r--r--library/core/src/alloc/global.rs32
-rw-r--r--library/core/src/cell.rs82
-rw-r--r--library/core/src/cell/once.rs3
-rw-r--r--library/core/src/char/methods.rs3
-rw-r--r--library/core/src/cmp.rs356
-rw-r--r--library/core/src/fmt/num.rs212
-rw-r--r--library/core/src/intrinsics.rs22
-rw-r--r--library/core/src/intrinsics/mir.rs2
-rw-r--r--library/core/src/lib.rs10
-rw-r--r--library/core/src/num/f128.rs28
-rw-r--r--library/core/src/num/f16.rs28
-rw-r--r--library/core/src/num/f32.rs17
-rw-r--r--library/core/src/num/f64.rs17
-rw-r--r--library/core/src/ops/control_flow.rs20
-rw-r--r--library/core/src/ops/mod.rs2
-rw-r--r--library/core/src/option.rs24
-rw-r--r--library/core/src/panic/location.rs2
-rw-r--r--library/core/src/primitive_docs.rs2
-rw-r--r--library/core/src/ptr/const_ptr.rs57
-rw-r--r--library/core/src/ptr/metadata.rs6
-rw-r--r--library/core/src/ptr/mod.rs6
-rw-r--r--library/core/src/ptr/mut_ptr.rs58
-rw-r--r--library/core/src/ptr/non_null.rs10
-rw-r--r--library/core/src/slice/mod.rs34
-rw-r--r--library/core/src/slice/raw.rs3
-rw-r--r--library/core/src/str/converts.rs6
-rw-r--r--library/core/src/str/mod.rs6
-rw-r--r--library/core/src/sync/atomic.rs87
-rw-r--r--library/core/tests/lib.rs2
-rw-r--r--library/proc_macro/src/lib.rs2
-rw-r--r--library/std/Cargo.toml4
-rw-r--r--library/std/build.rs35
-rw-r--r--library/std/src/collections/hash/map.rs201
-rw-r--r--library/std/src/collections/hash/map/tests.rs5
-rw-r--r--library/std/src/collections/hash/set.rs48
-rw-r--r--library/std/src/collections/hash/set/tests.rs2
-rw-r--r--library/std/src/env/tests.rs2
-rw-r--r--library/std/src/fs.rs10
-rw-r--r--library/std/src/io/buffered/tests.rs3
-rw-r--r--library/std/src/io/error/repr_bitpacked.rs1
-rw-r--r--library/std/src/io/mod.rs4
-rw-r--r--library/std/src/io/stdio.rs1
-rw-r--r--library/std/src/io/stdio/tests.rs8
-rw-r--r--library/std/src/lib.rs4
-rw-r--r--library/std/src/net/ip_addr.rs2
-rw-r--r--library/std/src/net/socket_addr.rs2
-rw-r--r--library/std/src/net/tcp.rs11
-rw-r--r--library/std/src/net/tcp/tests.rs29
-rw-r--r--library/std/src/net/udp.rs12
-rw-r--r--library/std/src/net/udp/tests.rs9
-rw-r--r--library/std/src/panic.rs58
-rw-r--r--library/std/src/path/tests.rs16
-rw-r--r--library/std/src/process.rs10
-rw-r--r--library/std/src/rt.rs34
-rw-r--r--library/std/src/sync/barrier/tests.rs2
-rw-r--r--library/std/src/sync/condvar/tests.rs16
-rw-r--r--library/std/src/sync/lazy_lock/tests.rs6
-rw-r--r--library/std/src/sync/mod.rs9
-rw-r--r--library/std/src/sync/mpmc/error.rs5
-rw-r--r--library/std/src/sync/mpmc/mod.rs1037
-rw-r--r--library/std/src/sync/mpmc/tests.rs728
-rw-r--r--library/std/src/sync/mpsc/mod.rs4
-rw-r--r--library/std/src/sync/mutex.rs2
-rw-r--r--library/std/src/sync/once.rs2
-rw-r--r--library/std/src/sync/once_lock/tests.rs7
-rw-r--r--library/std/src/sync/reentrant_lock.rs2
-rw-r--r--library/std/src/sync/rwlock.rs2
-rw-r--r--library/std/src/sys/pal/hermit/mod.rs6
-rw-r--r--library/std/src/sys/pal/hermit/thread.rs1
-rw-r--r--library/std/src/sys/pal/unix/thread.rs4
-rw-r--r--library/std/src/sys/pal/wasip2/mod.rs1
-rw-r--r--library/std/src/sys/pal/wasip2/net.rs379
-rw-r--r--library/std/src/sys/sync/condvar/mod.rs8
-rw-r--r--library/std/src/sys/sync/condvar/pthread.rs38
-rw-r--r--library/std/src/sys/sync/condvar/sgx.rs29
-rw-r--r--library/std/src/sys/sync/condvar/teeos.rs101
-rw-r--r--library/std/src/sys/sync/mod.rs3
-rw-r--r--library/std/src/sys/sync/mutex/mod.rs2
-rw-r--r--library/std/src/sys/sync/mutex/pthread.rs81
-rw-r--r--library/std/src/sys/sync/mutex/sgx.rs28
-rw-r--r--library/std/src/sys/sync/once_box.rs82
-rw-r--r--library/std/src/sys/sync/rwlock/queue.rs6
-rw-r--r--library/std/src/sys/sync/rwlock/teeos.rs8
-rw-r--r--library/std/src/sys/thread_local/guard/apple.rs1
-rw-r--r--library/std/src/sys/thread_local/guard/key.rs39
-rw-r--r--library/std/src/sys/thread_local/guard/solid.rs5
-rw-r--r--library/std/src/sys/thread_local/guard/windows.rs8
-rw-r--r--library/std/src/sys/thread_local/key/xous.rs2
-rw-r--r--library/std/src/sys/thread_local/mod.rs48
-rw-r--r--library/std/src/sys/thread_local/native/mod.rs31
-rw-r--r--library/std/src/sys/thread_local/os.rs34
-rw-r--r--library/std/src/sys/thread_local/statik.rs33
-rw-r--r--library/std/src/sys_common/io.rs2
-rw-r--r--library/std/src/sys_common/lazy_box.rs88
-rw-r--r--library/std/src/sys_common/mod.rs4
-rw-r--r--library/std/src/thread/current.rs252
-rw-r--r--library/std/src/thread/local.rs2
-rw-r--r--library/std/src/thread/local/tests.rs33
-rw-r--r--library/std/src/thread/mod.rs157
-rw-r--r--library/std/tests/create_dir_all_bare.rs2
-rw-r--r--library/std/tests/process_spawning.rs2
-rw-r--r--library/std/tests/thread.rs2
-rw-r--r--src/bootstrap/Cargo.lock100
-rw-r--r--src/bootstrap/Cargo.toml2
-rw-r--r--src/bootstrap/README.md6
-rwxr-xr-xsrc/bootstrap/configure.py2
-rw-r--r--src/bootstrap/src/bin/rustc.rs1
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs21
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/format.rs1
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs24
-rw-r--r--src/bootstrap/src/core/build_steps/setup.rs197
-rw-r--r--src/bootstrap/src/core/build_steps/setup/tests.rs9
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs4
-rw-r--r--src/bootstrap/src/core/builder.rs17
-rw-r--r--src/bootstrap/src/core/config/config.rs40
-rw-r--r--src/bootstrap/src/core/config/flags.rs6
-rw-r--r--src/bootstrap/src/core/config/tests.rs22
-rw-r--r--src/bootstrap/src/core/sanity.rs7
-rw-r--r--src/bootstrap/src/lib.rs59
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile2
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version2
-rw-r--r--src/ci/scripts/upload-build-metrics.py81
-rw-r--r--src/doc/rustc/src/platform-support.md4
-rw-r--r--src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md2
-rw-r--r--src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md2
-rw-r--r--src/doc/rustc/src/platform-support/riscv32e-unknown-none-elf.md30
-rw-r--r--src/doc/rustdoc/src/write-documentation/documentation-tests.md4
-rw-r--r--src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md4
-rw-r--r--src/doc/unstable-book/src/compiler-flags/default-hidden-visibility.md12
-rw-r--r--src/doc/unstable-book/src/compiler-flags/default-visibility.md44
-rw-r--r--src/doc/unstable-book/src/compiler-flags/print-check-cfg.md27
-rw-r--r--src/doc/unstable-book/src/language-features/asm-experimental-arch.md7
-rw-r--r--src/doc/unstable-book/src/language-features/cfg-boolean-literals.md22
-rw-r--r--src/etc/completions/x.py.sh2
-rw-r--r--src/etc/rust_analyzer_eglot.el50
-rw-r--r--src/librustdoc/clean/auto_trait.rs1
-rw-r--r--src/librustdoc/clean/blanket_impl.rs1
-rw-r--r--src/librustdoc/clean/cfg.rs10
-rw-r--r--src/librustdoc/clean/cfg/tests.rs51
-rw-r--r--src/librustdoc/clean/inline.rs1
-rw-r--r--src/librustdoc/clean/mod.rs12
-rw-r--r--src/librustdoc/clean/types.rs81
-rw-r--r--src/librustdoc/config.rs4
-rw-r--r--src/librustdoc/core.rs4
-rw-r--r--src/librustdoc/doctest.rs19
-rw-r--r--src/librustdoc/doctest/make.rs2
-rw-r--r--src/librustdoc/doctest/runner.rs6
-rw-r--r--src/librustdoc/doctest/rust.rs30
-rw-r--r--src/librustdoc/formats/cache.rs16
-rw-r--r--src/librustdoc/html/highlight.rs4
-rw-r--r--src/librustdoc/html/highlight/tests.rs4
-rw-r--r--src/librustdoc/html/layout.rs4
-rw-r--r--src/librustdoc/html/markdown.rs85
-rw-r--r--src/librustdoc/html/render/context.rs14
-rw-r--r--src/librustdoc/html/render/mod.rs38
-rw-r--r--src/librustdoc/html/render/print_item.rs35
-rw-r--r--src/librustdoc/html/render/search_index.rs10
-rw-r--r--src/librustdoc/html/render/span_map.rs5
-rw-r--r--src/librustdoc/html/render/write_shared.rs10
-rw-r--r--src/librustdoc/html/sources.rs8
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css28
-rw-r--r--src/librustdoc/html/static/js/main.js14
-rw-r--r--src/librustdoc/lib.rs3
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs122
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs2
-rw-r--r--src/librustdoc/passes/lint/check_code_block_syntax.rs4
-rw-r--r--src/librustdoc/passes/mod.rs5
-rw-r--r--src/librustdoc/passes/propagate_stability.rs72
-rw-r--r--src/librustdoc/scrape_examples.rs10
-rw-r--r--src/librustdoc/theme.rs33
-rw-r--r--src/librustdoc/visit.rs11
-rw-r--r--src/librustdoc/visit_ast.rs12
m---------src/llvm-project0
-rw-r--r--src/tools/build_helper/src/ci.rs9
-rw-r--r--src/tools/build_helper/src/git.rs64
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/.github/workflows/remark.yml2
-rw-r--r--src/tools/clippy/CHANGELOG.md1
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md1
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs1
-rw-r--r--src/tools/clippy/clippy_config/src/msrvs.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs86
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/checked_conversions.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_enum.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_nesting.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/fallible_impl_from.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/format_impl.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/from_over_into.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs60
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/ref_option.rs122
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs445
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_clamp.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/wild_in_or_pats.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_mut.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/single_component_path_imports.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/zombie_processes.rs11
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs109
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs16
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs52
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs9
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/mod.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_origin.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs4
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs4
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/src/driver.rs61
-rw-r--r--src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs3
-rw-r--r--src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr12
-rw-r--r--src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed1
-rw-r--r--src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs1
-rw-r--r--src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr2
-rw-r--r--src/tools/clippy/tests/ui/as_ptr_cast_mut.rs2
-rw-r--r--src/tools/clippy/tests/ui/borrow_box.fixed133
-rw-r--r--src/tools/clippy/tests/ui/borrow_box.rs20
-rw-r--r--src/tools/clippy/tests/ui/borrow_box.stderr14
-rw-r--r--src/tools/clippy/tests/ui/boxed_local.rs3
-rw-r--r--src/tools/clippy/tests/ui/boxed_local.stderr8
-rw-r--r--src/tools/clippy/tests/ui/bytecount.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.fixed2
-rw-r--r--src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr20
-rw-r--r--src/tools/clippy/tests/ui/deref_addrof_double_trigger.rs4
-rw-r--r--src/tools/clippy/tests/ui/derive.rs7
-rw-r--r--src/tools/clippy/tests/ui/derive.stderr20
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed3
-rw-r--r--src/tools/clippy/tests/ui/eta.rs3
-rw-r--r--src/tools/clippy/tests/ui/eta.stderr68
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.fixed3
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.rs3
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.stderr92
-rw-r--r--src/tools/clippy/tests/ui/extra_unused_lifetimes.rs8
-rw-r--r--src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr8
-rw-r--r--src/tools/clippy/tests/ui/float_cmp.rs2
-rw-r--r--src/tools/clippy/tests/ui/float_cmp_const.rs3
-rw-r--r--src/tools/clippy/tests/ui/float_cmp_const.stderr16
-rw-r--r--src/tools/clippy/tests/ui/float_equality_without_abs.rs2
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.fixed1
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.rs1
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.stderr8
-rw-r--r--src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs2
-rw-r--r--src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed7
-rw-r--r--src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs5
-rw-r--r--src/tools/clippy/tests/ui/invalid_null_ptr_usage.stderr36
-rw-r--r--src/tools/clippy/tests/ui/iter_without_into_iter.rs1
-rw-r--r--src/tools/clippy/tests/ui/iter_without_into_iter.stderr16
-rw-r--r--src/tools/clippy/tests/ui/mem_replace.fixed3
-rw-r--r--src/tools/clippy/tests/ui/mem_replace.rs3
-rw-r--r--src/tools/clippy/tests/ui/mem_replace.stderr48
-rw-r--r--src/tools/clippy/tests/ui/mem_replace_no_std.fixed3
-rw-r--r--src/tools/clippy/tests/ui/mem_replace_no_std.rs3
-rw-r--r--src/tools/clippy/tests/ui/mem_replace_no_std.stderr14
-rw-r--r--src/tools/clippy/tests/ui/mismatching_type_param_order.rs2
-rw-r--r--src/tools/clippy/tests/ui/mut_mutex_lock.fixed12
-rw-r--r--src/tools/clippy/tests/ui/mut_mutex_lock.rs12
-rw-r--r--src/tools/clippy/tests/ui/mut_mutex_lock.stderr8
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.fixed3
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.rs3
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.stderr56
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.fixed23
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.rs21
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.stderr24
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_value.rs3
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_value.stderr52
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed20
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs20
-rw-r--r--src/tools/clippy/tests/ui/new_without_default.fixed3
-rw-r--r--src/tools/clippy/tests/ui/new_without_default.rs3
-rw-r--r--src/tools/clippy/tests/ui/new_without_default.stderr18
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed62
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool_methods.rs62
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr110
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool_methods_unfixable.rs9
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool_methods_unfixable.stderr17
-rw-r--r--src/tools/clippy/tests/ui/ref_as_ptr.fixed2
-rw-r--r--src/tools/clippy/tests/ui/ref_as_ptr.rs2
-rw-r--r--src/tools/clippy/tests/ui/ref_option/all/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui/ref_option/private/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui/ref_option/ref_option.all.fixed62
-rw-r--r--src/tools/clippy/tests/ui/ref_option/ref_option.all.stderr162
-rw-r--r--src/tools/clippy/tests/ui/ref_option/ref_option.private.fixed62
-rw-r--r--src/tools/clippy/tests/ui/ref_option/ref_option.private.stderr108
-rw-r--r--src/tools/clippy/tests/ui/ref_option/ref_option.rs62
-rw-r--r--src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr37
-rw-r--r--src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr21
-rw-r--r--src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs37
-rw-r--r--src/tools/clippy/tests/ui/serde.rs2
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs7
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr58
-rw-r--r--src/tools/clippy/tests/ui/str_split.fixed1
-rw-r--r--src/tools/clippy/tests/ui/str_split.rs1
-rw-r--r--src/tools/clippy/tests/ui/str_split.stderr20
-rw-r--r--src/tools/clippy/tests/ui/temporary_assignment.rs2
-rw-r--r--src/tools/clippy/tests/ui/transmute_float_to_int.fixed4
-rw-r--r--src/tools/clippy/tests/ui/transmute_float_to_int.rs4
-rw-r--r--src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed9
-rw-r--r--src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs9
-rw-r--r--src/tools/clippy/tests/ui/unconditional_recursion.rs3
-rw-r--r--src/tools/clippy/tests/ui/unconditional_recursion.stderr90
-rw-r--r--src/tools/clippy/tests/ui/unused_async.rs16
-rw-r--r--src/tools/clippy/tests/ui/unused_async.stderr4
-rw-r--r--src/tools/clippy/tests/ui/unused_format_specs.1.fixed35
-rw-r--r--src/tools/clippy/tests/ui/unused_format_specs.2.fixed35
-rw-r--r--src/tools/clippy/tests/ui/unused_format_specs.rs (renamed from src/tools/clippy/tests/ui/unused_format_specs_unfixable.rs)2
-rw-r--r--src/tools/clippy/tests/ui/unused_format_specs.stderr (renamed from src/tools/clippy/tests/ui/unused_format_specs_unfixable.stderr)8
-rw-r--r--src/tools/clippy/tests/ui/useful_asref.rs1
-rw-r--r--src/tools/clippy/tests/ui/wild_in_or_pats.rs68
-rw-r--r--src/tools/clippy/tests/ui/wild_in_or_pats.stderr18
-rw-r--r--src/tools/clippy/tests/ui/zombie_processes.rs7
-rw-r--r--src/tools/compiletest/src/command-list.rs16
-rw-r--r--src/tools/compiletest/src/common.rs3
-rw-r--r--src/tools/compiletest/src/header.rs11
-rw-r--r--src/tools/compiletest/src/header/cfg.rs4
-rw-r--r--src/tools/compiletest/src/header/needs.rs5
-rw-r--r--src/tools/compiletest/src/header/tests.rs5
-rw-r--r--src/tools/compiletest/src/lib.rs3
-rw-r--r--src/tools/compiletest/src/runtest.rs13
-rw-r--r--src/tools/compiletest/src/runtest/crashes.rs (renamed from src/tools/compiletest/src/runtest/crash.rs)0
-rw-r--r--src/tools/miri/.github/workflows/ci.yml8
-rw-r--r--src/tools/miri/Cargo.lock22
-rw-r--r--src/tools/miri/Cargo.toml2
-rw-r--r--src/tools/miri/README.md2
-rw-r--r--src/tools/miri/bench-cargo-miri/backtraces/Cargo.lock13
-rw-r--r--src/tools/miri/bench-cargo-miri/backtraces/src/main.rs3
-rw-r--r--src/tools/miri/bench-cargo-miri/serde2/src/main.rs3
-rw-r--r--src/tools/miri/cargo-miri/Cargo.lock4
-rw-r--r--src/tools/miri/cargo-miri/Cargo.toml2
-rw-r--r--src/tools/miri/cargo-miri/src/phases.rs4
-rwxr-xr-xsrc/tools/miri/ci/ci.sh20
-rw-r--r--src/tools/miri/miri-script/Cargo.lock74
-rw-r--r--src/tools/miri/miri-script/Cargo.toml2
-rw-r--r--src/tools/miri/miri-script/src/args.rs3
-rw-r--r--src/tools/miri/miri-script/src/commands.rs7
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/rustfmt.toml7
-rw-r--r--src/tools/miri/src/alloc_addresses/mod.rs29
-rw-r--r--src/tools/miri/src/alloc_addresses/reuse_pool.rs4
-rw-r--r--src/tools/miri/src/alloc_bytes.rs3
-rw-r--r--src/tools/miri/src/bin/miri.rs22
-rw-r--r--src/tools/miri/src/borrow_tracker/mod.rs11
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs2
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs73
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs20
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs12
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs47
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs24
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs3
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs3
-rw-r--r--src/tools/miri/src/concurrency/data_race.rs120
-rw-r--r--src/tools/miri/src/concurrency/init_once.rs9
-rw-r--r--src/tools/miri/src/concurrency/range_object_map.rs2
-rw-r--r--src/tools/miri/src/concurrency/sync.rs52
-rw-r--r--src/tools/miri/src/concurrency/thread.rs35
-rw-r--r--src/tools/miri/src/concurrency/vector_clock.rs17
-rw-r--r--src/tools/miri/src/concurrency/weak_memory.rs37
-rw-r--r--src/tools/miri/src/diagnostics.rs2
-rw-r--r--src/tools/miri/src/eval.rs26
-rw-r--r--src/tools/miri/src/helpers.rs281
-rw-r--r--src/tools/miri/src/intrinsics/atomic.rs27
-rw-r--r--src/tools/miri/src/intrinsics/mod.rs26
-rw-r--r--src/tools/miri/src/intrinsics/simd.rs12
-rw-r--r--src/tools/miri/src/lib.rs46
-rw-r--r--src/tools/miri/src/machine.rs79
-rw-r--r--src/tools/miri/src/operator.rs5
-rw-r--r--src/tools/miri/src/provenance_gc.rs1
-rw-r--r--src/tools/miri/src/shims/alloc.rs20
-rw-r--r--src/tools/miri/src/shims/backtrace.rs14
-rw-r--r--src/tools/miri/src/shims/env.rs11
-rw-r--r--src/tools/miri/src/shims/extern_static.rs8
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs54
-rw-r--r--src/tools/miri/src/shims/io_error.rs228
-rw-r--r--src/tools/miri/src/shims/mod.rs1
-rw-r--r--src/tools/miri/src/shims/native_lib.rs13
-rw-r--r--src/tools/miri/src/shims/os_str.rs28
-rw-r--r--src/tools/miri/src/shims/panic.rs12
-rw-r--r--src/tools/miri/src/shims/time.rs37
-rw-r--r--src/tools/miri/src/shims/tls.rs32
-rw-r--r--src/tools/miri/src/shims/unix/android/foreign_items.rs4
-rw-r--r--src/tools/miri/src/shims/unix/env.rs56
-rw-r--r--src/tools/miri/src/shims/unix/fd.rs132
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs51
-rw-r--r--src/tools/miri/src/shims/unix/freebsd/foreign_items.rs4
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs318
-rw-r--r--src/tools/miri/src/shims/unix/linux/epoll.rs96
-rw-r--r--src/tools/miri/src/shims/unix/linux/eventfd.rs32
-rw-r--r--src/tools/miri/src/shims/unix/linux/foreign_items.rs23
-rw-r--r--src/tools/miri/src/shims/unix/linux/mem.rs9
-rw-r--r--src/tools/miri/src/shims/unix/linux/sync.rs47
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs7
-rw-r--r--src/tools/miri/src/shims/unix/macos/sync.rs12
-rw-r--r--src/tools/miri/src/shims/unix/mem.rs23
-rw-r--r--src/tools/miri/src/shims/unix/mod.rs11
-rw-r--r--src/tools/miri/src/shims/unix/solarish/foreign_items.rs4
-rw-r--r--src/tools/miri/src/shims/unix/sync.rs96
-rw-r--r--src/tools/miri/src/shims/unix/thread.rs19
-rw-r--r--src/tools/miri/src/shims/unix/unnamed_socket.rs37
-rw-r--r--src/tools/miri/src/shims/wasi/foreign_items.rs4
-rw-r--r--src/tools/miri/src/shims/windows/env.rs40
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs24
-rw-r--r--src/tools/miri/src/shims/windows/handle.rs9
-rw-r--r--src/tools/miri/src/shims/windows/mod.rs3
-rw-r--r--src/tools/miri/src/shims/windows/sync.rs18
-rw-r--r--src/tools/miri/src/shims/windows/thread.rs4
-rw-r--r--src/tools/miri/src/shims/x86/aesni.rs6
-rw-r--r--src/tools/miri/src/shims/x86/avx.rs6
-rw-r--r--src/tools/miri/src/shims/x86/avx2.rs4
-rw-r--r--src/tools/miri/src/shims/x86/bmi.rs6
-rw-r--r--src/tools/miri/src/shims/x86/gfni.rs196
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs102
-rw-r--r--src/tools/miri/src/shims/x86/sha.rs8
-rw-r--r--src/tools/miri/src/shims/x86/sse.rs4
-rw-r--r--src/tools/miri/src/shims/x86/sse2.rs4
-rw-r--r--src/tools/miri/src/shims/x86/sse3.rs4
-rw-r--r--src/tools/miri/src/shims/x86/sse41.rs4
-rw-r--r--src/tools/miri/src/shims/x86/sse42.rs16
-rw-r--r--src/tools/miri/src/shims/x86/ssse3.rs4
-rw-r--r--src/tools/miri/test-cargo-miri/src/main.rs3
-rw-r--r--src/tools/miri/test-cargo-miri/subcrate/test.rs1
-rw-r--r--src/tools/miri/test_dependencies/Cargo.lock13
-rw-r--r--src/tools/miri/tests/avr.json25
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs3
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.rs (renamed from src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs)4
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.stderr (renamed from src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.stderr)8
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.rs (renamed from src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs)9
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.stderr (renamed from src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.stderr)8
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.rs (renamed from src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs)2
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.stderr (renamed from src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.stderr)4
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.rs12
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.stderr15
-rw-r--r--src/tools/miri/tests/fail-dep/libc/affinity.rs4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs3
-rw-r--r--src/tools/miri/tests/fail/coroutine-pinned-moved.rs6
-rw-r--r--src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs3
-rw-r--r--src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs3
-rw-r--r--src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs3
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_read.rs28
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr22
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr22
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs39
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr22
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs39
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr (renamed from src/tools/miri/tests/fail/data_race/mixed_size_read.stderr)14
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr22
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs (renamed from src/tools/miri/tests/fail/data_race/mixed_size_write.rs)4
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr22
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_write_write.stderr (renamed from src/tools/miri/tests/fail/data_race/mixed_size_write.stderr)6
-rw-r--r--src/tools/miri/tests/fail/data_race/read_read_race1.rs30
-rw-r--r--src/tools/miri/tests/fail/data_race/read_read_race1.stderr22
-rw-r--r--src/tools/miri/tests/fail/data_race/read_read_race2.rs30
-rw-r--r--src/tools/miri/tests/fail/data_race/read_read_race2.stderr22
-rw-r--r--src/tools/miri/tests/fail/panic/abort_unwind.rs11
-rw-r--r--src/tools/miri/tests/fail/panic/abort_unwind.stderr33
-rw-r--r--src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr6
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/children-can-alias.rs3
-rw-r--r--src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.rs32
-rw-r--r--src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.stderr15
-rw-r--r--src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.rs37
-rw-r--r--src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.stderr15
-rw-r--r--src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs4
-rw-r--r--src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs41
-rw-r--r--src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs39
-rw-r--r--src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr22
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs3
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs3
-rw-r--r--src/tools/miri/tests/pass-dep/getrandom.rs5
-rw-r--r--src/tools/miri/tests/pass-dep/libc/gettid.rs3
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-affinity.rs3
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs41
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs4
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-fs.rs3
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-random.rs13
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-time.rs30
-rw-r--r--src/tools/miri/tests/pass-dep/tokio/file-io.rs1
-rw-r--r--src/tools/miri/tests/pass/async-niche-aliasing.rs12
-rw-r--r--src/tools/miri/tests/pass/atomic-compare-exchange-weak-never-fail.rs3
-rw-r--r--src/tools/miri/tests/pass/atomic.rs5
-rw-r--r--src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr2
-rw-r--r--src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr2
-rw-r--r--src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr2
-rw-r--r--src/tools/miri/tests/pass/backtrace/backtrace-std.stderr2
-rw-r--r--src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs12
-rw-r--r--src/tools/miri/tests/pass/box-custom-alloc.rs3
-rw-r--r--src/tools/miri/tests/pass/concurrency/address_reuse_happens_before.rs3
-rw-r--r--src/tools/miri/tests/pass/concurrency/data_race.rs76
-rw-r--r--src/tools/miri/tests/pass/concurrency/sync_singlethread.rs3
-rw-r--r--src/tools/miri/tests/pass/coroutine.rs6
-rw-r--r--src/tools/miri/tests/pass/dyn-arbitrary-self.rs10
-rw-r--r--src/tools/miri/tests/pass/function_calls/abi_compat.rs4
-rw-r--r--src/tools/miri/tests/pass/intrinsics/portable-simd.rs3
-rw-r--r--src/tools/miri/tests/pass/issues/issue-miri-3541-dyn-vtable-trait-normalization.rs3
-rw-r--r--src/tools/miri/tests/pass/leak-in-static.rs6
-rw-r--r--src/tools/miri/tests/pass/ptr_int_casts.rs3
-rw-r--r--src/tools/miri/tests/pass/shims/env/var.rs3
-rw-r--r--src/tools/miri/tests/pass/shims/fs.rs6
-rw-r--r--src/tools/miri/tests/pass/shims/random.rs5
-rw-r--r--src/tools/miri/tests/pass/shims/windows-threadname.rs3
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs518
-rw-r--r--src/tools/miri/tests/pass/slices.rs3
-rw-r--r--src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs6
-rw-r--r--src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs6
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs3
-rw-r--r--src/tools/miri/tests/pass/underscore_pattern.rs51
-rw-r--r--src/tools/miri/tests/ui.rs3
-rw-r--r--src/tools/miri/tests/x86_64-unknown-kernel.json24
-rw-r--r--src/tools/rustbook/Cargo.lock52
-rw-r--r--src/tools/rustdoc-gui/tester.js26
-rw-r--r--src/tools/rustfmt/src/parse/macros/asm.rs2
-rw-r--r--src/tools/rustfmt/src/parse/session.rs8
-rw-r--r--src/tools/tidy/src/deps.rs6
-rw-r--r--src/tools/wasm-component-ld/Cargo.toml2
-rw-r--r--tests/assembly/aarch64-naked-fn-no-bti-prolog.rs4
-rw-r--r--tests/assembly/targets/targets-elf.rs12
-rw-r--r--tests/assembly/x86_64-naked-fn-no-cet-prolog.rs4
-rw-r--r--tests/codegen/asm-s390x-clobbers.rs50
-rw-r--r--tests/codegen/binary-heap-peek-mut-pop-no-panic.rs13
-rw-r--r--tests/codegen/cffi/c-variadic-naked.rs3
-rw-r--r--tests/codegen/default-visibility.rs (renamed from tests/codegen/default-hidden-visibility.rs)18
-rw-r--r--tests/codegen/issues/issue-123712-str-to-lower-autovectorization.rs23
-rw-r--r--tests/codegen/naked-asan.rs2
-rw-r--r--tests/codegen/naked-fn/aligned.rs4
-rw-r--r--tests/codegen/naked-fn/naked-functions.rs6
-rw-r--r--tests/codegen/naked-fn/naked-nocoverage.rs4
-rw-r--r--tests/codegen/naked-fn/naked-noinline.rs4
-rw-r--r--tests/coverage/closure_macro.cov-map8
-rw-r--r--tests/coverage/closure_macro_async.cov-map8
-rw-r--r--tests/crashes/119716-2.rs4
-rw-r--r--tests/crashes/119716.rs4
-rw-r--r--tests/crashes/121422.rs8
-rw-r--r--tests/crashes/124375.rs4
-rw-r--r--tests/crashes/125843.rs4
-rw-r--r--tests/crashes/125881.rs8
-rw-r--r--tests/crashes/126377.rs29
-rw-r--r--tests/crashes/127880.rs5
-rw-r--r--tests/crashes/128327.rs5
-rw-r--r--tests/crashes/129099.rs15
-rw-r--r--tests/crashes/130413.rs17
-rw-r--r--tests/crashes/130521.rs13
-rw-r--r--tests/crashes/130524.rs22
-rw-r--r--tests/crashes/130627.rs20
-rw-r--r--tests/crashes/130687.rs4
-rw-r--r--tests/crashes/130779.rs11
-rw-r--r--tests/crashes/130921.rs10
-rw-r--r--tests/crashes/130970.rs9
-rw-r--r--tests/incremental/hashes/function_interfaces.rs4
-rw-r--r--tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff46
-rw-r--r--tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff46
-rw-r--r--tests/mir-opt/jump_threading.rs12
-rw-r--r--tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir91
-rw-r--r--tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir91
-rw-r--r--tests/mir-opt/separate_const_switch.rs1
-rw-r--r--tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir3
-rw-r--r--tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir2
-rw-r--r--tests/mir-opt/uninhabited_enum.rs5
-rw-r--r--tests/mir-opt/uninhabited_not_read.main.SimplifyLocals-final.after.mir49
-rw-r--r--tests/mir-opt/uninhabited_not_read.rs26
-rw-r--r--tests/run-make/apple-sdk-version/foo.rs1
-rw-r--r--tests/run-make/apple-sdk-version/rmake.rs95
-rw-r--r--tests/run-make/checksum-freshness/expected.d6
-rw-r--r--tests/run-make/checksum-freshness/foo.rs5
-rw-r--r--tests/run-make/checksum-freshness/lib.rs7
-rw-r--r--tests/run-make/checksum-freshness/rmake.rs9
-rw-r--r--tests/run-make/doctests-merge/doctest-standalone.rs4
-rw-r--r--tests/run-make/dylib-soname/rmake.rs16
-rw-r--r--tests/run-make/naked-symbol-visibility/a_rust_dylib.rs12
-rw-r--r--tests/rustdoc-gui/README.md7
-rw-r--r--tests/rustdoc-gui/docblock-code-block-line-number.goml18
-rw-r--r--tests/rustdoc-gui/list-margins.goml11
-rw-r--r--tests/rustdoc-gui/scrape-examples-layout.goml4
-rw-r--r--tests/rustdoc-gui/search-result-display.goml2
-rw-r--r--tests/rustdoc-gui/sidebar-source-code-display.goml2
-rw-r--r--tests/rustdoc-gui/source-anchor-scroll.goml8
-rw-r--r--tests/rustdoc-gui/src/test_docs/lib.rs24
-rw-r--r--tests/rustdoc-gui/toggle-docs-mobile.goml12
-rw-r--r--tests/rustdoc-js-std/path-ordering.js1
-rw-r--r--tests/rustdoc-ui/cfg-boolean-literal.rs19
-rw-r--r--tests/rustdoc-ui/doctest/check-attr-test.stderr48
-rw-r--r--tests/rustdoc-ui/doctest/standalone-warning-2024.rs16
-rw-r--r--tests/rustdoc-ui/doctest/standalone-warning-2024.stderr38
-rw-r--r--tests/rustdoc-ui/doctest/standalone-warning.rs10
-rw-r--r--tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs18
-rw-r--r--tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr54
-rw-r--r--tests/rustdoc-ui/intra-doc/errors.rs2
-rw-r--r--tests/rustdoc-ui/intra-doc/errors.stderr4
-rw-r--r--tests/rustdoc-ui/intra-doc/field-ice.rs4
-rw-r--r--tests/rustdoc-ui/intra-doc/field-ice.stderr7
-rw-r--r--tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr6
-rw-r--r--tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr4
-rw-r--r--tests/rustdoc-ui/intra-doc/value-ctor.rs35
-rw-r--r--tests/rustdoc-ui/intra-doc/value-ctor.stderr62
-rw-r--r--tests/rustdoc-ui/intra-doc/weird-syntax.stderr20
-rw-r--r--tests/rustdoc-ui/issues/issue-91713.stdout2
-rw-r--r--tests/rustdoc-ui/lints/check-attr.stderr52
-rw-r--r--tests/rustdoc-ui/lints/check-fail.stderr8
-rw-r--r--tests/rustdoc/intra-doc/field.rs20
-rw-r--r--tests/rustdoc/stability.rs49
-rw-r--r--tests/ui-fulldeps/stable-mir/check_abi.rs1
-rw-r--r--tests/ui-fulldeps/stable-mir/check_allocation.rs1
-rw-r--r--tests/ui-fulldeps/stable-mir/check_attribute.rs1
-rw-r--r--tests/ui-fulldeps/stable-mir/check_def_ty.rs1
-rw-r--r--tests/ui-fulldeps/stable-mir/check_defs.rs1
-rw-r--r--tests/ui-fulldeps/stable-mir/check_foreign.rs1
-rw-r--r--tests/ui-fulldeps/stable-mir/check_instance.rs1
-rw-r--r--tests/ui-fulldeps/stable-mir/check_item_kind.rs1
-rw-r--r--tests/ui-fulldeps/stable-mir/check_trait_queries.rs1
-rw-r--r--tests/ui-fulldeps/stable-mir/check_transform.rs1
-rw-r--r--tests/ui-fulldeps/stable-mir/check_ty_fold.rs1
-rw-r--r--tests/ui-fulldeps/stable-mir/crate-info.rs1
-rw-r--r--tests/ui-fulldeps/stable-mir/projections.rs1
-rw-r--r--tests/ui-fulldeps/stable-mir/smir_internal.rs1
-rw-r--r--tests/ui-fulldeps/stable-mir/smir_serde.rs1
-rw-r--r--tests/ui-fulldeps/stable-mir/smir_visitor.rs1
-rw-r--r--tests/ui/abi/riscv32e-registers.riscv32e.stderr194
-rw-r--r--tests/ui/abi/riscv32e-registers.riscv32em.stderr194
-rw-r--r--tests/ui/abi/riscv32e-registers.riscv32emc.stderr194
-rw-r--r--tests/ui/abi/riscv32e-registers.rs91
-rw-r--r--tests/ui/asm/aarch64/type-check-4.rs27
-rw-r--r--tests/ui/asm/aarch64/type-check-4.stderr21
-rw-r--r--tests/ui/asm/const-error.rs6
-rw-r--r--tests/ui/asm/const-error.stderr9
-rw-r--r--tests/ui/asm/naked-functions-ffi.rs4
-rw-r--r--tests/ui/asm/naked-functions-instruction-set.rs6
-rw-r--r--tests/ui/asm/naked-functions-testattrs.rs10
-rw-r--r--tests/ui/asm/naked-functions-unused.aarch64.stderr16
-rw-r--r--tests/ui/asm/naked-functions-unused.rs42
-rw-r--r--tests/ui/asm/naked-functions-unused.x86_64.stderr16
-rw-r--r--tests/ui/asm/naked-functions.rs94
-rw-r--r--tests/ui/asm/naked-functions.stderr244
-rw-r--r--tests/ui/asm/naked-invalid-attr.rs13
-rw-r--r--tests/ui/asm/naked-invalid-attr.stderr6
-rw-r--r--tests/ui/asm/naked-with-invalid-repr-attr.rs12
-rw-r--r--tests/ui/asm/naked-with-invalid-repr-attr.stderr12
-rw-r--r--tests/ui/asm/named-asm-labels.rs10
-rw-r--r--tests/ui/asm/named-asm-labels.stderr18
-rw-r--r--tests/ui/asm/non-const.rs11
-rw-r--r--tests/ui/asm/non-const.stderr11
-rw-r--r--tests/ui/asm/x86_64/type-check-4.rs27
-rw-r--r--tests/ui/asm/x86_64/type-check-4.stderr21
-rw-r--r--tests/ui/associated-type-bounds/duplicate.stderr66
-rw-r--r--tests/ui/async-await/async-fn/edition-2015.stderr8
-rw-r--r--tests/ui/async-await/inference_var_self_argument.stderr18
-rw-r--r--tests/ui/async-await/issue-66312.stderr12
-rw-r--r--tests/ui/async-await/pin-reborrow-self.rs19
-rw-r--r--tests/ui/attributes/rustc_confusables_std_cases.rs4
-rw-r--r--tests/ui/attributes/rustc_confusables_std_cases.stderr13
-rw-r--r--tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs6
-rw-r--r--tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr20
-rw-r--r--tests/ui/cast/fat-ptr-cast.stderr2
-rw-r--r--tests/ui/cfg/crate-attributes-using-cfg_attr.rs (renamed from tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs)4
-rw-r--r--tests/ui/cfg/crate-attributes-using-cfg_attr.stderr30
-rw-r--r--tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr41
-rw-r--r--tests/ui/cfg/raw-true-false.rs19
-rw-r--r--tests/ui/cfg/true-false.rs30
-rw-r--r--tests/ui/check-cfg/invalid-arguments.rs3
-rw-r--r--tests/ui/check-cfg/invalid-arguments.unsafe_attr.stderr5
-rw-r--r--tests/ui/check-cfg/mix.stderr2
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr4
-rw-r--r--tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr6
-rw-r--r--tests/ui/codegen/sub-principals-in-codegen.rs8
-rw-r--r--tests/ui/command/command-current-dir.rs1
-rw-r--r--tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr18
-rw-r--r--tests/ui/const-generics/const-param-elided-lifetime.full.stderr8
-rw-r--r--tests/ui/const-generics/const-param-elided-lifetime.min.stderr90
-rw-r--r--tests/ui/const-generics/const-param-elided-lifetime.rs5
-rw-r--r--tests/ui/const-generics/const-param-type-depends-on-const-param.min.stderr4
-rw-r--r--tests/ui/const-generics/default-ty-closure.stderr2
-rw-r--r--tests/ui/const-generics/float-generic.simple.stderr2
-rw-r--r--tests/ui/const-generics/fn-const-param-call.min.stderr4
-rw-r--r--tests/ui/const-generics/fn-const-param-infer.min.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr2
-rw-r--r--tests/ui/const-generics/ice-118285-fn-ptr-value.stderr2
-rw-r--r--tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-56445-1.min.stderr18
-rw-r--r--tests/ui/const-generics/issues/issue-56445-1.rs1
-rw-r--r--tests/ui/const-generics/issues/issue-62878.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-68366.full.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-68366.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-68615-adt.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-68615-array.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-71169.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-71381.min.stderr4
-rw-r--r--tests/ui/const-generics/issues/issue-71382.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-71611.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-72352.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-73491.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-74101.min.stderr4
-rw-r--r--tests/ui/const-generics/issues/issue-74255.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-74950.min.stderr8
-rw-r--r--tests/ui/const-generics/issues/issue-75047.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-82956.stderr2
-rw-r--r--tests/ui/const-generics/lifetime-in-const-param.rs1
-rw-r--r--tests/ui/const-generics/lifetime-in-const-param.stderr14
-rw-r--r--tests/ui/const-generics/min_const_generics/complex-types.stderr14
-rw-r--r--tests/ui/const-generics/nested-type.min.stderr2
-rw-r--r--tests/ui/const-generics/not_wf_param_in_rpitit.rs1
-rw-r--r--tests/ui/const-generics/not_wf_param_in_rpitit.stderr16
-rw-r--r--tests/ui/const-generics/opaque_types.stderr16
-rw-r--r--tests/ui/const-generics/projection-as-arg-const.stderr2
-rw-r--r--tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr4
-rw-r--r--tests/ui/const-generics/raw-ptr-const-param.min.stderr2
-rw-r--r--tests/ui/const-generics/slice-const-param-mismatch.min.stderr4
-rw-r--r--tests/ui/const-generics/std/const-generics-range.min.stderr12
-rw-r--r--tests/ui/const-generics/transmute-const-param-static-reference.min.stderr2
-rw-r--r--tests/ui/const-generics/type-dependent/issue-71348.min.stderr4
-rw-r--r--tests/ui/const-generics/type-dependent/issue-71382.stderr2
-rw-r--r--tests/ui/consts/auxiliary/unstable_but_const_stable.rs13
-rw-r--r--tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs70
-rw-r--r--tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr53
-rw-r--r--tests/ui/consts/issue-103790.rs1
-rw-r--r--tests/ui/consts/issue-103790.stderr16
-rw-r--r--tests/ui/consts/issue-94675.rs2
-rw-r--r--tests/ui/consts/issue-94675.stderr10
-rw-r--r--tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr2
-rw-r--r--tests/ui/consts/unstable-const-stable.rs14
-rw-r--r--tests/ui/consts/unstable-const-stable.stderr43
-rw-r--r--tests/ui/coverage-attr/bad-attr-ice.feat.stderr15
-rw-r--r--tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr26
-rw-r--r--tests/ui/coverage-attr/bad-attr-ice.rs16
-rw-r--r--tests/ui/delegation/unsupported.stderr32
-rw-r--r--tests/ui/drop/lint-if-let-rescope.fixed30
-rw-r--r--tests/ui/drop/lint-if-let-rescope.rs30
-rw-r--r--tests/ui/drop/lint-if-let-rescope.stderr62
-rw-r--r--tests/ui/error-codes/E0607.stderr2
-rw-r--r--tests/ui/error-festival.stderr2
-rw-r--r--tests/ui/errors/remap-path-prefix-sysroot.rs24
-rw-r--r--tests/ui/errors/remap-path-prefix-sysroot.with-remap.stderr17
-rw-r--r--tests/ui/errors/remap-path-prefix-sysroot.without-remap.stderr17
-rw-r--r--tests/ui/feature-gates/feature-gate-adt_const_params.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs10
-rw-r--r--tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr43
-rw-r--r--tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr16
-rw-r--r--tests/ui/feature-gates/feature-gate-naked_functions.rs13
-rw-r--r--tests/ui/feature-gates/feature-gate-naked_functions.stderr48
-rw-r--r--tests/ui/feature-gates/feature-gate-pin_ergonomics.rs10
-rw-r--r--tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr26
-rw-r--r--tests/ui/feature-gates/feature-gate-unsized-const-params.stderr2
-rw-r--r--tests/ui/float/classify-runtime-const.rs5
-rw-r--r--tests/ui/float/conv-bits-runtime-const.rs3
-rw-r--r--tests/ui/generic-associated-types/self-outlives-lint.stderr22
-rw-r--r--tests/ui/generic-const-items/elided-lifetimes.rs1
-rw-r--r--tests/ui/generic-const-items/elided-lifetimes.stderr20
-rw-r--r--tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.rs7
-rw-r--r--tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.stderr11
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions1.stderr3
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions2.stderr3
-rw-r--r--tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr5
-rw-r--r--tests/ui/impl-trait/issues/issue-78722-2.stderr12
-rw-r--r--tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr44
-rw-r--r--tests/ui/impl-trait/where-allowed.stderr94
-rw-r--r--tests/ui/infinite/auxiliary/alias.rs3
-rw-r--r--tests/ui/infinite/infinite-assoc.rs16
-rw-r--r--tests/ui/infinite/infinite-assoc.stderr25
-rw-r--r--tests/ui/issues/issue-12041.stderr2
-rw-r--r--tests/ui/issues/issue-31511.rs2
-rw-r--r--tests/ui/issues/issue-31511.stderr2
-rw-r--r--tests/ui/lifetimes/unusual-rib-combinations.rs2
-rw-r--r--tests/ui/lifetimes/unusual-rib-combinations.stderr32
-rw-r--r--tests/ui/lint/invalid-nan-comparison.stderr5
-rw-r--r--tests/ui/lint/unconditional_panic_promoted.rs8
-rw-r--r--tests/ui/lint/unconditional_panic_promoted.stderr10
-rw-r--r--tests/ui/lint/unused/unused-macro-with-bad-frag-spec.stderr2
-rw-r--r--tests/ui/lint/use_suggestion_json.stderr25
-rw-r--r--tests/ui/macros/cfg.rs2
-rw-r--r--tests/ui/macros/cfg.stderr4
-rw-r--r--tests/ui/macros/expr_2021.rs14
-rw-r--r--tests/ui/macros/expr_2021_cargo_fix_edition.fixed2
-rw-r--r--tests/ui/macros/expr_2021_cargo_fix_edition.rs2
-rw-r--r--tests/ui/macros/expr_2021_cargo_fix_edition.stderr6
-rw-r--r--tests/ui/macros/expr_2021_inline_const.edi2021.stderr8
-rw-r--r--tests/ui/macros/expr_2021_inline_const.edi2024.stderr4
-rw-r--r--tests/ui/macros/expr_2021_inline_const.rs3
-rw-r--r--tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr8
-rw-r--r--tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr4
-rw-r--r--tests/ui/macros/expr_2024_underscore_expr.rs3
-rw-r--r--tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs11
-rw-r--r--tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr13
-rw-r--r--tests/ui/macros/invalid-fragment-specifier.stderr4
-rw-r--r--tests/ui/macros/issue-21356.stderr2
-rw-r--r--tests/ui/macros/macro-missing-fragment.e2024.stderr6
-rw-r--r--tests/ui/macros/metavar_cross_edition_recursive_macros.rs1
-rw-r--r--tests/ui/methods/dont-suggest-import-on-deref-err.rs13
-rw-r--r--tests/ui/methods/dont-suggest-import-on-deref-err.stderr12
-rw-r--r--tests/ui/mismatched_types/cast-rfc0401.stderr2
-rw-r--r--tests/ui/never_type/diverging-place-match.rs74
-rw-r--r--tests/ui/never_type/diverging-place-match.stderr142
-rw-r--r--tests/ui/panic-handler/panic-handler-with-track-caller.stderr2
-rw-r--r--tests/ui/parser/bad-name.stderr4
-rw-r--r--tests/ui/parser/issues/issue-24197.stderr4
-rw-r--r--tests/ui/parser/issues/issue-24375.stderr3
-rw-r--r--tests/ui/parser/pat-lt-bracket-5.stderr4
-rw-r--r--tests/ui/parser/pat-lt-bracket-6.stderr4
-rw-r--r--tests/ui/parser/pat-ranges-3.stderr8
-rw-r--r--tests/ui/parser/recover/recover-pat-exprs.stderr103
-rw-r--r--tests/ui/parser/recover/recover-pat-issues.stderr18
-rw-r--r--tests/ui/parser/recover/recover-pat-lets.stderr18
-rw-r--r--tests/ui/parser/recover/recover-pat-ranges.stderr18
-rw-r--r--tests/ui/parser/recover/recover-pat-wildcards.stderr3
-rw-r--r--tests/ui/pattern/at-in-struct-patterns.rs14
-rw-r--r--tests/ui/pattern/at-in-struct-patterns.stderr69
-rw-r--r--tests/ui/privacy/private-type-in-interface.rs2
-rw-r--r--tests/ui/privacy/private-type-in-interface.stderr16
-rw-r--r--tests/ui/raw-ref-op/never-place-isnt-diverging.rs22
-rw-r--r--tests/ui/raw-ref-op/never-place-isnt-diverging.stderr34
-rw-r--r--tests/ui/reachable/expr_assign.stderr9
-rw-r--r--tests/ui/resolve/issue-10200.rs2
-rw-r--r--tests/ui/resolve/issue-10200.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs6
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr16
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr16
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs6
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr29
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs7
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr29
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs6
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr29
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr56
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr8
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs6
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr29
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr6
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr10
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr10
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr10
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr22
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs2
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr23
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr22
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr16
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs1
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr14
-rw-r--r--tests/ui/self/arbitrary-self-opaque.stderr18
-rw-r--r--tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr12
-rw-r--r--tests/ui/self/elision/lt-ref-self-async.fixed12
-rw-r--r--tests/ui/self/elision/lt-ref-self-async.stderr24
-rw-r--r--tests/ui/self/elision/ref-assoc-async.stderr20
-rw-r--r--tests/ui/self/elision/ref-mut-self-async.stderr24
-rw-r--r--tests/ui/self/elision/ref-mut-struct-async.stderr20
-rw-r--r--tests/ui/self/elision/ref-self-async.stderr28
-rw-r--r--tests/ui/self/elision/ref-struct-async.stderr20
-rw-r--r--tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr4
-rw-r--r--tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr2
-rw-r--r--tests/ui/traits/missing-for-type-in-impl.e2015.stderr74
-rw-r--r--tests/ui/traits/missing-for-type-in-impl.e2021.stderr31
-rw-r--r--tests/ui/traits/missing-for-type-in-impl.rs22
-rw-r--r--tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr4
-rw-r--r--tests/ui/traits/next-solver/overflow/coherence-alias-hang-with-region.rs30
-rw-r--r--tests/ui/traits/next-solver/overflow/coherence-alias-hang.rs (renamed from tests/ui/traits/coherence-alias-hang.rs)11
-rw-r--r--tests/ui/traits/next-solver/overflow/nalgebra-hang.rs35
-rw-r--r--tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.rs24
-rw-r--r--tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr12
-rw-r--r--tests/ui/traits/object/pretty.rs4
-rw-r--r--tests/ui/traits/object/pretty.stderr13
-rw-r--r--tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs15
-rw-r--r--tests/ui/transmutability/assoc-bound.rs25
-rw-r--r--tests/ui/transmutability/assoc-bound.stderr31
-rw-r--r--tests/ui/try-trait/bad-interconversion.rs2
-rw-r--r--tests/ui/try-trait/bad-interconversion.stderr16
-rw-r--r--tests/ui/try-trait/try-operator-custom.rs1
-rw-r--r--tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs18
-rw-r--r--tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr28
-rw-r--r--tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr16
-rw-r--r--tests/ui/type-alias-impl-trait/constrain_inputs.stderr26
-rw-r--r--tests/ui/type-alias-impl-trait/generic_underconstrained.stderr22
-rw-r--r--tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr44
-rw-r--r--tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr12
-rw-r--r--tests/ui/type-alias-impl-trait/in-where-clause.stderr42
-rw-r--r--tests/ui/type-alias-impl-trait/issue-53092-2.rs9
-rw-r--r--tests/ui/type-alias-impl-trait/issue-53092-2.stderr66
-rw-r--r--tests/ui/type-alias-impl-trait/issue-84660-unsoundness.current.stderr18
-rw-r--r--tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr18
-rw-r--r--tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr16
-rw-r--r--tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs13
-rw-r--r--tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr30
-rw-r--r--tests/ui/type-alias-impl-trait/non-lifetime-binder.rs10
-rw-r--r--tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr25
-rw-r--r--tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr14
-rw-r--r--tests/ui/typeck/ice-unexpected-region-123863.stderr4
-rw-r--r--tests/ui/typeck/typeck_type_placeholder_item.rs4
-rw-r--r--tests/ui/typeck/typeck_type_placeholder_item.stderr91
-rw-r--r--tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs2
-rw-r--r--tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr44
-rw-r--r--tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr4
-rw-r--r--triagebot.toml4
1292 files changed, 20276 insertions, 9945 deletions
diff --git a/.github/ISSUE_TEMPLATE/blank_issue.md b/.github/ISSUE_TEMPLATE/blank_issue.md
deleted file mode 100644
index 9aef3ebe637..00000000000
--- a/.github/ISSUE_TEMPLATE/blank_issue.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-name: Blank Issue
-about: Create a blank issue.
----
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index fd54a153a16..ecf8f993f90 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -7,6 +7,6 @@ tracking issue or there are none, feel free to ignore this.
 This PR will get automatically assigned to a reviewer. In case you would like
 a specific user to review your work, you can assign it to them by using
 
-    r​? <reviewer name>
+    r\? <reviewer name> (with the `\` removed)
 -->
 <!-- homu-ignore:end -->
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8032154a736..b6dc27f1234 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -212,6 +212,16 @@ jobs:
         # erroring about invalid credentials instead.
         if: github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1'
 
+      - name: upload job metrics to DataDog
+        if: needs.calculate_matrix.outputs.run_type != 'pr'
+        env:
+          DATADOG_SITE: datadoghq.com
+          DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}
+          DD_GITHUB_JOB_NAME: ${{ matrix.name }}
+        run: |
+          npm install -g @datadog/datadog-ci@^2.x.x
+          python3 src/ci/scripts/upload-build-metrics.py build/cpu-usage.csv
+
   # This job isused to tell bors the final status of the build, as there is no practical way to detect
   # when a workflow is successful listening to webhooks only in our current bors implementation (homu).
   outcome:
diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml
index 83b92b7fa09..b7b5a03bd41 100644
--- a/.github/workflows/dependencies.yml
+++ b/.github/workflows/dependencies.yml
@@ -61,9 +61,11 @@ jobs:
           rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN
           rustup default $TOOLCHAIN
 
-      - name: cargo update
+      - name: cargo update compiler & tools
         # Remove first line that always just says "Updating crates.io index"
-        run: cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
+        run: |
+          echo -e "\ncompiler & tools dependencies:" >> cargo_update.log
+          cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
       - name: cargo update library
         run: |
           echo -e "\nlibrary dependencies:" >> cargo_update.log
diff --git a/.gitignore b/.gitignore
index d6d8b99f602..b170dca88fa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -86,4 +86,13 @@ package.json
 ## Rustdoc GUI tests
 tests/rustdoc-gui/src/**.lock
 
+## direnv
+.envrc
+.direnv/
+
+## nix
+flake.nix
+flake.lock
+default.nix
+
 # Before adding new lines, see the comment at the top.
diff --git a/Cargo.lock b/Cargo.lock
index ebb8d114f2a..502920350d5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -200,6 +200,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "arrayref"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
+
+[[package]]
 name = "arrayvec"
 version = "0.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -207,9 +213,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
 
 [[package]]
 name = "autocfg"
-version = "1.3.0"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
 
 [[package]]
 name = "backtrace"
@@ -263,6 +269,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
 
 [[package]]
+name = "blake3"
+version = "1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d08263faac5cde2a4d52b513dadb80846023aade56fcd8fc99ba73ba8050e92"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "cc",
+ "cfg-if",
+ "constant_time_eq",
+]
+
+[[package]]
 name = "block-buffer"
 version = "0.10.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -393,9 +412,12 @@ version = "0.1.0"
 
 [[package]]
 name = "cc"
-version = "1.0.105"
+version = "1.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5208975e568d83b6b05cc0a063c8e7e9acc2b43bee6da15616a5b73e109d7437"
+checksum = "3bbb537bb4a30b90362caddba8f360c0a56bc13d3a5570028e7197204cb54a17"
+dependencies = [
+ "shlex",
+]
 
 [[package]]
 name = "cfg-if"
@@ -424,9 +446,9 @@ dependencies = [
 
 [[package]]
 name = "chrono-tz"
-version = "0.9.0"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb"
+checksum = "cd6dd8046d00723a59a2f8c5f295c515b9bb9a331ee4f8f3d4dd49e428acd3b6"
 dependencies = [
  "chrono",
  "chrono-tz-build",
@@ -435,12 +457,11 @@ dependencies = [
 
 [[package]]
 name = "chrono-tz-build"
-version = "0.3.0"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1"
+checksum = "e94fea34d77a245229e7746bd2beb786cd2a896f306ff491fb8cecb3074b10a7"
 dependencies = [
  "parse-zoneinfo",
- "phf",
  "phf_codegen",
 ]
 
@@ -505,7 +526,7 @@ dependencies = [
  "heck 0.5.0",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -534,7 +555,7 @@ dependencies = [
  "rustc_tools_util",
  "serde",
  "serde_json",
- "syn 2.0.77",
+ "syn 2.0.79",
  "tempfile",
  "termize",
  "tokio",
@@ -643,7 +664,7 @@ dependencies = [
  "nom",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -721,6 +742,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "constant_time_eq"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2"
+
+[[package]]
 name = "core-foundation-sys"
 version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -861,7 +888,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "strsim",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -872,7 +899,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
 dependencies = [
  "darling_core",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -898,7 +925,7 @@ version = "0.1.83"
 dependencies = [
  "itertools",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -918,7 +945,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -939,7 +966,7 @@ dependencies = [
  "darling",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -949,7 +976,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc"
 dependencies = [
  "derive_builder_core",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -961,7 +988,7 @@ dependencies = [
  "darling",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -1039,7 +1066,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -1192,9 +1219,9 @@ dependencies = [
 
 [[package]]
 name = "flate2"
-version = "1.0.33"
+version = "1.0.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253"
+checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0"
 dependencies = [
  "crc32fast",
  "miniz_oxide 0.8.0",
@@ -1330,7 +1357,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -1554,7 +1581,7 @@ dependencies = [
  "markup5ever",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -1686,7 +1713,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -2661,7 +2688,7 @@ dependencies = [
  "pest_meta",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -2763,9 +2790,9 @@ dependencies = [
 
 [[package]]
 name = "portable-atomic"
-version = "1.8.0"
+version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d30538d42559de6b034bc76fd6dd4c38961b1ee5c6c56e3808c50128fdbc22ce"
+checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
 
 [[package]]
 name = "powerfmt"
@@ -3073,7 +3100,7 @@ dependencies = [
  "rinja_parser",
  "rustc-hash 2.0.0",
  "serde",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -3449,6 +3476,7 @@ dependencies = [
  "rustc_span",
  "rustc_symbol_mangling",
  "rustc_target",
+ "rustc_trait_selection",
  "rustc_type_ir",
  "serde_json",
  "smallvec",
@@ -3671,7 +3699,7 @@ dependencies = [
  "fluent-syntax",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
  "unic-langid",
 ]
 
@@ -3805,7 +3833,7 @@ version = "0.0.0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -3954,7 +3982,7 @@ version = "0.0.0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
  "synstructure",
 ]
 
@@ -4375,6 +4403,7 @@ dependencies = [
 name = "rustc_span"
 version = "0.0.0"
 dependencies = [
+ "blake3",
  "derive-where",
  "indexmap",
  "itoa",
@@ -4535,7 +4564,7 @@ version = "0.0.0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
  "synstructure",
 ]
 
@@ -4623,7 +4652,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "serde",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -4760,7 +4789,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -5024,9 +5053,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.77"
+version = "2.0.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
+checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5041,7 +5070,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -5078,9 +5107,9 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.12.0"
+version = "3.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
+checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
 dependencies = [
  "cfg-if",
  "fastrand",
@@ -5174,7 +5203,7 @@ checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -5365,7 +5394,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -5536,7 +5565,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b"
 dependencies = [
  "proc-macro-hack",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
  "unic-langid-impl",
 ]
 
@@ -5734,7 +5763,7 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
  "wasm-bindgen-shared",
 ]
 
@@ -5756,7 +5785,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -5769,16 +5798,16 @@ checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
 
 [[package]]
 name = "wasm-component-ld"
-version = "0.5.8"
+version = "0.5.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb17cdbc91766d4ea0bcd6026c36ba77a21b5c8199aeb1f0993461fe6a6bec2b"
+checksum = "fde17bc96539700198e12516230c76095cc215c84ef39ad206e1af3f84243e0f"
 dependencies = [
  "anyhow",
  "clap",
  "lexopt",
  "tempfile",
  "wasi-preview1-component-adapter-provider",
- "wasmparser 0.217.0",
+ "wasmparser 0.218.0",
  "wat",
  "wit-component",
  "wit-parser",
@@ -5802,19 +5831,19 @@ dependencies = [
 
 [[package]]
 name = "wasm-encoder"
-version = "0.217.0"
+version = "0.218.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b88b0814c9a2b323a9b46c687e726996c255ac8b64aa237dd11c81ed4854760"
+checksum = "22b896fa8ceb71091ace9bcb81e853f54043183a1c9667cf93422c40252ffa0a"
 dependencies = [
  "leb128",
- "wasmparser 0.217.0",
+ "wasmparser 0.218.0",
 ]
 
 [[package]]
 name = "wasm-metadata"
-version = "0.217.0"
+version = "0.218.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65a146bf9a60e9264f0548a2599aa9656dba9a641eff9ab88299dc2a637e483c"
+checksum = "aa5eeb071abe8a2132fdd5565dabffee70775ee8c24fc7e300ac43f51f4a8a91"
 dependencies = [
  "anyhow",
  "indexmap",
@@ -5822,8 +5851,8 @@ dependencies = [
  "serde_derive",
  "serde_json",
  "spdx",
- "wasm-encoder 0.217.0",
- "wasmparser 0.217.0",
+ "wasm-encoder 0.218.0",
+ "wasmparser 0.218.0",
 ]
 
 [[package]]
@@ -5838,9 +5867,9 @@ dependencies = [
 
 [[package]]
 name = "wasmparser"
-version = "0.217.0"
+version = "0.218.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca917a21307d3adf2b9857b94dd05ebf8496bdcff4437a9b9fb3899d3e6c74e7"
+checksum = "b09e46c7fceceaa72b2dd1a8a137ea7fd8f93dfaa69806010a709918e496c5dc"
 dependencies = [
  "ahash",
  "bitflags 2.6.0",
@@ -5852,22 +5881,22 @@ dependencies = [
 
 [[package]]
 name = "wast"
-version = "217.0.0"
+version = "218.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79004ecebded92d3c710d4841383368c7f04b63d0992ddd6b0c7d5029b7629b7"
+checksum = "8a53cd1f0fa505df97557e36a58bddb8296e2fcdcd089529545ebfdb18a1b9d7"
 dependencies = [
  "bumpalo",
  "leb128",
  "memchr",
  "unicode-width",
- "wasm-encoder 0.217.0",
+ "wasm-encoder 0.218.0",
 ]
 
 [[package]]
 name = "wat"
-version = "1.217.0"
+version = "1.218.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c126271c3d92ca0f7c63e4e462e40c69cca52fd4245fcda730d1cf558fb55088"
+checksum = "4f87f8e14e776762e07927c27c2054d2cf678aab9aae2d431a79b3e31e4dd391"
 dependencies = [
  "wast",
 ]
@@ -5923,7 +5952,7 @@ dependencies = [
  "rayon",
  "serde",
  "serde_json",
- "syn 2.0.77",
+ "syn 2.0.79",
  "windows-metadata",
 ]
 
@@ -5956,7 +5985,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -5967,7 +5996,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -6144,9 +6173,9 @@ dependencies = [
 
 [[package]]
 name = "wit-component"
-version = "0.217.0"
+version = "0.218.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7117809905e49db716d81e794f79590c052bf2fdbbcda1731ca0fb28f6f3ddf"
+checksum = "aa53aa7e6bf2b3e8ccaffbcc963fbdb672a603dc0af393a481b6cec24c266406"
 dependencies = [
  "anyhow",
  "bitflags 2.6.0",
@@ -6155,17 +6184,17 @@ dependencies = [
  "serde",
  "serde_derive",
  "serde_json",
- "wasm-encoder 0.217.0",
+ "wasm-encoder 0.218.0",
  "wasm-metadata",
- "wasmparser 0.217.0",
+ "wasmparser 0.218.0",
  "wit-parser",
 ]
 
 [[package]]
 name = "wit-parser"
-version = "0.217.0"
+version = "0.218.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb893dcd6d370cfdf19a0d9adfcd403efb8e544e1a0ea3a8b81a21fe392eaa78"
+checksum = "0d3d1066ab761b115f97fef2b191090faabcb0f37b555b758d3caf42d4ed9e55"
 dependencies = [
  "anyhow",
  "id-arena",
@@ -6176,7 +6205,7 @@ dependencies = [
  "serde_derive",
  "serde_json",
  "unicode-xid",
- "wasmparser 0.217.0",
+ "wasmparser 0.218.0",
 ]
 
 [[package]]
@@ -6234,7 +6263,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
  "synstructure",
 ]
 
@@ -6256,7 +6285,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
 
 [[package]]
@@ -6276,7 +6305,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
  "synstructure",
 ]
 
@@ -6299,5 +6328,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.77",
+ "syn 2.0.79",
 ]
diff --git a/INSTALL.md b/INSTALL.md
index ded0b59fc6c..74fcc58348b 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -79,9 +79,23 @@ See [the rustc-dev-guide for more info][sysllvm].
    ./configure
    ```
 
-   If you plan to use `x.py install` to create an installation, it is
-   recommended that you set the `prefix` value in the `[install]` section to a
-   directory: `./configure --set install.prefix=<path>`
+   If you plan to use `x.py install` to create an installation, you can either
+   set `DESTDIR` environment variable to your custom directory path:
+
+   ```bash
+   export DESTDIR=<path>
+   ```
+
+   or set `prefix` and `sysconfdir` in the `[install]` section to your custom
+   directory path:
+
+   ```sh
+   ./configure --set install.prefix=<path> --set install.sysconfdir=<path>
+   ```
+
+   When the `DESTDIR` environment variable is present, the `prefix` and
+   `sysconfdir` values are combined with the path from the `DESTDIR`
+   environment variable.
 
 3. Build and install:
 
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 37f429cce44..733c2d93114 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2278,7 +2278,7 @@ impl InlineAsmOptions {
     pub const COUNT: usize = Self::all().bits().count_ones() as usize;
 
     pub const GLOBAL_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW);
-    pub const NAKED_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW).union(Self::NORETURN);
+    pub const NAKED_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW);
 
     pub fn human_readable_names(&self) -> Vec<&'static str> {
         let mut options = vec![];
@@ -2434,6 +2434,32 @@ pub enum AsmMacro {
     NakedAsm,
 }
 
+impl AsmMacro {
+    pub const fn macro_name(self) -> &'static str {
+        match self {
+            AsmMacro::Asm => "asm",
+            AsmMacro::GlobalAsm => "global_asm",
+            AsmMacro::NakedAsm => "naked_asm",
+        }
+    }
+
+    pub const fn is_supported_option(self, option: InlineAsmOptions) -> bool {
+        match self {
+            AsmMacro::Asm => true,
+            AsmMacro::GlobalAsm => InlineAsmOptions::GLOBAL_OPTIONS.contains(option),
+            AsmMacro::NakedAsm => InlineAsmOptions::NAKED_OPTIONS.contains(option),
+        }
+    }
+
+    pub const fn diverges(self, options: InlineAsmOptions) -> bool {
+        match self {
+            AsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN),
+            AsmMacro::GlobalAsm => true,
+            AsmMacro::NakedAsm => true,
+        }
+    }
+}
+
 /// Inline assembly.
 ///
 /// E.g., `asm!("NOP");`.
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 124d0acfa49..338d50cb394 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -527,6 +527,16 @@ impl NestedMetaItem {
         }
     }
 
+    /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem` or if it's
+    /// `NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(_), .. })`.
+    pub fn meta_item_or_bool(&self) -> Option<&NestedMetaItem> {
+        match self {
+            NestedMetaItem::MetaItem(_item) => Some(self),
+            NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self),
+            _ => None,
+        }
+    }
+
     /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
     pub fn meta_item(&self) -> Option<&MetaItem> {
         match self {
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index e77c0fb3a3e..6289966561f 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -226,6 +226,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         });
     }
 
+    fn visit_opaque_ty(&mut self, opaq: &'hir OpaqueTy<'hir>) {
+        self.insert(opaq.span, opaq.hir_id, Node::OpaqueTy(opaq));
+
+        self.with_parent(opaq.hir_id, |this| {
+            intravisit::walk_opaque_ty(this, opaq);
+        });
+    }
+
     fn visit_anon_const(&mut self, constant: &'hir AnonConst) {
         // FIXME: use real span?
         self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant));
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 7bb3b2fa290..1273b50dff8 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -286,7 +286,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                                 parent: this.local_def_id(id),
                                 in_assoc_ty: false,
                             },
-                            fn_kind: None,
                         }),
                     },
                 );
@@ -983,7 +982,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                                     parent: this.local_def_id(i.id),
                                     in_assoc_ty: true,
                                 },
-                                fn_kind: None,
                             });
                             hir::ImplItemKind::Type(ty)
                         }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index c6cb7aa7dd5..b26797f4203 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -288,12 +288,7 @@ enum ImplTraitContext {
     /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
     /// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`.
     ///
-    OpaqueTy {
-        origin: hir::OpaqueTyOrigin,
-        /// Only used to change the lifetime capture rules, since
-        /// RPITIT captures all in scope, RPIT does not.
-        fn_kind: Option<FnDeclKind>,
-    },
+    OpaqueTy { origin: hir::OpaqueTyOrigin },
     /// `impl Trait` is unstably accepted in this position.
     FeatureGated(ImplTraitPosition, Symbol),
     /// `impl Trait` is not accepted in this position.
@@ -1404,14 +1399,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             TyKind::ImplTrait(def_node_id, bounds) => {
                 let span = t.span;
                 match itctx {
-                    ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait(
-                        span,
-                        origin,
-                        *def_node_id,
-                        bounds,
-                        fn_kind,
-                        itctx,
-                    ),
+                    ImplTraitContext::OpaqueTy { origin } => {
+                        self.lower_opaque_impl_trait(span, origin, *def_node_id, bounds, itctx)
+                    }
                     ImplTraitContext::Universal => {
                         if let Some(span) = bounds.iter().find_map(|bound| match *bound {
                             ast::GenericBound::Use(_, span) => Some(span),
@@ -1513,7 +1503,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         origin: hir::OpaqueTyOrigin,
         opaque_ty_node_id: NodeId,
         bounds: &GenericBounds,
-        fn_kind: Option<FnDeclKind>,
         itctx: ImplTraitContext,
     ) -> hir::TyKind<'hir> {
         // Make sure we know that some funky desugaring has been going on here.
@@ -1555,11 +1544,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         .map(|(ident, id, _)| Lifetime { id, ident })
                         .collect()
                 }
-                hir::OpaqueTyOrigin::FnReturn(..) => {
-                    if matches!(
-                        fn_kind.expect("expected RPITs to be lowered with a FnKind"),
-                        FnDeclKind::Impl | FnDeclKind::Trait
-                    ) || self.tcx.features().lifetime_capture_rules_2024
+                hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => {
+                    if in_trait_or_impl.is_some()
+                        || self.tcx.features().lifetime_capture_rules_2024
                         || span.at_least_rust_2024()
                     {
                         // return-position impl trait in trait was decided to capture all
@@ -1576,16 +1563,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)
                     }
                 }
-                hir::OpaqueTyOrigin::AsyncFn(..) => {
+                hir::OpaqueTyOrigin::AsyncFn { .. } => {
                     unreachable!("should be using `lower_async_fn_ret_ty`")
                 }
             }
         };
         debug!(?captured_lifetimes_to_duplicate);
 
-        match fn_kind {
-            // Deny `use<>` on RPITIT in trait/trait-impl for now.
-            Some(FnDeclKind::Trait | FnDeclKind::Impl) => {
+        // Feature gate for RPITIT + use<..>
+        match origin {
+            rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => {
                 if let Some(span) = bounds.iter().find_map(|bound| match *bound {
                     ast::GenericBound::Use(_, span) => Some(span),
                     _ => None,
@@ -1593,20 +1580,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnRpitit { span });
                 }
             }
-            None
-            | Some(
-                FnDeclKind::Fn
-                | FnDeclKind::Inherent
-                | FnDeclKind::ExternFn
-                | FnDeclKind::Closure
-                | FnDeclKind::Pointer,
-            ) => {}
+            _ => {}
         }
 
         self.lower_opaque_inner(
             opaque_ty_node_id,
             origin,
-            matches!(fn_kind, Some(FnDeclKind::Trait)),
             captured_lifetimes_to_duplicate,
             span,
             opaque_ty_span,
@@ -1618,14 +1597,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         &mut self,
         opaque_ty_node_id: NodeId,
         origin: hir::OpaqueTyOrigin,
-        in_trait: bool,
         captured_lifetimes_to_duplicate: FxIndexSet<Lifetime>,
         span: Span,
         opaque_ty_span: Span,
         lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
     ) -> hir::TyKind<'hir> {
         let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
-        debug!(?opaque_ty_def_id);
+        let opaque_ty_hir_id = self.lower_node_id(opaque_ty_node_id);
+        debug!(?opaque_ty_def_id, ?opaque_ty_hir_id);
 
         // Map from captured (old) lifetime to synthetic (new) lifetime.
         // Used to resolve lifetimes in the bounds of the opaque.
@@ -1698,7 +1677,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             }
         }
 
-        self.with_hir_id_owner(opaque_ty_node_id, |this| {
+        let opaque_ty_def = self.with_def_id_parent(opaque_ty_def_id, |this| {
             // Install the remapping from old to new (if any). This makes sure that
             // any lifetimes that would have resolved to the def-id of captured
             // lifetimes are remapped to the new *synthetic* lifetimes of the opaque.
@@ -1736,7 +1715,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
             let lifetime_mapping = self.arena.alloc_slice(&synthesized_lifetime_args);
 
-            let opaque_ty_item = hir::OpaqueTy {
+            trace!("registering opaque type with id {:#?}", opaque_ty_def_id);
+            let opaque_ty_def = hir::OpaqueTy {
+                hir_id: opaque_ty_hir_id,
+                def_id: opaque_ty_def_id,
                 generics: this.arena.alloc(hir::Generics {
                     params: generic_params,
                     predicates: &[],
@@ -1747,20 +1729,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 bounds,
                 origin,
                 lifetime_mapping,
-                in_trait,
-            };
-
-            // Generate an `type Foo = impl Trait;` declaration.
-            trace!("registering opaque type with id {:#?}", opaque_ty_def_id);
-            let opaque_ty_item = hir::Item {
-                owner_id: hir::OwnerId { def_id: opaque_ty_def_id },
-                ident: Ident::empty(),
-                kind: hir::ItemKind::OpaqueTy(this.arena.alloc(opaque_ty_item)),
-                vis_span: this.lower_span(span.shrink_to_lo()),
                 span: this.lower_span(opaque_ty_span),
             };
-
-            hir::OwnerNode::Item(this.arena.alloc(opaque_ty_item))
+            this.arena.alloc(opaque_ty_def)
         });
 
         let generic_args = self.arena.alloc_from_iter(
@@ -1773,11 +1744,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // Foo = impl Trait` is, internally, created as a child of the
         // async fn, so the *type parameters* are inherited. It's
         // only the lifetime parameters that we must supply.
-        hir::TyKind::OpaqueDef(
-            hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
-            generic_args,
-            in_trait,
-        )
+        hir::TyKind::OpaqueDef(opaque_ty_def, generic_args)
     }
 
     fn lower_precise_capturing_args(
@@ -1864,12 +1831,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             None => match &decl.output {
                 FnRetTy::Ty(ty) => {
                     let itctx = match kind {
-                        FnDeclKind::Fn
-                        | FnDeclKind::Inherent
-                        | FnDeclKind::Trait
-                        | FnDeclKind::Impl => ImplTraitContext::OpaqueTy {
-                            origin: hir::OpaqueTyOrigin::FnReturn(self.local_def_id(fn_node_id)),
-                            fn_kind: Some(kind),
+                        FnDeclKind::Fn | FnDeclKind::Inherent => ImplTraitContext::OpaqueTy {
+                            origin: hir::OpaqueTyOrigin::FnReturn {
+                                parent: self.local_def_id(fn_node_id),
+                                in_trait_or_impl: None,
+                            },
+                        },
+                        FnDeclKind::Trait => ImplTraitContext::OpaqueTy {
+                            origin: hir::OpaqueTyOrigin::FnReturn {
+                                parent: self.local_def_id(fn_node_id),
+                                in_trait_or_impl: Some(hir::RpitContext::Trait),
+                            },
+                        },
+                        FnDeclKind::Impl => ImplTraitContext::OpaqueTy {
+                            origin: hir::OpaqueTyOrigin::FnReturn {
+                                parent: self.local_def_id(fn_node_id),
+                                in_trait_or_impl: Some(hir::RpitContext::TraitImpl),
+                            },
                         },
                         FnDeclKind::ExternFn => {
                             ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnReturn)
@@ -1951,10 +1929,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             .map(|(ident, id, _)| Lifetime { id, ident })
             .collect();
 
+        let in_trait_or_impl = match fn_kind {
+            FnDeclKind::Trait => Some(hir::RpitContext::Trait),
+            FnDeclKind::Impl => Some(hir::RpitContext::TraitImpl),
+            FnDeclKind::Fn | FnDeclKind::Inherent => None,
+            FnDeclKind::ExternFn | FnDeclKind::Closure | FnDeclKind::Pointer => unreachable!(),
+        };
+
         let opaque_ty_ref = self.lower_opaque_inner(
             opaque_ty_node_id,
-            hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
-            matches!(fn_kind, FnDeclKind::Trait),
+            hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl },
             captured_lifetimes,
             span,
             opaque_ty_span,
@@ -1964,8 +1948,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     coro,
                     opaque_ty_span,
                     ImplTraitContext::OpaqueTy {
-                        origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
-                        fn_kind: Some(fn_kind),
+                        origin: hir::OpaqueTyOrigin::FnReturn {
+                            parent: fn_def_id,
+                            in_trait_or_impl,
+                        },
                     },
                 );
                 arena_vec![this; bound]
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 229d04f8de2..5bdd9b6eda8 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -63,7 +63,7 @@ impl TraitOrTraitImpl {
 }
 
 struct AstValidator<'a> {
-    session: &'a Session,
+    sess: &'a Session,
     features: &'a Features,
 
     /// The span of the `extern` in an `extern { ... }` block, if any.
@@ -267,7 +267,7 @@ impl<'a> AstValidator<'a> {
     }
 
     fn dcx(&self) -> DiagCtxtHandle<'a> {
-        self.session.dcx()
+        self.sess.dcx()
     }
 
     fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) {
@@ -359,7 +359,7 @@ impl<'a> AstValidator<'a> {
             in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
             const_context_label: parent_constness,
             remove_const_sugg: (
-                self.session.source_map().span_extend_while_whitespace(span),
+                self.sess.source_map().span_extend_while_whitespace(span),
                 match parent_constness {
                     Some(_) => rustc_errors::Applicability::MachineApplicable,
                     None => rustc_errors::Applicability::MaybeIncorrect,
@@ -472,7 +472,7 @@ impl<'a> AstValidator<'a> {
 
     fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
         if let Defaultness::Default(def_span) = defaultness {
-            let span = self.session.source_map().guess_head_span(span);
+            let span = self.sess.source_map().guess_head_span(span);
             self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
         }
     }
@@ -480,7 +480,7 @@ impl<'a> AstValidator<'a> {
     /// If `sp` ends with a semicolon, returns it as a `Span`
     /// Otherwise, returns `sp.shrink_to_hi()`
     fn ending_semi_or_hi(&self, sp: Span) -> Span {
-        let source_map = self.session.source_map();
+        let source_map = self.sess.source_map();
         let end = source_map.end_point(sp);
 
         if source_map.span_to_snippet(end).is_ok_and(|s| s == ";") {
@@ -552,7 +552,7 @@ impl<'a> AstValidator<'a> {
     }
 
     fn current_extern_span(&self) -> Span {
-        self.session.source_map().guess_head_span(self.extern_mod.unwrap())
+        self.sess.source_map().guess_head_span(self.extern_mod.unwrap())
     }
 
     /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
@@ -648,7 +648,7 @@ impl<'a> AstValidator<'a> {
         if ident.name.as_str().is_ascii() {
             return;
         }
-        let span = self.session.source_map().guess_head_span(item_span);
+        let span = self.sess.source_map().guess_head_span(item_span);
         self.dcx().emit_err(errors::NoMangleAscii { span });
     }
 
@@ -753,7 +753,7 @@ impl<'a> AstValidator<'a> {
                     self.dcx().emit_err(errors::PatternFnPointer { span });
                 });
                 if let Extern::Implicit(_) = bfty.ext {
-                    let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
+                    let sig_span = self.sess.source_map().next_point(ty.span.shrink_to_lo());
                     self.maybe_lint_missing_abi(sig_span, ty.id);
                 }
             }
@@ -795,7 +795,7 @@ impl<'a> AstValidator<'a> {
         // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
         // call site which do not have a macro backtrace. See #61963.
         if self
-            .session
+            .sess
             .source_map()
             .span_to_snippet(span)
             .is_ok_and(|snippet| !snippet.starts_with("#["))
@@ -885,7 +885,7 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara
 
 impl<'a> Visitor<'a> for AstValidator<'a> {
     fn visit_attribute(&mut self, attr: &Attribute) {
-        validate_attr::check_attr(&self.session.psess, attr);
+        validate_attr::check_attr(&self.sess.psess, attr);
     }
 
     fn visit_ty(&mut self, ty: &'a Ty) {
@@ -1192,7 +1192,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 } else if where_clauses.after.has_where_token {
                     self.dcx().emit_err(errors::WhereClauseAfterTypeAlias {
                         span: where_clauses.after.span,
-                        help: self.session.is_nightly_build(),
+                        help: self.sess.is_nightly_build(),
                     });
                 }
             }
@@ -1328,7 +1328,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_))
                         if !self.features.more_maybe_bounds =>
                     {
-                        self.session
+                        self.sess
                             .create_feature_err(
                                 errors::OptionalTraitSupertrait {
                                     span: trait_ref.span,
@@ -1341,7 +1341,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_))
                         if !self.features.more_maybe_bounds =>
                     {
-                        self.session
+                        self.sess
                             .create_feature_err(
                                 errors::OptionalTraitObject { span: trait_ref.span },
                                 sym::more_maybe_bounds,
@@ -1752,13 +1752,13 @@ fn deny_equality_constraints(
 }
 
 pub fn check_crate(
-    session: &Session,
+    sess: &Session,
     features: &Features,
     krate: &Crate,
     lints: &mut LintBuffer,
 ) -> bool {
     let mut validator = AstValidator {
-        session,
+        sess,
         features,
         extern_mod: None,
         outer_trait_or_trait_impl: None,
diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl
index 5d9ac23ec49..adabf18ca85 100644
--- a/compiler/rustc_attr/messages.ftl
+++ b/compiler/rustc_attr/messages.ftl
@@ -107,6 +107,8 @@ attr_unknown_version_literal =
 attr_unstable_cfg_target_compact =
     compact `cfg(target(..))` is experimental and subject to change
 
+attr_unsupported_literal_cfg_boolean =
+    literal in `cfg` predicate value must be a boolean
 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 762ebc47ca9..d6a7dbad12d 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -18,7 +18,7 @@ use rustc_session::parse::feature_err;
 use rustc_session::{RustcVersion, Session};
 use rustc_span::Span;
 use rustc_span::hygiene::Transparency;
-use rustc_span::symbol::{Symbol, sym};
+use rustc_span::symbol::{Symbol, kw, sym};
 
 use crate::fluent_generated;
 use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
@@ -36,6 +36,7 @@ pub fn is_builtin_attr(attr: &Attribute) -> bool {
 pub(crate) enum UnsupportedLiteralReason {
     Generic,
     CfgString,
+    CfgBoolean,
     DeprecatedString,
     DeprecatedKvPair,
 }
@@ -80,6 +81,10 @@ impl Stability {
     pub fn is_stable(&self) -> bool {
         self.level.is_stable()
     }
+
+    pub fn stable_since(&self) -> Option<StableSince> {
+        self.level.stable_since()
+    }
 }
 
 /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
@@ -170,6 +175,12 @@ impl StabilityLevel {
     pub fn is_stable(&self) -> bool {
         matches!(self, StabilityLevel::Stable { .. })
     }
+    pub fn stable_since(&self) -> Option<StableSince> {
+        match *self {
+            StabilityLevel::Stable { since, .. } => Some(since),
+            StabilityLevel::Unstable { .. } => None,
+        }
+    }
 }
 
 #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
@@ -523,7 +534,7 @@ pub struct Condition {
 
 /// Tests if a cfg-pattern matches the cfg set
 pub fn cfg_matches(
-    cfg: &ast::MetaItem,
+    cfg: &ast::NestedMetaItem,
     sess: &Session,
     lint_node_id: NodeId,
     features: Option<&Features>,
@@ -594,12 +605,43 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
 /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
 /// evaluate individual items.
 pub fn eval_condition(
-    cfg: &ast::MetaItem,
+    cfg: &ast::NestedMetaItem,
     sess: &Session,
     features: Option<&Features>,
     eval: &mut impl FnMut(Condition) -> bool,
 ) -> bool {
     let dcx = sess.dcx();
+
+    let cfg = match cfg {
+        ast::NestedMetaItem::MetaItem(meta_item) => meta_item,
+        ast::NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
+            if let Some(features) = features {
+                // we can't use `try_gate_cfg` as symbols don't differentiate between `r#true`
+                // and `true`, and we want to keep the former working without feature gate
+                gate_cfg(
+                    &((
+                        if *b { kw::True } else { kw::False },
+                        sym::cfg_boolean_literals,
+                        |features: &Features| features.cfg_boolean_literals,
+                    )),
+                    cfg.span(),
+                    sess,
+                    features,
+                );
+            }
+            return *b;
+        }
+        _ => {
+            dcx.emit_err(session_diagnostics::UnsupportedLiteral {
+                span: cfg.span(),
+                reason: UnsupportedLiteralReason::CfgBoolean,
+                is_bytestr: false,
+                start_point_span: sess.source_map().start_point(cfg.span()),
+            });
+            return false;
+        }
+    };
+
     match &cfg.kind {
         ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
             try_gate_cfg(sym::version, cfg.span, sess, features);
@@ -635,7 +677,7 @@ pub fn eval_condition(
         }
         ast::MetaItemKind::List(mis) => {
             for mi in mis.iter() {
-                if !mi.is_meta_item() {
+                if mi.meta_item_or_bool().is_none() {
                     dcx.emit_err(session_diagnostics::UnsupportedLiteral {
                         span: mi.span(),
                         reason: UnsupportedLiteralReason::Generic,
@@ -653,23 +695,19 @@ pub fn eval_condition(
                     .iter()
                     // We don't use any() here, because we want to evaluate all cfg condition
                     // as eval_condition can (and does) extra checks
-                    .fold(false, |res, mi| {
-                        res | eval_condition(mi.meta_item().unwrap(), sess, features, eval)
-                    }),
+                    .fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)),
                 sym::all => mis
                     .iter()
                     // We don't use all() here, because we want to evaluate all cfg condition
                     // as eval_condition can (and does) extra checks
-                    .fold(true, |res, mi| {
-                        res & eval_condition(mi.meta_item().unwrap(), sess, features, eval)
-                    }),
+                    .fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)),
                 sym::not => {
                     let [mi] = mis.as_slice() else {
                         dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
                         return false;
                     };
 
-                    !eval_condition(mi.meta_item().unwrap(), sess, features, eval)
+                    !eval_condition(mi, sess, features, eval)
                 }
                 sym::target => {
                     if let Some(features) = features
@@ -690,7 +728,12 @@ pub fn eval_condition(
                             seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name));
                         }
 
-                        res & eval_condition(&mi, sess, features, eval)
+                        res & eval_condition(
+                            &ast::NestedMetaItem::MetaItem(mi),
+                            sess,
+                            features,
+                            eval,
+                        )
                     })
                 }
                 _ => {
diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs
index 959a5a4bba7..626840aa6a3 100644
--- a/compiler/rustc_attr/src/session_diagnostics.rs
+++ b/compiler/rustc_attr/src/session_diagnostics.rs
@@ -206,6 +206,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral {
         let mut diag = Diag::new(dcx, level, match self.reason {
             UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic,
             UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string,
+            UnsupportedLiteralReason::CfgBoolean => fluent::attr_unsupported_literal_cfg_boolean,
             UnsupportedLiteralReason::DeprecatedString => {
                 fluent::attr_unsupported_literal_deprecated_string
             }
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 4af5a10f581..5ea48d3fc7e 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -1,5 +1,3 @@
-use std::fmt;
-
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::graph;
 use rustc_index::bit_set::BitSet;
@@ -425,10 +423,6 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
         Borrows { tcx, body, borrow_set, borrows_out_of_scope_at_location }
     }
 
-    pub fn location(&self, idx: BorrowIndex) -> &Location {
-        &self.borrow_set[idx].reserve_location
-    }
-
     /// Add all borrows to the kill set, if those borrows are out of scope at `location`.
     /// That means they went out of a nonlexical scope
     fn kill_loans_out_of_scope_at_location(
@@ -615,8 +609,4 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
     }
 }
 
-impl DebugWithContext<Borrows<'_, '_>> for BorrowIndex {
-    fn fmt_with(&self, ctxt: &Borrows<'_, '_>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{:?}", ctxt.location(*self))
-    }
-}
+impl<C> DebugWithContext<C> for BorrowIndex {}
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 2f22e1532c1..1a5f9bdb154 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -830,20 +830,14 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
     ///
     /// [`OpaqueDef`]: hir::TyKind::OpaqueDef
     fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
-        let hir = self.infcx.tcx.hir();
-
-        let hir::TyKind::OpaqueDef(id, _, _) = hir_ty.kind else {
+        let hir::TyKind::OpaqueDef(opaque_ty, _) = hir_ty.kind else {
             span_bug!(
                 hir_ty.span,
                 "lowered return type of async fn is not OpaqueDef: {:?}",
                 hir_ty
             );
         };
-        let opaque_ty = hir.item(id);
-        if let hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-            bounds: [hir::GenericBound::Trait(trait_ref, _)],
-            ..
-        }) = opaque_ty.kind
+        if let hir::OpaqueTy { bounds: [hir::GenericBound::Trait(trait_ref, _)], .. } = opaque_ty
             && let Some(segment) = trait_ref.trait_ref.path.segments.last()
             && let Some(args) = segment.args
             && let [constraint] = args.constraints
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index a11eca0b9c7..fad4d790be4 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -5,7 +5,6 @@
 #![doc(rust_logo)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
-#![feature(control_flow_enum)]
 #![feature(file_buffered)]
 #![feature(let_chains)]
 #![feature(never_type)]
@@ -743,6 +742,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
             }
 
             TerminatorKind::InlineAsm {
+                asm_macro: _,
                 template: _,
                 operands,
                 options: _,
diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
index afd811a0efb..d1b65943199 100644
--- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
+++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
@@ -169,6 +169,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
                 }
             }
             TerminatorKind::InlineAsm {
+                asm_macro: _,
                 template: _,
                 operands,
                 options: _,
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 3cf21d4a36b..a16c1931a55 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -329,8 +329,8 @@ fn check_opaque_type_well_formed<'tcx>(
 ) -> Result<Ty<'tcx>, ErrorGuaranteed> {
     // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
     // on stable and we'd break that.
-    let opaque_ty_hir = tcx.hir().expect_item(def_id);
-    let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.expect_opaque_ty().origin else {
+    let opaque_ty_hir = tcx.hir().expect_opaque_ty(def_id);
+    let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.origin else {
         return Ok(definition_ty);
     };
     let param_env = tcx.param_env(def_id);
@@ -503,8 +503,8 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> {
         let &Self { tcx, def_id, .. } = self;
         let origin = tcx.opaque_type_origin(def_id);
         let parent = match origin {
-            hir::OpaqueTyOrigin::FnReturn(parent)
-            | hir::OpaqueTyOrigin::AsyncFn(parent)
+            hir::OpaqueTyOrigin::FnReturn { parent, .. }
+            | hir::OpaqueTyOrigin::AsyncFn { parent, .. }
             | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent,
         };
         let param_env = tcx.param_env(parent);
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 0a375c7fae8..b7aef71eb54 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -11,7 +11,7 @@ use crate::BorrowckInferCtxt;
 /// Replaces all free regions appearing in the MIR with fresh
 /// inference variables, returning the number of variables created.
 #[instrument(skip(infcx, body, promoted), level = "debug")]
-pub fn renumber_mir<'tcx>(
+pub(crate) fn renumber_mir<'tcx>(
     infcx: &BorrowckInferCtxt<'tcx>,
     body: &mut Body<'tcx>,
     promoted: &mut IndexSlice<Promoted, Body<'tcx>>,
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index fc1600ea4a6..6c86968389a 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -97,7 +97,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
     /// that we computed for the closure. This has the effect of adding new outlives obligations
     /// to existing region variables in `closure_args`.
     #[instrument(skip(self), level = "debug")]
-    pub fn apply_closure_requirements(
+    pub(crate) fn apply_closure_requirements(
         &mut self,
         closure_requirements: &ClosureRegionRequirements<'tcx>,
         closure_def_id: DefId,
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 9695df9c87e..b25892242b5 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -12,9 +12,9 @@ builtin_macros_asm_duplicate_arg = duplicate argument named `{$name}`
 builtin_macros_asm_expected_comma = expected token: `,`
     .label = expected `,`
 
-builtin_macros_asm_expected_other = expected operand, {$is_global_asm ->
-    [true] options
-    *[false] clobber_abi, options
+builtin_macros_asm_expected_other = expected operand, {$is_inline_asm ->
+    [false] options
+    *[true] clobber_abi, options
     }, or additional template string
 
 builtin_macros_asm_expected_string_literal = expected string literal
@@ -51,6 +51,15 @@ builtin_macros_asm_sym_no_path = expected a path for argument to `sym`
 
 builtin_macros_asm_underscore_input = _ cannot be used for input operands
 
+builtin_macros_asm_unsupported_clobber_abi = `clobber_abi` cannot be used with `{$macro_name}!`
+
+builtin_macros_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `{$macro_name}!`
+    .label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it
+
+builtin_macros_asm_unsupported_option = the `{$symbol}` option cannot be used with `{$macro_name}!`
+    .label = the `{$symbol}` option is not meaningful for global-scoped inline assembly
+    .suggestion = remove this option
+
 builtin_macros_assert_missing_comma = unexpected string literal
     .suggestion = try adding a comma
 
@@ -194,15 +203,6 @@ builtin_macros_format_unused_args = multiple unused formatting arguments
 
 builtin_macros_format_use_positional = consider using a positional formatting argument instead
 
-builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
-
-builtin_macros_global_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `global_asm!`
-    .label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it
-
-builtin_macros_global_asm_unsupported_option = the `{$symbol}` option cannot be used with `global_asm!`
-    .label = the `{$symbol}` option is not meaningful for global-scoped inline assembly
-    .suggestion = remove this option
-
 builtin_macros_invalid_crate_attribute = invalid crate attribute
 
 builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 75dbb3d8e6a..9ae48024f44 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -37,15 +37,23 @@ pub struct AsmArgs {
 /// - `Ok(true)` if the current token matches the keyword, and was expected
 /// - `Ok(false)` if the current token does not match the keyword
 /// - `Err(_)` if the current token matches the keyword, but was not expected
-fn eat_operand_keyword<'a>(p: &mut Parser<'a>, symbol: Symbol, expect: bool) -> PResult<'a, bool> {
-    if expect {
+fn eat_operand_keyword<'a>(
+    p: &mut Parser<'a>,
+    symbol: Symbol,
+    asm_macro: AsmMacro,
+) -> PResult<'a, bool> {
+    if matches!(asm_macro, AsmMacro::Asm) {
         Ok(p.eat_keyword(symbol))
     } else {
         let span = p.token.span;
         if p.eat_keyword_noexpect(symbol) {
             // in gets printed as `r#in` otherwise
             let symbol = if symbol == kw::In { "in" } else { symbol.as_str() };
-            Err(p.dcx().create_err(errors::GlobalAsmUnsupportedOperand { span, symbol }))
+            Err(p.dcx().create_err(errors::AsmUnsupportedOperand {
+                span,
+                symbol,
+                macro_name: asm_macro.macro_name(),
+            }))
         } else {
             Ok(false)
         }
@@ -56,10 +64,10 @@ fn parse_args<'a>(
     ecx: &ExtCtxt<'a>,
     sp: Span,
     tts: TokenStream,
-    is_global_asm: bool,
+    asm_macro: AsmMacro,
 ) -> PResult<'a, AsmArgs> {
     let mut p = ecx.new_parser_from_tts(tts);
-    parse_asm_args(&mut p, sp, is_global_asm)
+    parse_asm_args(&mut p, sp, asm_macro)
 }
 
 // Primarily public for rustfmt consumption.
@@ -67,7 +75,7 @@ fn parse_args<'a>(
 pub fn parse_asm_args<'a>(
     p: &mut Parser<'a>,
     sp: Span,
-    is_global_asm: bool,
+    asm_macro: AsmMacro,
 ) -> PResult<'a, AsmArgs> {
     let dcx = p.dcx();
 
@@ -110,7 +118,7 @@ pub fn parse_asm_args<'a>(
 
         // Parse options
         if p.eat_keyword(sym::options) {
-            parse_options(p, &mut args, is_global_asm)?;
+            parse_options(p, &mut args, asm_macro)?;
             allow_templates = false;
             continue;
         }
@@ -129,7 +137,7 @@ pub fn parse_asm_args<'a>(
         };
 
         let mut explicit_reg = false;
-        let op = if eat_operand_keyword(p, kw::In, !is_global_asm)? {
+        let op = if eat_operand_keyword(p, kw::In, asm_macro)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
                 let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -137,15 +145,15 @@ pub fn parse_asm_args<'a>(
             }
             let expr = p.parse_expr()?;
             ast::InlineAsmOperand::In { reg, expr }
-        } else if eat_operand_keyword(p, sym::out, !is_global_asm)? {
+        } else if eat_operand_keyword(p, sym::out, asm_macro)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: false }
-        } else if eat_operand_keyword(p, sym::lateout, !is_global_asm)? {
+        } else if eat_operand_keyword(p, sym::lateout, asm_macro)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: true }
-        } else if eat_operand_keyword(p, sym::inout, !is_global_asm)? {
+        } else if eat_operand_keyword(p, sym::inout, asm_macro)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
                 let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -159,7 +167,7 @@ pub fn parse_asm_args<'a>(
             } else {
                 ast::InlineAsmOperand::InOut { reg, expr, late: false }
             }
-        } else if eat_operand_keyword(p, sym::inlateout, !is_global_asm)? {
+        } else if eat_operand_keyword(p, sym::inlateout, asm_macro)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
                 let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -173,7 +181,7 @@ pub fn parse_asm_args<'a>(
             } else {
                 ast::InlineAsmOperand::InOut { reg, expr, late: true }
             }
-        } else if eat_operand_keyword(p, sym::label, !is_global_asm)? {
+        } else if eat_operand_keyword(p, sym::label, asm_macro)? {
             let block = p.parse_block()?;
             ast::InlineAsmOperand::Label { block }
         } else if p.eat_keyword(kw::Const) {
@@ -205,7 +213,7 @@ pub fn parse_asm_args<'a>(
                 _ => {
                     let err = dcx.create_err(errors::AsmExpectedOther {
                         span: template.span,
-                        is_global_asm,
+                        is_inline_asm: matches!(asm_macro, AsmMacro::Asm),
                     });
                     return Err(err);
                 }
@@ -301,20 +309,25 @@ pub fn parse_asm_args<'a>(
         dcx.emit_err(errors::AsmMayUnwind { labels_sp });
     }
 
-    if args.clobber_abis.len() > 0 {
-        if is_global_asm {
-            let err = dcx.create_err(errors::GlobalAsmClobberAbi {
-                spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
-            });
+    if !args.clobber_abis.is_empty() {
+        match asm_macro {
+            AsmMacro::GlobalAsm | AsmMacro::NakedAsm => {
+                let err = dcx.create_err(errors::AsmUnsupportedClobberAbi {
+                    spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
+                    macro_name: asm_macro.macro_name(),
+                });
 
-            // Bail out now since this is likely to confuse later stages
-            return Err(err);
-        }
-        if !regclass_outputs.is_empty() {
-            dcx.emit_err(errors::AsmClobberNoReg {
-                spans: regclass_outputs,
-                clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
-            });
+                // Bail out now since this is likely to confuse later stages
+                return Err(err);
+            }
+            AsmMacro::Asm => {
+                if !regclass_outputs.is_empty() {
+                    dcx.emit_err(errors::AsmClobberNoReg {
+                        spans: regclass_outputs,
+                        clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
+                    });
+                }
+            }
         }
     }
 
@@ -335,10 +348,15 @@ fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
 ///
 /// This function must be called immediately after the option token is parsed.
 /// Otherwise, the suggestion will be incorrect.
-fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
+fn err_unsupported_option(p: &Parser<'_>, asm_macro: AsmMacro, symbol: Symbol, span: Span) {
     // Tool-only output
     let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span };
-    p.dcx().emit_err(errors::GlobalAsmUnsupportedOption { span, symbol, full_span });
+    p.dcx().emit_err(errors::AsmUnsupportedOption {
+        span,
+        symbol,
+        full_span,
+        macro_name: asm_macro.macro_name(),
+    });
 }
 
 /// Try to set the provided option in the provided `AsmArgs`.
@@ -349,12 +367,12 @@ fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
 fn try_set_option<'a>(
     p: &Parser<'a>,
     args: &mut AsmArgs,
-    is_global_asm: bool,
+    asm_macro: AsmMacro,
     symbol: Symbol,
     option: ast::InlineAsmOptions,
 ) {
-    if is_global_asm && !ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) {
-        err_unsupported_option(p, symbol, p.prev_token.span);
+    if !asm_macro.is_supported_option(option) {
+        err_unsupported_option(p, asm_macro, symbol, p.prev_token.span);
     } else if args.options.contains(option) {
         err_duplicate_option(p, symbol, p.prev_token.span);
     } else {
@@ -365,7 +383,7 @@ fn try_set_option<'a>(
 fn parse_options<'a>(
     p: &mut Parser<'a>,
     args: &mut AsmArgs,
-    is_global_asm: bool,
+    asm_macro: AsmMacro,
 ) -> PResult<'a, ()> {
     let span_start = p.prev_token.span;
 
@@ -386,15 +404,14 @@ fn parse_options<'a>(
 
         'blk: {
             for (symbol, option) in OPTIONS {
-                let kw_matched =
-                    if !is_global_asm || ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) {
-                        p.eat_keyword(symbol)
-                    } else {
-                        p.eat_keyword_noexpect(symbol)
-                    };
+                let kw_matched = if asm_macro.is_supported_option(option) {
+                    p.eat_keyword(symbol)
+                } else {
+                    p.eat_keyword_noexpect(symbol)
+                };
 
                 if kw_matched {
-                    try_set_option(p, args, is_global_asm, symbol, option);
+                    try_set_option(p, args, asm_macro, symbol, option);
                     break 'blk;
                 }
             }
@@ -483,7 +500,7 @@ fn parse_reg<'a>(
 
 fn expand_preparsed_asm(
     ecx: &mut ExtCtxt<'_>,
-    asm_macro: ast::AsmMacro,
+    asm_macro: AsmMacro,
     args: AsmArgs,
 ) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> {
     let mut template = vec![];
@@ -797,7 +814,7 @@ pub(super) fn expand_asm<'cx>(
     sp: Span,
     tts: TokenStream,
 ) -> MacroExpanderResult<'cx> {
-    ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
+    ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::Asm) {
         Ok(args) => {
             let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::Asm, args) else {
                 return ExpandResult::Retry(());
@@ -826,29 +843,20 @@ pub(super) fn expand_naked_asm<'cx>(
     sp: Span,
     tts: TokenStream,
 ) -> MacroExpanderResult<'cx> {
-    ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
+    ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::NakedAsm) {
         Ok(args) => {
             let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::NakedAsm, args)
             else {
                 return ExpandResult::Retry(());
             };
             let expr = match mac {
-                Ok(mut inline_asm) => {
-                    // for future compatibility, we always set the NORETURN option.
-                    //
-                    // When we turn `asm!` into `naked_asm!` with this implementation, we can drop
-                    // the `options(noreturn)`, which makes the upgrade smooth when `naked_asm!`
-                    // starts disallowing the `noreturn` option in the future
-                    inline_asm.options |= ast::InlineAsmOptions::NORETURN;
-
-                    P(ast::Expr {
-                        id: ast::DUMMY_NODE_ID,
-                        kind: ast::ExprKind::InlineAsm(P(inline_asm)),
-                        span: sp,
-                        attrs: ast::AttrVec::new(),
-                        tokens: None,
-                    })
-                }
+                Ok(inline_asm) => P(ast::Expr {
+                    id: ast::DUMMY_NODE_ID,
+                    kind: ast::ExprKind::InlineAsm(P(inline_asm)),
+                    span: sp,
+                    attrs: ast::AttrVec::new(),
+                    tokens: None,
+                }),
                 Err(guar) => DummyResult::raw_expr(sp, Some(guar)),
             };
             MacEager::expr(expr)
@@ -865,7 +873,7 @@ pub(super) fn expand_global_asm<'cx>(
     sp: Span,
     tts: TokenStream,
 ) -> MacroExpanderResult<'cx> {
-    ExpandResult::Ready(match parse_args(ecx, sp, tts, true) {
+    ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::GlobalAsm) {
         Ok(args) => {
             let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::GlobalAsm, args)
             else {
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index de198115fa0..940c94b1cfc 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -6,7 +6,6 @@ use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_errors::PResult;
 use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
-use rustc_parse::parser::attr::AllowLeadingUnsafe;
 use rustc_span::Span;
 use {rustc_ast as ast, rustc_attr as attr};
 
@@ -36,14 +35,18 @@ pub(crate) fn expand_cfg(
     })
 }
 
-fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
+fn parse_cfg<'a>(
+    cx: &ExtCtxt<'a>,
+    span: Span,
+    tts: TokenStream,
+) -> PResult<'a, ast::NestedMetaItem> {
     let mut p = cx.new_parser_from_tts(tts);
 
     if p.token == token::Eof {
         return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span }));
     }
 
-    let cfg = p.parse_meta_item(AllowLeadingUnsafe::Yes)?;
+    let cfg = p.parse_meta_item_inner()?;
 
     let _ = p.eat(&token::Comma);
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
index 12749e87dcb..78028df2aa0 100644
--- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
@@ -310,7 +310,7 @@ pub(crate) fn expand_deriving_smart_ptr(
     // Add the impl blocks for `DispatchFromDyn` and `CoerceUnsized`.
     let gen_args = vec![GenericArg::Type(alt_self_type.clone())];
     add_impl_block(impl_generics.clone(), sym::DispatchFromDyn, gen_args.clone());
-    add_impl_block(impl_generics.clone(), sym::CoerceUnsized, gen_args.clone());
+    add_impl_block(impl_generics.clone(), sym::CoerceUnsized, gen_args);
 }
 
 fn contains_maybe_sized_bound_on_pointee(predicates: &[WherePredicate], pointee: Symbol) -> bool {
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 4fffffb91c8..f13ca224a45 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -751,7 +751,7 @@ pub(crate) struct AsmExpectedOther {
     #[primary_span]
     #[label(builtin_macros_asm_expected_other)]
     pub(crate) span: Span,
-    pub(crate) is_global_asm: bool,
+    pub(crate) is_inline_asm: bool,
 }
 
 #[derive(Diagnostic)]
@@ -799,13 +799,6 @@ pub(crate) struct AsmMayUnwind {
     pub(crate) labels_sp: Vec<Span>,
 }
 
-#[derive(Diagnostic)]
-#[diag(builtin_macros_global_asm_clobber_abi)]
-pub(crate) struct GlobalAsmClobberAbi {
-    #[primary_span]
-    pub(crate) spans: Vec<Span>,
-}
-
 pub(crate) struct AsmClobberNoReg {
     pub(crate) spans: Vec<Span>,
     pub(crate) clobbers: Vec<Span>,
@@ -841,23 +834,33 @@ pub(crate) struct AsmOptAlreadyprovided {
 }
 
 #[derive(Diagnostic)]
-#[diag(builtin_macros_global_asm_unsupported_option)]
-pub(crate) struct GlobalAsmUnsupportedOption {
+#[diag(builtin_macros_asm_unsupported_option)]
+pub(crate) struct AsmUnsupportedOption {
     #[primary_span]
     #[label]
     pub(crate) span: Span,
     pub(crate) symbol: Symbol,
     #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
     pub(crate) full_span: Span,
+    pub(crate) macro_name: &'static str,
 }
 
 #[derive(Diagnostic)]
-#[diag(builtin_macros_global_asm_unsupported_operand)]
-pub(crate) struct GlobalAsmUnsupportedOperand<'a> {
+#[diag(builtin_macros_asm_unsupported_operand)]
+pub(crate) struct AsmUnsupportedOperand<'a> {
     #[primary_span]
     #[label]
     pub(crate) span: Span,
     pub(crate) symbol: &'a str,
+    pub(crate) macro_name: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_unsupported_clobber_abi)]
+pub(crate) struct AsmUnsupportedClobberAbi {
+    #[primary_span]
+    pub(crate) spans: Vec<Span>,
+    pub(crate) macro_name: &'static str,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 5e535ff62e1..9fc0318df5d 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -726,6 +726,12 @@ pub macro global_asm() {
     /* compiler built-in */
 }
 
+#[rustc_builtin_macro]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro naked_asm() {
+    /* compiler built-in */
+}
+
 pub static A_STATIC: u8 = 42;
 
 #[lang = "panic_location"]
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 ccbd5a78485..e47431e0f87 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -390,7 +390,7 @@ global_asm! {
 #[naked]
 extern "C" fn naked_test() {
     unsafe {
-        asm!("ret", options(noreturn));
+        naked_asm!("ret");
     }
 }
 
diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs
index ebaa9c69c81..3078288c286 100644
--- a/compiler/rustc_codegen_cranelift/example/std_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/std_example.rs
@@ -168,7 +168,7 @@ fn main() {
 
     foo(I64X2([0, 0]));
 
-    transmute_fat_pointer();
+    transmute_wide_pointer();
 
     rust_call_abi();
 
@@ -192,7 +192,7 @@ type TwoPtrs = i64;
 #[cfg(target_pointer_width = "64")]
 type TwoPtrs = i128;
 
-fn transmute_fat_pointer() -> TwoPtrs {
+fn transmute_wide_pointer() -> TwoPtrs {
     unsafe { transmute::<_, TwoPtrs>("true !") }
 }
 
diff --git a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
index a3f370af916..646928893e9 100644
--- a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
@@ -82,19 +82,6 @@ index d9de37e..8293fce 100644
  #[cfg(target_has_atomic_load_store = "ptr")]
  macro_rules! atomic_int_ptr_sized {
      ( $($target_pointer_width:literal $align:literal)* ) => { $(
-diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
-index 58b9ba4..91bbd0a 100644
---- a/library/core/src/cell.rs
-+++ b/library/core/src/cell.rs
-@@ -2246,8 +2246,6 @@ unsafe_cell_primitive_into_inner! {
-     u32 "32"
-     i64 "64"
-     u64 "64"
--    i128 "128"
--    u128 "128"
-     isize "ptr"
-     usize "ptr"
- }
 --
 2.26.2.7.g19db9cfb68
 
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 1ce0aacab49..a681e6d9f3c 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -8,6 +8,7 @@ use rustc_ast::InlineAsmOptions;
 use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
 use rustc_index::IndexVec;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::mir::InlineAsmMacro;
 use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::layout::FnAbiOf;
@@ -57,6 +58,7 @@ pub(crate) fn codegen_fn<'tcx>(
 
         match &mir.basic_blocks[START_BLOCK].terminator().kind {
             TerminatorKind::InlineAsm {
+                asm_macro: InlineAsmMacro::NakedAsm,
                 template,
                 operands,
                 options,
@@ -498,6 +500,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                 "tail calls are not yet supported in `rustc_codegen_cranelift` backend"
             ),
             TerminatorKind::InlineAsm {
+                asm_macro: _,
                 template,
                 operands,
                 options,
@@ -713,17 +716,17 @@ fn codegen_stmt<'tcx>(
                     let from_ty = operand.layout().ty;
                     let to_ty = fx.monomorphize(to_ty);
 
-                    fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
+                    fn is_wide_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
                         ty.builtin_deref(true)
                             .is_some_and(|pointee_ty| has_ptr_meta(fx.tcx, pointee_ty))
                     }
 
-                    if is_fat_ptr(fx, from_ty) {
-                        if is_fat_ptr(fx, to_ty) {
-                            // fat-ptr -> fat-ptr
+                    if is_wide_ptr(fx, from_ty) {
+                        if is_wide_ptr(fx, to_ty) {
+                            // wide-ptr -> wide-ptr
                             lval.write_cvalue(fx, operand.cast_pointer_to(dest_layout));
                         } else {
-                            // fat-ptr -> thin-ptr
+                            // wide-ptr -> thin-ptr
                             let (ptr, _extra) = operand.load_scalar_pair(fx);
                             lval.write_cvalue(fx, CValue::by_val(ptr, dest_layout))
                         }
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index e78ba5a3415..69a32cc3d43 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -101,7 +101,7 @@ fn clif_pair_type_from_ty<'tcx>(
     })
 }
 
-/// Is a pointer to this type a fat ptr?
+/// Is a pointer to this type a wide ptr?
 pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
     if ty.is_sized(tcx, ParamEnv::reveal_all()) {
         return false;
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs
index a710701e72c..714742aeaff 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs
@@ -139,7 +139,7 @@ impl DebugContext {
 
             pointer_type_id
         } else {
-            // FIXME implement debuginfo for fat pointers
+            // FIXME implement debuginfo for wide pointers
             self.placeholder_for_type(tcx, type_dbg, ptr_type)
         }
     }
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index 339628053a9..5c297ebfadb 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -2,6 +2,7 @@
 //!
 //! [`PointerCoercion::Unsize`]: `rustc_middle::ty::adjustment::PointerCoercion::Unsize`
 
+use rustc_codegen_ssa::base::validate_trivial_unsize;
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 
 use crate::base::codegen_panic_nounwind;
@@ -34,20 +35,8 @@ pub(crate) fn unsized_info<'tcx>(
             let old_info =
                 old_info.expect("unsized_info: missing old info for trait upcasting coercion");
             if data_a.principal_def_id() == data_b.principal_def_id() {
-                // Codegen takes advantage of the additional assumption, where if the
-                // principal trait def id of what's being casted doesn't change,
-                // then we don't need to adjust the vtable at all. This
-                // corresponds to the fact that `dyn Tr<A>: Unsize<dyn Tr<B>>`
-                // requires that `A = B`; we don't allow *upcasting* objects
-                // between the same trait with different args. If we, for
-                // some reason, were to relax the `Unsize` trait, it could become
-                // unsound, so let's assert here that the trait refs are *equal*.
-                //
-                // We can use `assert_eq` because the binders should have been anonymized,
-                // and because higher-ranked equality now requires the binders are equal.
-                debug_assert_eq!(
-                    data_a.principal(),
-                    data_b.principal(),
+                debug_assert!(
+                    validate_trivial_unsize(fx.tcx, data_a, data_b),
                     "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
                 );
                 return old_info;
diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs
index e9498857fb9..f13a75648ae 100644
--- a/compiler/rustc_codegen_gcc/src/allocator.rs
+++ b/compiler/rustc_codegen_gcc/src/allocator.rs
@@ -104,10 +104,17 @@ fn create_wrapper_function(
         false,
     );
 
-    if tcx.sess.default_hidden_visibility() {
-        #[cfg(feature = "master")]
-        func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
+    #[cfg(feature = "master")]
+    match tcx.sess.default_visibility() {
+        rustc_target::spec::SymbolVisibility::Hidden => {
+            func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden))
+        }
+        rustc_target::spec::SymbolVisibility::Protected => {
+            func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Protected))
+        }
+        rustc_target::spec::SymbolVisibility::Interposable => {}
     }
+
     if tcx.sess.must_emit_unwind_tables() {
         // TODO(antoyo): emit unwind tables.
     }
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 13a00f7e08d..a04cd4735f4 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -682,6 +682,11 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
             InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
             InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
+            InlineAsmRegClass::S390x(
+                S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg,
+            ) => {
+                unreachable!("clobber-only")
+            }
             InlineAsmRegClass::Err => unreachable!(),
         },
     };
@@ -757,6 +762,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
             S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr,
         ) => cx.type_i32(),
         InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
+        InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
+            unreachable!("clobber-only")
+        }
         InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(),
         InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(),
         InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(),
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
index eeab2a5f155..4e1b99fdebf 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
@@ -478,7 +478,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
                 let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
                     bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
                 });
-                require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer {
+                require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
                     span,
                     name,
                     ty: in_elem
@@ -493,7 +493,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
                 let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
                     bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
                 });
-                require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer {
+                require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
                     span,
                     name,
                     ty: out_elem
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
index cb45bbde2c2..5b0d862ae6d 100644
--- a/compiler/rustc_codegen_gcc/src/type_of.rs
+++ b/compiler/rustc_codegen_gcc/src/type_of.rs
@@ -207,7 +207,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
         // layout.
         if let Abi::Scalar(ref scalar) = self.abi {
             // Use a different cache for scalars because pointers to DSTs
-            // can be either fat or thin (data pointers of fat pointers).
+            // can be either wide or thin (data pointers of wide pointers).
             if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) {
                 return ty;
             }
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 3d75393bf06..6a29eb5fa04 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -7,7 +7,7 @@ use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
 use rustc_codegen_ssa::traits::*;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf;
-pub(crate) use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
+pub(crate) use rustc_middle::ty::layout::{WIDE_PTR_ADDR, WIDE_PTR_EXTRA};
 use rustc_middle::{bug, ty};
 use rustc_session::config;
 pub(crate) use rustc_target::abi::call::*;
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 2adac278c62..89f5305840b 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -77,18 +77,20 @@ pub(crate) unsafe fn codegen(
         // __rust_alloc_error_handler_should_panic
         let name = OomStrategy::SYMBOL;
         let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
-        if tcx.sess.default_hidden_visibility() {
-            llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
-        }
+        llvm::LLVMRustSetVisibility(
+            ll_g,
+            llvm::Visibility::from_generic(tcx.sess.default_visibility()),
+        );
         let val = tcx.sess.opts.unstable_opts.oom.should_panic();
         let llval = llvm::LLVMConstInt(i8, val as u64, False);
         llvm::LLVMSetInitializer(ll_g, llval);
 
         let name = NO_ALLOC_SHIM_IS_UNSTABLE;
         let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
-        if tcx.sess.default_hidden_visibility() {
-            llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
-        }
+        llvm::LLVMRustSetVisibility(
+            ll_g,
+            llvm::Visibility::from_generic(tcx.sess.default_visibility()),
+        );
         let llval = llvm::LLVMConstInt(i8, 0, False);
         llvm::LLVMSetInitializer(ll_g, llval);
     }
@@ -132,9 +134,11 @@ fn create_wrapper_function(
             None
         };
 
-        if tcx.sess.default_hidden_visibility() {
-            llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
-        }
+        llvm::LLVMRustSetVisibility(
+            llfn,
+            llvm::Visibility::from_generic(tcx.sess.default_visibility()),
+        );
+
         if tcx.sess.must_emit_unwind_tables() {
             let uwtable =
                 attributes::uwtable_attr(llcx, tcx.sess.opts.unstable_opts.use_sync_unwind);
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 7621f111fe2..82ca3f519f7 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -708,6 +708,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
             S390x(S390xInlineAsmRegClass::reg) => "r",
             S390x(S390xInlineAsmRegClass::reg_addr) => "a",
             S390x(S390xInlineAsmRegClass::freg) => "f",
+            S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
+                unreachable!("clobber-only")
+            }
             Msp430(Msp430InlineAsmRegClass::reg) => "r",
             M68k(M68kInlineAsmRegClass::reg) => "r",
             M68k(M68kInlineAsmRegClass::reg_addr) => "a",
@@ -866,6 +869,9 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
         Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(),
         S390x(S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr) => cx.type_i32(),
         S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
+        S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
+            unreachable!("clobber-only")
+        }
         Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(),
         M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(),
         M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(),
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 964b83c0fa0..15d441a986d 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -34,7 +34,7 @@ use super::utils::{
 };
 use crate::common::CodegenCx;
 use crate::debuginfo::metadata::type_map::build_type_with_children;
-use crate::debuginfo::utils::{FatPtrKind, fat_pointer_kind};
+use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind};
 use crate::llvm::debuginfo::{
     DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind,
     DebugNameTableKind,
@@ -161,7 +161,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
     unique_type_id: UniqueTypeId<'tcx>,
 ) -> DINodeCreationResult<'ll> {
     // The debuginfo generated by this function is only valid if `ptr_type` is really just
-    // a (fat) pointer. Make sure it is not called for e.g. `Box<T, NonZSTAllocator>`.
+    // a (wide) pointer. Make sure it is not called for e.g. `Box<T, NonZSTAllocator>`.
     assert_eq!(
         cx.size_and_align_of(ptr_type),
         cx.size_and_align_of(Ty::new_mut_ptr(cx.tcx, pointee_type))
@@ -174,7 +174,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
     let data_layout = &cx.tcx.data_layout;
     let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true);
 
-    match fat_pointer_kind(cx, pointee_type) {
+    match wide_pointer_kind(cx, pointee_type) {
         None => {
             // This is a thin pointer. Create a regular pointer type and give it the correct name.
             assert_eq!(
@@ -197,7 +197,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
 
             DINodeCreationResult { di_node, already_stored_in_typemap: false }
         }
-        Some(fat_pointer_kind) => {
+        Some(wide_pointer_kind) => {
             type_map::build_type_with_children(
                 cx,
                 type_map::stub(
@@ -210,7 +210,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                     DIFlags::FlagZero,
                 ),
                 |cx, owner| {
-                    // FIXME: If this fat pointer is a `Box` then we don't want to use its
+                    // FIXME: If this wide pointer is a `Box` then we don't want to use its
                     //        type layout and instead use the layout of the raw pointer inside
                     //        of it.
                     //        The proper way to handle this is to not treat Box as a pointer
@@ -227,16 +227,16 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                     };
 
                     let layout = cx.layout_of(layout_type);
-                    let addr_field = layout.field(cx, abi::FAT_PTR_ADDR);
-                    let extra_field = layout.field(cx, abi::FAT_PTR_EXTRA);
+                    let addr_field = layout.field(cx, abi::WIDE_PTR_ADDR);
+                    let extra_field = layout.field(cx, abi::WIDE_PTR_EXTRA);
 
-                    let (addr_field_name, extra_field_name) = match fat_pointer_kind {
-                        FatPtrKind::Dyn => ("pointer", "vtable"),
-                        FatPtrKind::Slice => ("data_ptr", "length"),
+                    let (addr_field_name, extra_field_name) = match wide_pointer_kind {
+                        WidePtrKind::Dyn => ("pointer", "vtable"),
+                        WidePtrKind::Slice => ("data_ptr", "length"),
                     };
 
-                    assert_eq!(abi::FAT_PTR_ADDR, 0);
-                    assert_eq!(abi::FAT_PTR_EXTRA, 1);
+                    assert_eq!(abi::WIDE_PTR_ADDR, 0);
+                    assert_eq!(abi::WIDE_PTR_EXTRA, 1);
 
                     // The data pointer type is a regular, thin pointer, regardless of whether this
                     // is a slice or a trait object.
@@ -258,7 +258,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                             owner,
                             addr_field_name,
                             (addr_field.size, addr_field.align.abi),
-                            layout.fields.offset(abi::FAT_PTR_ADDR),
+                            layout.fields.offset(abi::WIDE_PTR_ADDR),
                             DIFlags::FlagZero,
                             data_ptr_type_di_node,
                         ),
@@ -267,7 +267,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                             owner,
                             extra_field_name,
                             (extra_field.size, extra_field.align.abi),
-                            layout.fields.offset(abi::FAT_PTR_EXTRA),
+                            layout.fields.offset(abi::WIDE_PTR_EXTRA),
                             DIFlags::FlagZero,
                             type_di_node(cx, extra_field.ty),
                         ),
@@ -391,7 +391,7 @@ fn build_dyn_type_di_node<'ll, 'tcx>(
 ///
 /// NOTE: We currently emit just emit the debuginfo for the element type here
 /// (i.e. `T` for slices and `u8` for `str`), so that we end up with
-/// `*const T` for the `data_ptr` field of the corresponding fat-pointer
+/// `*const T` for the `data_ptr` field of the corresponding wide-pointer
 /// debuginfo of `&[T]`.
 ///
 /// It would be preferable and more accurate if we emitted a DIArray of T
@@ -630,6 +630,7 @@ pub(crate) fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFi
             rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5,
             rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1,
             rustc_span::SourceFileHashAlgorithm::Sha256 => llvm::ChecksumKind::SHA256,
+            rustc_span::SourceFileHashAlgorithm::Blake3 => llvm::ChecksumKind::None,
         };
         let hash_value = hex_encode(source_file.src_hash.hash_bytes());
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
index acb15449ce3..960487ada16 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
@@ -49,23 +49,23 @@ pub(crate) fn get_namespace_for_item<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId
 }
 
 #[derive(Debug, PartialEq, Eq)]
-pub(crate) enum FatPtrKind {
+pub(crate) enum WidePtrKind {
     Slice,
     Dyn,
 }
 
 /// Determines if `pointee_ty` is slice-like or trait-object-like, i.e.
-/// if the second field of the fat pointer is a length or a vtable-pointer.
-/// If `pointee_ty` does not require a fat pointer (because it is Sized) then
+/// if the second field of the wide pointer is a length or a vtable-pointer.
+/// If `pointee_ty` does not require a wide pointer (because it is Sized) then
 /// the function returns `None`.
-pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
+pub(crate) fn wide_pointer_kind<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     pointee_ty: Ty<'tcx>,
-) -> Option<FatPtrKind> {
+) -> Option<WidePtrKind> {
     let pointee_tail_ty = cx.tcx.struct_tail_for_codegen(pointee_ty, cx.param_env());
     let layout = cx.layout_of(pointee_tail_ty);
     trace!(
-        "fat_pointer_kind: {:?} has layout {:?} (is_unsized? {})",
+        "wide_pointer_kind: {:?} has layout {:?} (is_unsized? {})",
         pointee_tail_ty,
         layout,
         layout.is_unsized()
@@ -76,8 +76,8 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
     }
 
     match *pointee_tail_ty.kind() {
-        ty::Str | ty::Slice(_) => Some(FatPtrKind::Slice),
-        ty::Dynamic(..) => Some(FatPtrKind::Dyn),
+        ty::Str | ty::Slice(_) => Some(WidePtrKind::Slice),
+        ty::Dynamic(..) => Some(WidePtrKind::Dyn),
         ty::Foreign(_) => {
             // Assert that pointers to foreign types really are thin:
             assert_eq!(
@@ -90,7 +90,7 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
             // For all other pointee types we should already have returned None
             // at the beginning of the function.
             panic!(
-                "fat_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {pointee_tail_ty:?}"
+                "wide_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {pointee_tail_ty:?}"
             )
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index b0b29ca1280..7be44dd51b5 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -22,6 +22,7 @@ use tracing::debug;
 use crate::abi::{FnAbi, FnAbiLlvmExt};
 use crate::context::CodegenCx;
 use crate::llvm::AttributePlace::Function;
+use crate::llvm::Visibility;
 use crate::type_::Type;
 use crate::value::Value;
 use crate::{attributes, llvm};
@@ -84,11 +85,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
         fn_type: &'ll Type,
     ) -> &'ll Value {
         // Declare C ABI functions with the visibility used by C by default.
-        let visibility = if self.tcx.sess.default_hidden_visibility() {
-            llvm::Visibility::Hidden
-        } else {
-            llvm::Visibility::Default
-        };
+        let visibility = Visibility::from_generic(self.tcx.sess.default_visibility());
 
         declare_raw_fn(self, name, llvm::CCallConv, unnamed, visibility, fn_type)
     }
@@ -107,11 +104,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
         unnamed: llvm::UnnamedAddr,
         fn_type: &'ll Type,
     ) -> &'ll Value {
-        let visibility = if self.tcx.sess.default_hidden_visibility() {
-            llvm::Visibility::Hidden
-        } else {
-            llvm::Visibility::Default
-        };
+        let visibility = Visibility::from_generic(self.tcx.sess.default_visibility());
         declare_raw_fn(self, name, callconv, unnamed, visibility, fn_type)
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index c66c80da9fc..30c6f08e894 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -2185,7 +2185,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
                 let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
                     bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
                 });
-                require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer {
+                require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
                     span,
                     name,
                     ty: in_elem
@@ -2200,7 +2200,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
                 let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
                     bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
                 });
-                require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer {
+                require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
                     span,
                     name,
                     ty: out_elem
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 9aabfd794ba..d3950df91fb 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -4,6 +4,7 @@
 use std::marker::PhantomData;
 
 use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t};
+use rustc_target::spec::SymbolVisibility;
 
 use super::RustString;
 use super::debuginfo::{
@@ -133,6 +134,16 @@ pub enum Visibility {
     Protected = 2,
 }
 
+impl Visibility {
+    pub fn from_generic(visibility: SymbolVisibility) -> Self {
+        match visibility {
+            SymbolVisibility::Hidden => Visibility::Hidden,
+            SymbolVisibility::Protected => Visibility::Protected,
+            SymbolVisibility::Interposable => Visibility::Default,
+        }
+    }
+}
+
 /// LLVMUnnamedAddr
 #[repr(C)]
 pub enum UnnamedAddr {
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index a2a5499597c..bd847cd0068 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -264,6 +264,10 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
         ("riscv32" | "riscv64", "unaligned-scalar-mem") if get_version().0 == 18 => {
             Some(LLVMFeature::new("fast-unaligned-access"))
         }
+        // Filter out features that are not supported by the current LLVM version
+        ("riscv32" | "riscv64", "zaamo") if get_version().0 < 19 => None,
+        ("riscv32" | "riscv64", "zabha") if get_version().0 < 19 => None,
+        ("riscv32" | "riscv64", "zalrsc") if get_version().0 < 19 => None,
         // Enable the evex512 target feature if an avx512 target feature is enabled.
         ("x86", s) if s.starts_with("avx512") => {
             Some(LLVMFeature::with_dependency(s, TargetFeatureFoldStrength::EnableOnly("evex512")))
@@ -536,6 +540,11 @@ pub(crate) fn global_llvm_features(
     // -Ctarget-cpu=native
     match sess.opts.cg.target_cpu {
         Some(ref s) if s == "native" => {
+            // We have already figured out the actual CPU name with `LLVMRustGetHostCPUName` and set
+            // that for LLVM, so the features implied by that CPU name will be available everywhere.
+            // However, that is not sufficient: e.g. `skylake` alone is not sufficient to tell if
+            // some of the instructions are available or not. So we have to also explicitly ask for
+            // the exact set of features available on the host, and enable all of them.
             let features_string = unsafe {
                 let ptr = llvm::LLVMGetHostCPUFeatures();
                 let features_string = if !ptr.is_null() {
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 6e429a1674a..7071dd86ee0 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -199,7 +199,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
         // layout.
         if let Abi::Scalar(scalar) = self.abi {
             // Use a different cache for scalars because pointers to DSTs
-            // can be either fat or thin (data pointers of fat pointers).
+            // can be either wide or thin (data pointers of wide pointers).
             if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) {
                 return llty;
             }
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 81590674ec7..58baf40b581 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -8,7 +8,7 @@ edition = "2021"
 ar_archive_writer = "0.4.2"
 arrayvec = { version = "0.7", default-features = false }
 bitflags = "2.4.1"
-cc = "=1.0.105" # FIXME(cc): pinned to keep support for VS2013
+cc = "1.1.23"
 either = "1.5.0"
 itertools = "0.12"
 jobserver = "0.1.28"
@@ -34,6 +34,7 @@ rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
 rustc_target = { path = "../rustc_target" }
+rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_type_ir = { path = "../rustc_type_ir" }
 serde_json = "1.0.59"
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 9091602d75b..f02b0f72674 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -82,7 +82,7 @@ codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphizati
 
 codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
 
-codegen_ssa_invalid_monomorphization_cast_fat_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast fat pointer `{$ty}`
+codegen_ssa_invalid_monomorphization_cast_wide_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast wide pointer `{$ty}`
 
 codegen_ssa_invalid_monomorphization_expected_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of second argument `{$second_arg}` to be a pointer to the element type `{$in_elem}` of the first argument `{$in_ty}`, found `{$expected_element}` != `{$mutability} {$in_elem}`
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 80e8111516e..e7b1c63a822 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2490,7 +2490,7 @@ fn add_order_independent_options(
         }
     }
 
-    cmd.set_output_kind(link_output_kind, out_filename);
+    cmd.set_output_kind(link_output_kind, crate_type, out_filename);
 
     add_relro_args(cmd, sess);
 
@@ -2959,11 +2959,12 @@ pub(crate) fn are_upstream_rust_objects_already_included(sess: &Session) -> bool
     }
 }
 
-/// We need to communicate four things to the linker on Apple/Darwin targets:
+/// We need to communicate five things to the linker on Apple/Darwin targets:
 /// - The architecture.
 /// - The operating system (and that it's an Apple platform).
-/// - The deployment target.
 /// - The environment / ABI.
+/// - The deployment target.
+/// - The SDK version.
 fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
     if !sess.target.is_like_osx {
         return;
@@ -3039,7 +3040,38 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
         let (major, minor, patch) = current_apple_deployment_target(&sess.target);
         let min_version = format!("{major}.{minor}.{patch}");
 
-        // Lie about the SDK version, we don't know it here
+        // The SDK version is used at runtime when compiling with a newer SDK / version of Xcode:
+        // - By dyld to give extra warnings and errors, see e.g.:
+        //   <https://github.com/apple-oss-distributions/dyld/blob/dyld-1165.3/common/MachOFile.cpp#L3029>
+        //   <https://github.com/apple-oss-distributions/dyld/blob/dyld-1165.3/common/MachOFile.cpp#L3738-L3857>
+        // - By system frameworks to change certain behaviour. For example, the default value of
+        //   `-[NSView wantsBestResolutionOpenGLSurface]` is `YES` when the SDK version is >= 10.15.
+        //   <https://developer.apple.com/documentation/appkit/nsview/1414938-wantsbestresolutionopenglsurface?language=objc>
+        //
+        // We do not currently know the actual SDK version though, so we have a few options:
+        // 1. Use the minimum version supported by rustc.
+        // 2. Use the same as the deployment target.
+        // 3. Use an arbitary recent version.
+        // 4. Omit the version.
+        //
+        // The first option is too low / too conservative, and means that users will not get the
+        // same behaviour from a binary compiled with rustc as with one compiled by clang.
+        //
+        // The second option is similarly conservative, and also wrong since if the user specified a
+        // higher deployment target than the SDK they're compiling/linking with, the runtime might
+        // make invalid assumptions about the capabilities of the binary.
+        //
+        // The third option requires that `rustc` is periodically kept up to date with Apple's SDK
+        // version, and is also wrong for similar reasons as above.
+        //
+        // The fourth option is bad because while `ld`, `otool`, `vtool` and such understand it to
+        // mean "absent" or `n/a`, dyld doesn't actually understand it, and will end up interpreting
+        // it as 0.0, which is again too low/conservative.
+        //
+        // Currently, we lie about the SDK version, and choose the second option.
+        //
+        // FIXME(madsmtm): Parse the SDK version from the SDK root instead.
+        // <https://github.com/rust-lang/rust/issues/129432>
         let sdk_version = &*min_version;
 
         // From the man page for ld64 (`man ld`):
@@ -3053,11 +3085,13 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
         cmd.link_args(&["-platform_version", platform_name, &*min_version, sdk_version]);
     } else {
         // cc == Cc::Yes
+        //
         // We'd _like_ to use `-target` everywhere, since that can uniquely
-        // communicate all the required details, but that doesn't work on GCC,
-        // and since we don't know whether the `cc` compiler is Clang, GCC, or
-        // something else, we fall back to other options that also work on GCC
-        // when compiling for macOS.
+        // communicate all the required details except for the SDK version
+        // (which is read by Clang itself from the SDKROOT), but that doesn't
+        // work on GCC, and since we don't know whether the `cc` compiler is
+        // Clang, GCC, or something else, we fall back to other options that
+        // also work on GCC when compiling for macOS.
         //
         // Targets other than macOS are ill-supported by GCC (it doesn't even
         // support e.g. `-miphoneos-version-min`), so in those cases we can
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index a73ec83ee62..3f3d305da01 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -275,7 +275,12 @@ pub(crate) trait Linker {
     fn is_cc(&self) -> bool {
         false
     }
-    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
+    fn set_output_kind(
+        &mut self,
+        output_kind: LinkOutputKind,
+        crate_type: CrateType,
+        out_filename: &Path,
+    );
     fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
         bug!("dylib linked with unsupported linker")
     }
@@ -396,7 +401,7 @@ impl<'a> GccLinker<'a> {
         ]);
     }
 
-    fn build_dylib(&mut self, out_filename: &Path) {
+    fn build_dylib(&mut self, crate_type: CrateType, out_filename: &Path) {
         // On mac we need to tell the linker to let this library be rpathed
         if self.sess.target.is_like_osx {
             if !self.is_ld {
@@ -427,7 +432,7 @@ impl<'a> GccLinker<'a> {
                     let mut out_implib = OsString::from("--out-implib=");
                     out_implib.push(out_filename.with_file_name(implib_name));
                     self.link_arg(out_implib);
-                } else {
+                } else if crate_type == CrateType::Dylib {
                     // When dylibs are linked by a full path this value will get into `DT_NEEDED`
                     // instead of the full path, so the library can be later found in some other
                     // location than that specific path.
@@ -474,7 +479,12 @@ impl<'a> Linker for GccLinker<'a> {
         !self.is_ld
     }
 
-    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
+    fn set_output_kind(
+        &mut self,
+        output_kind: LinkOutputKind,
+        crate_type: CrateType,
+        out_filename: &Path,
+    ) {
         match output_kind {
             LinkOutputKind::DynamicNoPicExe => {
                 if !self.is_ld && self.is_gnu {
@@ -509,10 +519,10 @@ impl<'a> Linker for GccLinker<'a> {
                     self.link_args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
                 }
             }
-            LinkOutputKind::DynamicDylib => self.build_dylib(out_filename),
+            LinkOutputKind::DynamicDylib => self.build_dylib(crate_type, out_filename),
             LinkOutputKind::StaticDylib => {
                 self.link_or_cc_arg("-static");
-                self.build_dylib(out_filename);
+                self.build_dylib(crate_type, out_filename);
             }
             LinkOutputKind::WasiReactorExe => {
                 self.link_args(&["--entry", "_initialize"]);
@@ -866,7 +876,12 @@ impl<'a> Linker for MsvcLinker<'a> {
         &mut self.cmd
     }
 
-    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
+    fn set_output_kind(
+        &mut self,
+        output_kind: LinkOutputKind,
+        _crate_type: CrateType,
+        out_filename: &Path,
+    ) {
         match output_kind {
             LinkOutputKind::DynamicNoPicExe
             | LinkOutputKind::DynamicPicExe
@@ -1124,7 +1139,13 @@ impl<'a> Linker for EmLinker<'a> {
         true
     }
 
-    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+    fn set_output_kind(
+        &mut self,
+        _output_kind: LinkOutputKind,
+        _crate_type: CrateType,
+        _out_filename: &Path,
+    ) {
+    }
 
     fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
         // Emscripten always links statically
@@ -1273,7 +1294,12 @@ impl<'a> Linker for WasmLd<'a> {
         &mut self.cmd
     }
 
-    fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path) {
+    fn set_output_kind(
+        &mut self,
+        output_kind: LinkOutputKind,
+        _crate_type: CrateType,
+        _out_filename: &Path,
+    ) {
         match output_kind {
             LinkOutputKind::DynamicNoPicExe
             | LinkOutputKind::DynamicPicExe
@@ -1422,7 +1448,13 @@ impl<'a> Linker for L4Bender<'a> {
         &mut self.cmd
     }
 
-    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+    fn set_output_kind(
+        &mut self,
+        _output_kind: LinkOutputKind,
+        _crate_type: CrateType,
+        _out_filename: &Path,
+    ) {
+    }
 
     fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
         self.hint_static();
@@ -1568,7 +1600,12 @@ impl<'a> Linker for AixLinker<'a> {
         &mut self.cmd
     }
 
-    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
+    fn set_output_kind(
+        &mut self,
+        output_kind: LinkOutputKind,
+        _crate_type: CrateType,
+        out_filename: &Path,
+    ) {
         match output_kind {
             LinkOutputKind::DynamicDylib => {
                 self.hint_dynamic();
@@ -1775,7 +1812,13 @@ impl<'a> Linker for PtxLinker<'a> {
         &mut self.cmd
     }
 
-    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+    fn set_output_kind(
+        &mut self,
+        _output_kind: LinkOutputKind,
+        _crate_type: CrateType,
+        _out_filename: &Path,
+    ) {
+    }
 
     fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
         panic!("staticlibs not supported")
@@ -1841,7 +1884,13 @@ impl<'a> Linker for LlbcLinker<'a> {
         &mut self.cmd
     }
 
-    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+    fn set_output_kind(
+        &mut self,
+        _output_kind: LinkOutputKind,
+        _crate_type: CrateType,
+        _out_filename: &Path,
+    ) {
+    }
 
     fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
         panic!("staticlibs not supported")
@@ -1912,7 +1961,13 @@ impl<'a> Linker for BpfLinker<'a> {
         &mut self.cmd
     }
 
-    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+    fn set_output_kind(
+        &mut self,
+        _output_kind: LinkOutputKind,
+        _crate_type: CrateType,
+        _out_filename: &Path,
+    ) {
+    }
 
     fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
         panic!("staticlibs not supported")
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 06433484ea3..8857fda1e97 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -402,13 +402,17 @@ fn macho_object_build_version_for_target(target: &Target) -> object::write::Mach
     let platform =
         rustc_target::spec::current_apple_platform(target).expect("unknown Apple target OS");
     let min_os = rustc_target::spec::current_apple_deployment_target(target);
-    let (sdk_major, sdk_minor) =
-        rustc_target::spec::current_apple_sdk_version(platform).expect("unknown Apple target OS");
 
     let mut build_version = object::write::MachOBuildVersion::default();
     build_version.platform = platform;
     build_version.minos = pack_version(min_os);
-    build_version.sdk = pack_version((sdk_major, sdk_minor, 0));
+    // The version here does not _really_ matter, since it is only used at runtime, and we specify
+    // it when linking the final binary, so we will omit the version. This is also what LLVM does,
+    // and the tooling also allows this (and shows the SDK version as `n/a`). Finally, it is the
+    // semantically correct choice, as the SDK has not influenced the binary generated by rustc at
+    // this point in time.
+    build_version.sdk = 0;
+
     build_version
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 4d81ff933dd..e22dd8373bd 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -11,7 +11,6 @@ use rustc_ast::attr;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard};
-use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::Emitter;
 use rustc_errors::translation::Translate;
 use rustc_errors::{
@@ -1889,7 +1888,7 @@ impl SharedEmitter {
 }
 
 impl Translate for SharedEmitter {
-    fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
+    fn fluent_bundle(&self) -> Option<&FluentBundle> {
         None
     }
 
@@ -1924,7 +1923,7 @@ impl Emitter for SharedEmitter {
         );
     }
 
-    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
+    fn source_map(&self) -> Option<&SourceMap> {
         None
     }
 }
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 5c67600e4ee..d91c0f0790d 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -27,6 +27,9 @@ use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
 use rustc_span::symbol::sym;
 use rustc_span::{DUMMY_SP, Symbol};
 use rustc_target::abi::FIRST_VARIANT;
+use rustc_trait_selection::infer::at::ToTrace;
+use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt};
+use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
 use tracing::{debug, info};
 
 use crate::assert_module_sources::CguReuse;
@@ -101,6 +104,54 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx.sext(cmp, ret_ty)
 }
 
+/// Codegen takes advantage of the additional assumption, where if the
+/// principal trait def id of what's being casted doesn't change,
+/// then we don't need to adjust the vtable at all. This
+/// corresponds to the fact that `dyn Tr<A>: Unsize<dyn Tr<B>>`
+/// requires that `A = B`; we don't allow *upcasting* objects
+/// between the same trait with different args. If we, for
+/// some reason, were to relax the `Unsize` trait, it could become
+/// unsound, so let's validate here that the trait refs are subtypes.
+pub fn validate_trivial_unsize<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    source_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
+    target_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
+) -> bool {
+    match (source_data.principal(), target_data.principal()) {
+        (Some(hr_source_principal), Some(hr_target_principal)) => {
+            let infcx = tcx.infer_ctxt().build();
+            let universe = infcx.universe();
+            let ocx = ObligationCtxt::new(&infcx);
+            infcx.enter_forall(hr_target_principal, |target_principal| {
+                let source_principal = infcx.instantiate_binder_with_fresh_vars(
+                    DUMMY_SP,
+                    BoundRegionConversionTime::HigherRankedType,
+                    hr_source_principal,
+                );
+                let Ok(()) = ocx.eq_trace(
+                    &ObligationCause::dummy(),
+                    ty::ParamEnv::reveal_all(),
+                    ToTrace::to_trace(
+                        &ObligationCause::dummy(),
+                        hr_target_principal,
+                        hr_source_principal,
+                    ),
+                    target_principal,
+                    source_principal,
+                ) else {
+                    return false;
+                };
+                if !ocx.select_all_or_error().is_empty() {
+                    return false;
+                }
+                infcx.leak_check(universe, None).is_ok()
+            })
+        }
+        (None, None) => true,
+        _ => false,
+    }
+}
+
 /// Retrieves the information we are losing (making dynamic) in an unsizing
 /// adjustment.
 ///
@@ -133,12 +184,8 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 // between the same trait with different args. If we, for
                 // some reason, were to relax the `Unsize` trait, it could become
                 // unsound, so let's assert here that the trait refs are *equal*.
-                //
-                // We can use `assert_eq` because the binders should have been anonymized,
-                // and because higher-ranked equality now requires the binders are equal.
-                debug_assert_eq!(
-                    data_a.principal(),
-                    data_b.principal(),
+                debug_assert!(
+                    validate_trivial_unsize(cx.tcx(), data_a, data_b),
                     "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
                 );
 
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 08b326e3ac3..ab909abcead 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -916,8 +916,8 @@ pub enum InvalidMonomorphization<'tcx> {
         ret_ty: Ty<'tcx>,
     },
 
-    #[diag(codegen_ssa_invalid_monomorphization_cast_fat_pointer, code = E0511)]
-    CastFatPointer {
+    #[diag(codegen_ssa_invalid_monomorphization_cast_wide_pointer, code = E0511)]
+    CastWidePointer {
         #[primary_span]
         span: Span,
         name: Symbol,
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 162d14272a5..3129b9ac203 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -156,7 +156,7 @@ pub struct NativeLib {
     pub kind: NativeLibKind,
     pub name: Symbol,
     pub filename: Option<Symbol>,
-    pub cfg: Option<ast::MetaItem>,
+    pub cfg: Option<ast::NestedMetaItem>,
     pub verbatim: bool,
     pub dll_imports: Vec<cstore::DllImport>,
 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 125d3b908c7..be9a6d9a90e 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -3,7 +3,9 @@ use std::cmp;
 use rustc_ast as ast;
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_hir::lang_items::LangItem;
-use rustc_middle::mir::{self, AssertKind, BasicBlock, SwitchTargets, UnwindTerminateReason};
+use rustc_middle::mir::{
+    self, AssertKind, BasicBlock, InlineAsmMacro, SwitchTargets, UnwindTerminateReason,
+};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Instance, Ty};
@@ -1133,6 +1135,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         &mut self,
         helper: TerminatorCodegenHelper<'tcx>,
         bx: &mut Bx,
+        asm_macro: InlineAsmMacro,
         terminator: &mir::Terminator<'tcx>,
         template: &[ast::InlineAsmTemplatePiece],
         operands: &[mir::InlineAsmOperand<'tcx>],
@@ -1203,11 +1206,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             &operands,
             options,
             line_spans,
-            if options.contains(InlineAsmOptions::NORETURN) {
-                None
-            } else {
-                targets.get(0).copied()
-            },
+            if asm_macro.diverges(options) { None } else { targets.get(0).copied() },
             unwind,
             instance,
             mergeable_succ,
@@ -1381,6 +1380,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             }
 
             mir::TerminatorKind::InlineAsm {
+                asm_macro,
                 template,
                 ref operands,
                 options,
@@ -1390,6 +1390,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             } => self.codegen_asm_terminator(
                 helper,
                 bx,
+                asm_macro,
                 terminator,
                 template,
                 operands,
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index c4fb24aa625..8bd172a9ce6 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -133,9 +133,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 enum LocalRef<'tcx, V> {
     Place(PlaceRef<'tcx, V>),
     /// `UnsizedPlace(p)`: `p` itself is a thin pointer (indirect place).
-    /// `*p` is the fat pointer that references the actual unsized place.
+    /// `*p` is the wide pointer that references the actual unsized place.
     /// Every time it is initialized, we have to reallocate the place
-    /// and update the fat pointer. That's the reason why it is indirect.
+    /// and update the wide pointer. That's the reason why it is indirect.
     UnsizedPlace(PlaceRef<'tcx, V>),
     /// The backend [`OperandValue`] has already been generated.
     Operand(OperandRef<'tcx, V>),
@@ -429,7 +429,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 // Unsized indirect qrguments
                 PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
                     // As the storage for the indirect argument lives during
-                    // the whole function call, we just copy the fat pointer.
+                    // the whole function call, we just copy the wide pointer.
                     let llarg = bx.get_param(llarg_idx);
                     llarg_idx += 1;
                     let llextra = bx.get_param(llarg_idx);
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 17f66c12a03..0bcd7d6d081 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -41,7 +41,7 @@ pub enum OperandValue<V> {
     /// The backend value in this variant must be the *immediate* backend type,
     /// as returned by [`LayoutTypeCodegenMethods::immediate_backend_type`].
     Immediate(V),
-    /// A pair of immediate LLVM values. Used by fat pointers too.
+    /// A pair of immediate LLVM values. Used by wide pointers too.
     ///
     /// An `OperandValue` *must* be this variant for any type for which
     /// [`LayoutTypeCodegenMethods::is_backend_scalar_pair`] returns `true`.
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index f9c0f3ce941..a132ca69540 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -38,10 +38,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 ref source,
                 _,
             ) => {
-                // The destination necessarily contains a fat pointer, so if
-                // it's a scalar pair, it's a fat pointer or newtype thereof.
+                // The destination necessarily contains a wide pointer, so if
+                // it's a scalar pair, it's a wide pointer or newtype thereof.
                 if bx.cx().is_backend_scalar_pair(dest.layout) {
-                    // Into-coerce of a thin pointer to a fat pointer -- just
+                    // Into-coerce of a thin pointer to a wide pointer -- just
                     // use the operand path.
                     let temp = self.codegen_rvalue_operand(bx, rvalue);
                     temp.val.store(bx, dest);
@@ -519,7 +519,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             if bx.cx().is_backend_scalar_pair(cast) {
                                 OperandValue::Pair(data_ptr, meta)
                             } else {
-                                // Cast of fat-ptr to thin-ptr is an extraction of data-ptr.
+                                // Cast of wide-ptr to thin-ptr is an extraction of data-ptr.
                                 OperandValue::Immediate(data_ptr)
                             }
                         } else {
@@ -622,7 +622,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     (
                         OperandValue::Pair(lhs_addr, lhs_extra),
                         OperandValue::Pair(rhs_addr, rhs_extra),
-                    ) => self.codegen_fat_ptr_binop(
+                    ) => self.codegen_wide_ptr_binop(
                         bx,
                         op,
                         lhs_addr,
@@ -984,7 +984,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         }
     }
 
-    fn codegen_fat_ptr_binop(
+    fn codegen_wide_ptr_binop(
         &mut self,
         bx: &mut Bx,
         op: mir::BinOp,
@@ -1021,7 +1021,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 bx.or(lhs, rhs)
             }
             _ => {
-                bug!("unexpected fat ptr binop");
+                bug!("unexpected wide ptr binop");
             }
         }
     }
diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
index ed1c912e6cb..743924faa21 100644
--- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
@@ -6,7 +6,8 @@ use rustc_middle::{bug, span_bug, ty};
 use rustc_span::def_id::DefId;
 
 use crate::interpret::{
-    self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic, throw_machine_stop,
+    self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic, interp_ok,
+    throw_machine_stop,
 };
 
 /// Macro for machine-specific `InterpError` without allocation.
@@ -79,7 +80,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine {
             throw_machine_stop_str!("can't access mutable globals in ConstProp");
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     fn find_mir_or_eval_fn(
@@ -127,7 +128,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine {
         right: &interpret::ImmTy<'tcx, Self::Provenance>,
     ) -> interpret::InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> {
         use rustc_middle::mir::BinOp::*;
-        Ok(match bin_op {
+        interp_ok(match bin_op {
             Eq | Ne | Lt | Le | Gt | Ge => {
                 // Types can differ, e.g. fn ptrs with different `for`.
                 assert_eq!(left.layout.abi, right.layout.abi);
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index a241edbd77a..672353e629d 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -20,7 +20,7 @@ use crate::const_eval::CheckAlignment;
 use crate::interpret::{
     CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpError,
     InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup, create_static_alloc,
-    eval_nullary_intrinsic, intern_const_alloc_recursive, throw_exhaust,
+    eval_nullary_intrinsic, intern_const_alloc_recursive, interp_ok, throw_exhaust,
 };
 use crate::{CTRL_C_RECEIVED, errors};
 
@@ -98,19 +98,19 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
             return Err(ecx
                 .tcx
                 .dcx()
-                .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind })
-                .into());
+                .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }))
+            .into();
         }
         Err(InternResult::FoundBadMutablePointer) => {
             return Err(ecx
                 .tcx
                 .dcx()
-                .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind })
-                .into());
+                .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }))
+            .into();
         }
     }
 
-    Ok(R::make_result(ret, ecx))
+    interp_ok(R::make_result(ret, ecx))
 }
 
 /// The `InterpCx` is only meant to be used to do field and index projections into constants for
@@ -147,7 +147,8 @@ pub fn mk_eval_cx_for_const_val<'tcx>(
     ty: Ty<'tcx>,
 ) -> Option<(CompileTimeInterpCx<'tcx>, OpTy<'tcx>)> {
     let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No);
-    let op = ecx.const_val_to_op(val, ty, None).ok()?;
+    // FIXME: is it a problem to discard the error here?
+    let op = ecx.const_val_to_op(val, ty, None).discard_err()?;
     Some((ecx, op))
 }
 
@@ -185,12 +186,16 @@ pub(super) fn op_to_const<'tcx>(
         _ => false,
     };
     let immediate = if force_as_immediate {
-        match ecx.read_immediate(op) {
+        match ecx.read_immediate(op).report_err() {
             Ok(imm) => Right(imm),
-            Err(err) if !for_diagnostics => {
-                panic!("normalization works on validated constants: {err:?}")
+            Err(err) => {
+                if for_diagnostics {
+                    // This discard the error, but for diagnostics that's okay.
+                    op.as_mplace_or_imm()
+                } else {
+                    panic!("normalization works on validated constants: {err:?}")
+                }
             }
-            _ => op.as_mplace_or_imm(),
         }
     } else {
         op.as_mplace_or_imm()
@@ -283,17 +288,19 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
         let ty::FnDef(_, args) = ty.kind() else {
             bug!("intrinsic with type {:?}", ty);
         };
-        return eval_nullary_intrinsic(tcx, key.param_env, def_id, args).map_err(|error| {
-            let span = tcx.def_span(def_id);
-
-            super::report(
-                tcx,
-                error.into_kind(),
-                span,
-                || (span, vec![]),
-                |span, _| errors::NullaryIntrinsicError { span },
-            )
-        });
+        return eval_nullary_intrinsic(tcx, key.param_env, def_id, args).report_err().map_err(
+            |error| {
+                let span = tcx.def_span(def_id);
+
+                super::report(
+                    tcx,
+                    error.into_kind(),
+                    span,
+                    || (span, vec![]),
+                    |span, _| errors::NullaryIntrinsicError { span },
+                )
+            },
+        );
     }
 
     tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key))
@@ -376,6 +383,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
     );
     let res = ecx.load_mir(cid.instance.def, cid.promoted);
     res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body))
+        .report_err()
         .map_err(|error| report_eval_error(&ecx, cid, error))
 }
 
@@ -400,6 +408,7 @@ fn const_validate_mplace<'tcx>(
             }
         };
         ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)
+            .report_err()
             // Instead of just reporting the `InterpError` via the usual machinery, we give a more targeted
             // error about the validation failure.
             .map_err(|error| report_validation_error(&ecx, cid, error, alloc_id))?;
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 6d74998b7d8..4aec74595bc 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -24,8 +24,8 @@ use crate::fluent_generated as fluent;
 use crate::interpret::{
     self, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy,
     InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, RangeSet, Scalar,
-    StackPopCleanup, compile_time_machine, err_ub, throw_exhaust, throw_inval, throw_ub_custom,
-    throw_unsup, throw_unsup_format,
+    StackPopCleanup, compile_time_machine, interp_ok, throw_exhaust, throw_inval, throw_ub,
+    throw_ub_custom, throw_unsup, throw_unsup_format,
 };
 
 /// When hitting this many interpreted terminators we emit a deny by default lint
@@ -247,7 +247,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
             let msg = Symbol::intern(self.read_str(&msg_place)?);
             let span = self.find_closest_untracked_caller_location();
             let (file, line, col) = self.location_triple_for_span(span);
-            return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into());
+            return Err(ConstEvalErrKind::Panic { msg, file, line, col }).into();
         } else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) {
             // For panic_fmt, call const_panic_fmt instead.
             let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None);
@@ -259,16 +259,16 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
                 self.cur_span(),
             );
 
-            return Ok(Some(new_instance));
+            return interp_ok(Some(new_instance));
         } else if self.tcx.is_lang_item(def_id, LangItem::AlignOffset) {
             let args = self.copy_fn_args(args);
             // For align_offset, we replace the function call if the pointer has no address.
             match self.align_offset(instance, &args, dest, ret)? {
-                ControlFlow::Continue(()) => return Ok(Some(instance)),
-                ControlFlow::Break(()) => return Ok(None),
+                ControlFlow::Continue(()) => return interp_ok(Some(instance)),
+                ControlFlow::Break(()) => return interp_ok(None),
             }
         }
-        Ok(Some(instance))
+        interp_ok(Some(instance))
     }
 
     /// `align_offset(ptr, target_align)` needs special handling in const eval, because the pointer
@@ -323,25 +323,25 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
                         dest,
                         StackPopCleanup::Goto { ret, unwind: mir::UnwindAction::Unreachable },
                     )?;
-                    Ok(ControlFlow::Break(()))
+                    interp_ok(ControlFlow::Break(()))
                 } else {
                     // Not alignable in const, return `usize::MAX`.
                     let usize_max = Scalar::from_target_usize(self.target_usize_max(), self);
                     self.write_scalar(usize_max, dest)?;
                     self.return_to_block(ret)?;
-                    Ok(ControlFlow::Break(()))
+                    interp_ok(ControlFlow::Break(()))
                 }
             }
             Err(_addr) => {
                 // The pointer has an address, continue with function call.
-                Ok(ControlFlow::Continue(()))
+                interp_ok(ControlFlow::Continue(()))
             }
         }
     }
 
     /// See documentation on the `ptr_guaranteed_cmp` intrinsic.
     fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> {
-        Ok(match (a, b) {
+        interp_ok(match (a, b) {
             // Comparisons between integers are always known.
             (Scalar::Int { .. }, Scalar::Int { .. }) => {
                 if a == b {
@@ -403,8 +403,8 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
         instance: ty::InstanceKind<'tcx>,
     ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
         match instance {
-            ty::InstanceKind::Item(def) => Ok(ecx.tcx.mir_for_ctfe(def)),
-            _ => Ok(ecx.tcx.instance_mir(instance)),
+            ty::InstanceKind::Item(def) => interp_ok(ecx.tcx.mir_for_ctfe(def)),
+            _ => interp_ok(ecx.tcx.instance_mir(instance)),
         }
     }
 
@@ -422,7 +422,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
         // Replace some functions.
         let Some(instance) = ecx.hook_special_const_fn(orig_instance, args, dest, ret)? else {
             // Call has already been handled.
-            return Ok(None);
+            return interp_ok(None);
         };
 
         // Only check non-glue functions
@@ -444,14 +444,14 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
         // This is a const fn. Call it.
         // In case of replacement, we return the *original* instance to make backtraces work out
         // (and we hope this does not confuse the FnAbi checks too much).
-        Ok(Some((ecx.load_mir(instance.def, None)?, orig_instance)))
+        interp_ok(Some((ecx.load_mir(instance.def, None)?, orig_instance)))
     }
 
     fn panic_nounwind(ecx: &mut InterpCx<'tcx, Self>, msg: &str) -> InterpResult<'tcx> {
         let msg = Symbol::intern(msg);
         let span = ecx.find_closest_untracked_caller_location();
         let (file, line, col) = ecx.location_triple_for_span(span);
-        Err(ConstEvalErrKind::Panic { msg, file, line, col }.into())
+        Err(ConstEvalErrKind::Panic { msg, file, line, col }).into()
     }
 
     fn call_intrinsic(
@@ -464,7 +464,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
     ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
         // Shared intrinsics.
         if ecx.eval_intrinsic(instance, args, dest, target)? {
-            return Ok(None);
+            return interp_ok(None);
         }
         let intrinsic_name = ecx.tcx.item_name(instance.def_id());
 
@@ -541,7 +541,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
                         "intrinsic `{intrinsic_name}` is not supported at compile-time"
                     );
                 }
-                return Ok(Some(ty::Instance {
+                return interp_ok(Some(ty::Instance {
                     def: ty::InstanceKind::Item(instance.def_id()),
                     args: instance.args,
                 }));
@@ -550,7 +550,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
 
         // Intrinsic is done, jump to next block.
         ecx.return_to_block(target)?;
-        Ok(None)
+        interp_ok(None)
     }
 
     fn assert_panic(
@@ -581,7 +581,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
                 }
             }
         };
-        Err(ConstEvalErrKind::AssertFailure(err).into())
+        Err(ConstEvalErrKind::AssertFailure(err)).into()
     }
 
     fn binary_ptr_op(
@@ -652,7 +652,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
             }
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     #[inline(always)]
@@ -670,7 +670,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
         if !ecx.recursion_limit.value_within_limit(ecx.stack().len() + 1) {
             throw_exhaust!(StackFrameLimitReached)
         } else {
-            Ok(frame)
+            interp_ok(frame)
         }
     }
 
@@ -700,22 +700,22 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
         if is_write {
             // Write access. These are never allowed, but we give a targeted error message.
             match alloc.mutability {
-                Mutability::Not => Err(err_ub!(WriteToReadOnly(alloc_id)).into()),
-                Mutability::Mut => Err(ConstEvalErrKind::ModifiedGlobal.into()),
+                Mutability::Not => throw_ub!(WriteToReadOnly(alloc_id)),
+                Mutability::Mut => Err(ConstEvalErrKind::ModifiedGlobal).into(),
             }
         } else {
             // Read access. These are usually allowed, with some exceptions.
             if machine.can_access_mut_global == CanAccessMutGlobal::Yes {
                 // Machine configuration allows us read from anything (e.g., `static` initializer).
-                Ok(())
+                interp_ok(())
             } else if alloc.mutability == Mutability::Mut {
                 // Machine configuration does not allow us to read statics (e.g., `const`
                 // initializer).
-                Err(ConstEvalErrKind::ConstAccessesMutGlobal.into())
+                Err(ConstEvalErrKind::ConstAccessesMutGlobal).into()
             } else {
                 // Immutable global, this read is fine.
                 assert_eq!(alloc.mutability, Mutability::Not);
-                Ok(())
+                interp_ok(())
             }
         }
     }
@@ -748,9 +748,9 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
                 // even when there is interior mutability.)
                 place.map_provenance(CtfeProvenance::as_shared_ref)
             };
-            Ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout))
+            interp_ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout))
         } else {
-            Ok(val.clone())
+            interp_ok(val.clone())
         }
     }
 
@@ -763,20 +763,20 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
     ) -> InterpResult<'tcx> {
         if range.size == Size::ZERO {
             // Nothing to check.
-            return Ok(());
+            return interp_ok(());
         }
         // Reject writes through immutable pointers.
         if immutable {
-            return Err(ConstEvalErrKind::WriteThroughImmutablePointer.into());
+            return Err(ConstEvalErrKind::WriteThroughImmutablePointer).into();
         }
         // Everything else is fine.
-        Ok(())
+        interp_ok(())
     }
 
     fn before_alloc_read(ecx: &InterpCx<'tcx, Self>, alloc_id: AllocId) -> InterpResult<'tcx> {
         // Check if this is the currently evaluated static.
         if Some(alloc_id) == ecx.machine.static_root_ids.map(|(id, _)| id) {
-            return Err(ConstEvalErrKind::RecursiveStatic.into());
+            return Err(ConstEvalErrKind::RecursiveStatic).into();
         }
         // If this is another static, make sure we fire off the query to detect cycles.
         // But only do that when checks for static recursion are enabled.
@@ -788,7 +788,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
                 ecx.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
             }
         }
-        Ok(())
+        interp_ok(())
     }
 
     fn cached_union_data_range<'e>(
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index 48aeee2e6f0..ba19f642795 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -1,13 +1,12 @@
 // Not in interpret to make sure we do not use private implementation details
 
-use rustc_middle::mir::interpret::InterpErrorInfo;
 use rustc_middle::query::{Key, TyCtxtAt};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::{bug, mir};
 use rustc_target::abi::VariantIdx;
 use tracing::instrument;
 
-use crate::interpret::{InterpCx, format_interp_error};
+use crate::interpret::InterpCx;
 
 mod dummy_machine;
 mod error;
@@ -33,17 +32,6 @@ pub(crate) enum ValTreeCreationError<'tcx> {
 }
 pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError<'tcx>>;
 
-impl<'tcx> From<InterpErrorInfo<'tcx>> for ValTreeCreationError<'tcx> {
-    fn from(err: InterpErrorInfo<'tcx>) -> Self {
-        ty::tls::with(|tcx| {
-            bug!(
-                "Unexpected Undefined Behavior error during valtree construction: {}",
-                format_interp_error(tcx.dcx(), err),
-            )
-        })
-    }
-}
-
 #[instrument(skip(tcx), level = "debug")]
 pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
     tcx: TyCtxtAt<'tcx>,
@@ -60,8 +48,8 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
             return None;
         }
         ty::Adt(def, _) => {
-            let variant = ecx.read_discriminant(&op).ok()?;
-            let down = ecx.project_downcast(&op, variant).ok()?;
+            let variant = ecx.read_discriminant(&op).discard_err()?;
+            let down = ecx.project_downcast(&op, variant).discard_err()?;
             (def.variants()[variant].fields.len(), Some(variant), down)
         }
         ty::Tuple(args) => (args.len(), None, op),
@@ -70,7 +58,7 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
 
     let fields_iter = (0..field_count)
         .map(|i| {
-            let field_op = ecx.project_field(&down, i).ok()?;
+            let field_op = ecx.project_field(&down, i).discard_err()?;
             let val = op_to_const(&ecx, &field_op, /* for diagnostics */ true);
             Some((val, field_op.layout.ty))
         })
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index a11d491bdd2..9e80e666ba9 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -92,7 +92,7 @@ fn const_to_valtree_inner<'tcx>(
             Ok(ty::ValTree::zst())
         }
         ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
-            let val = ecx.read_immediate(place)?;
+            let val = ecx.read_immediate(place).unwrap();
             let val = val.to_scalar_int().unwrap();
             *num_nodes += 1;
 
@@ -114,7 +114,7 @@ fn const_to_valtree_inner<'tcx>(
             // equality at compile-time (see `ptr_guaranteed_cmp`).
             // However we allow those that are just integers in disguise.
             // First, get the pointer. Remember it might be wide!
-            let val = ecx.read_immediate(place)?;
+            let val = ecx.read_immediate(place).unwrap();
             // We could allow wide raw pointers where both sides are integers in the future,
             // but for now we reject them.
             if matches!(val.layout.abi, Abi::ScalarPair(..)) {
@@ -135,7 +135,7 @@ fn const_to_valtree_inner<'tcx>(
         ty::FnPtr(..) => Err(ValTreeCreationError::NonSupportedType(ty)),
 
         ty::Ref(_, _, _)  => {
-            let derefd_place = ecx.deref_pointer(place)?;
+            let derefd_place = ecx.deref_pointer(place).unwrap();
             const_to_valtree_inner(ecx, &derefd_place, num_nodes)
         }
 
@@ -159,7 +159,7 @@ fn const_to_valtree_inner<'tcx>(
                 bug!("uninhabited types should have errored and never gotten converted to valtree")
             }
 
-            let variant = ecx.read_discriminant(place)?;
+            let variant = ecx.read_discriminant(place).unwrap();
             branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes)
         }
 
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index 19aa76bf1ea..4945563f4a4 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -15,8 +15,8 @@ use tracing::{info, instrument, trace};
 
 use super::{
     CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy,
-    Projectable, Provenance, ReturnAction, Scalar, StackPopCleanup, StackPopInfo, throw_ub,
-    throw_ub_custom, throw_unsup_format,
+    Projectable, Provenance, ReturnAction, Scalar, StackPopCleanup, StackPopInfo, interp_ok,
+    throw_ub, throw_ub_custom, throw_unsup_format,
 };
 use crate::fluent_generated as fluent;
 
@@ -64,7 +64,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         arg: &FnArg<'tcx, M::Provenance>,
         field: usize,
     ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> {
-        Ok(match arg {
+        interp_ok(match arg {
             FnArg::Copy(op) => FnArg::Copy(self.project_field(op, field)?),
             FnArg::InPlace(mplace) => FnArg::InPlace(self.project_field(mplace, field)?),
         })
@@ -97,7 +97,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // another type.
         let ty::Adt(def, args) = layout.ty.kind() else {
             // Not an ADT, so definitely no NPO.
-            return Ok(layout);
+            return interp_ok(layout);
         };
         let inner = if self.tcx.is_diagnostic_item(sym::Option, def.did()) {
             // The wrapped type is the only arg.
@@ -111,10 +111,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             } else if rhs.is_1zst() {
                 lhs
             } else {
-                return Ok(layout); // no NPO
+                return interp_ok(layout); // no NPO
             }
         } else {
-            return Ok(layout); // no NPO
+            return interp_ok(layout); // no NPO
         };
 
         // Check if the inner type is one of the NPO-guaranteed ones.
@@ -126,7 +126,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             // Stop at NPO types so that we don't miss that attribute in the check below!
             def.is_struct() && !is_npo(def)
         });
-        Ok(match inner.ty.kind() {
+        interp_ok(match inner.ty.kind() {
             ty::Ref(..) | ty::FnPtr(..) => {
                 // Option<&T> behaves like &T, and same for fn()
                 inner
@@ -153,11 +153,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ) -> InterpResult<'tcx, bool> {
         // Fast path: equal types are definitely compatible.
         if caller.ty == callee.ty {
-            return Ok(true);
+            return interp_ok(true);
         }
         // 1-ZST are compatible with all 1-ZST (and with nothing else).
         if caller.is_1zst() || callee.is_1zst() {
-            return Ok(caller.is_1zst() && callee.is_1zst());
+            return interp_ok(caller.is_1zst() && callee.is_1zst());
         }
         // Unfold newtypes and NPO optimizations.
         let unfold = |layout: TyAndLayout<'tcx>| {
@@ -180,17 +180,17 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             _ => None,
         };
         if let (Some(caller), Some(callee)) = (thin_pointer(caller), thin_pointer(callee)) {
-            return Ok(caller == callee);
+            return interp_ok(caller == callee);
         }
         // For wide pointers we have to get the pointee type.
         let pointee_ty = |ty: Ty<'tcx>| -> InterpResult<'tcx, Option<Ty<'tcx>>> {
             // We cannot use `builtin_deref` here since we need to reject `Box<T, MyAlloc>`.
-            Ok(Some(match ty.kind() {
+            interp_ok(Some(match ty.kind() {
                 ty::Ref(_, ty, _) => *ty,
                 ty::RawPtr(ty, _) => *ty,
                 // We only accept `Box` with the default allocator.
                 _ if ty.is_box_global(*self.tcx) => ty.expect_boxed_ty(),
-                _ => return Ok(None),
+                _ => return interp_ok(None),
             }))
         };
         if let (Some(caller), Some(callee)) = (pointee_ty(caller.ty)?, pointee_ty(callee.ty)?) {
@@ -202,7 +202,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let normalize = |ty| self.tcx.normalize_erasing_regions(self.param_env, ty);
                 ty.ptr_metadata_ty(*self.tcx, normalize)
             };
-            return Ok(meta_ty(caller) == meta_ty(callee));
+            return interp_ok(meta_ty(caller) == meta_ty(callee));
         }
 
         // Compatible integer types (in particular, usize vs ptr-sized-u32/u64).
@@ -217,11 +217,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         };
         if let (Some(caller), Some(callee)) = (int_ty(caller.ty), int_ty(callee.ty)) {
             // This is okay if they are the same integer type.
-            return Ok(caller == callee);
+            return interp_ok(caller == callee);
         }
 
         // Fall back to exact equality.
-        Ok(caller == callee)
+        interp_ok(caller == callee)
     }
 
     fn check_argument_compat(
@@ -235,13 +235,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             // Ensure that our checks imply actual ABI compatibility for this concrete call.
             // (This can fail e.g. if `#[rustc_nonnull_optimization_guaranteed]` is used incorrectly.)
             assert!(caller_abi.eq_abi(callee_abi));
-            Ok(true)
+            interp_ok(true)
         } else {
             trace!(
                 "check_argument_compat: incompatible ABIs:\ncaller: {:?}\ncallee: {:?}",
                 caller_abi, callee_abi
             );
-            Ok(false)
+            interp_ok(false)
         }
     }
 
@@ -266,7 +266,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             if !already_live {
                 self.storage_live(callee_arg.as_local().unwrap())?;
             }
-            return Ok(());
+            return interp_ok(());
         }
         // Find next caller arg.
         let Some((caller_arg, caller_abi)) = caller_args.next() else {
@@ -308,7 +308,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         if let FnArg::InPlace(mplace) = caller_arg {
             M::protect_in_place_function_argument(self, mplace)?;
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// The main entry point for creating a new stack frame: performs ABI checks and initializes
@@ -536,7 +536,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                         unwind,
                     );
                 } else {
-                    Ok(())
+                    interp_ok(())
                 }
             }
             ty::InstanceKind::VTableShim(..)
@@ -561,7 +561,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     unwind,
                 )?
                 else {
-                    return Ok(());
+                    return interp_ok(());
                 };
 
                 // Special handling for the closure ABI: untuple the last argument.
@@ -572,7 +572,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                         trace!("init_fn_call: Will pass last argument by untupling");
                         Cow::from(
                             args.iter()
-                                .map(|a| Ok(a.clone()))
+                                .map(|a| interp_ok(a.clone()))
                                 .chain(
                                     (0..untuple_arg.layout().fields.count())
                                         .map(|i| self.fn_arg_field(untuple_arg, i)),
@@ -886,27 +886,25 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             // this transmute.
             res
         } else {
-            Ok(())
+            interp_ok(())
         };
 
         // All right, now it is time to actually pop the frame.
-        let stack_pop_info = self.pop_stack_frame_raw(unwinding)?;
-
-        // Report error from return value copy, if any.
-        copy_ret_result?;
+        // An error here takes precedence over the copy error.
+        let (stack_pop_info, ()) = self.pop_stack_frame_raw(unwinding).and(copy_ret_result)?;
 
         match stack_pop_info.return_action {
             ReturnAction::Normal => {}
             ReturnAction::NoJump => {
                 // The hook already did everything.
-                return Ok(());
+                return interp_ok(());
             }
             ReturnAction::NoCleanup => {
                 // If we are not doing cleanup, also skip everything else.
                 assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
                 assert!(!unwinding, "tried to skip cleanup during unwinding");
                 // Skip machine hook.
-                return Ok(());
+                return interp_ok(());
             }
         }
 
@@ -931,7 +929,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                         self.stack().is_empty(),
                         "only the bottommost frame can have StackPopCleanup::Root"
                     );
-                    Ok(())
+                    interp_ok(())
                 }
             }
         }
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 85e7d91c2ad..30b5a8d70bc 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -14,7 +14,8 @@ use tracing::trace;
 
 use super::util::ensure_monomorphic_enough;
 use super::{
-    FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, err_inval, throw_ub, throw_ub_custom,
+    FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, err_inval, interp_ok, throw_ub,
+    throw_ub_custom,
 };
 use crate::fluent_generated as fluent;
 
@@ -157,7 +158,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 self.copy_op_allow_transmute(src, dest)?;
             }
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Handles 'IntToInt' and 'IntToFloat' casts.
@@ -169,7 +170,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         assert!(src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool());
         assert!(cast_to.ty.is_floating_point() || cast_to.ty.is_integral() || cast_to.ty.is_char());
 
-        Ok(ImmTy::from_scalar(
+        interp_ok(ImmTy::from_scalar(
             self.cast_from_int_like(src.to_scalar(), src.layout, cast_to.ty)?,
             cast_to,
         ))
@@ -192,7 +193,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             FloatTy::F64 => self.cast_from_float(src.to_scalar().to_f64()?, cast_to.ty),
             FloatTy::F128 => self.cast_from_float(src.to_scalar().to_f128()?, cast_to.ty),
         };
-        Ok(ImmTy::from_scalar(val, cast_to))
+        interp_ok(ImmTy::from_scalar(val, cast_to))
     }
 
     /// Handles 'FnPtrToPtr' and 'PtrToPtr' casts.
@@ -203,17 +204,17 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
         assert!(src.layout.ty.is_any_ptr());
         assert!(cast_to.ty.is_unsafe_ptr());
-        // Handle casting any ptr to raw ptr (might be a fat ptr).
+        // Handle casting any ptr to raw ptr (might be a wide ptr).
         if cast_to.size == src.layout.size {
-            // Thin or fat pointer that just has the ptr kind of target type changed.
-            return Ok(ImmTy::from_immediate(**src, cast_to));
+            // Thin or wide pointer that just has the ptr kind of target type changed.
+            return interp_ok(ImmTy::from_immediate(**src, cast_to));
         } else {
-            // Casting the metadata away from a fat ptr.
+            // Casting the metadata away from a wide ptr.
             assert_eq!(src.layout.size, 2 * self.pointer_size());
             assert_eq!(cast_to.size, self.pointer_size());
             assert!(src.layout.ty.is_unsafe_ptr());
             return match **src {
-                Immediate::ScalarPair(data, _) => Ok(ImmTy::from_scalar(data, cast_to)),
+                Immediate::ScalarPair(data, _) => interp_ok(ImmTy::from_scalar(data, cast_to)),
                 Immediate::Scalar(..) => span_bug!(
                     self.cur_span(),
                     "{:?} input to a fat-to-thin cast ({} -> {})",
@@ -240,7 +241,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             Ok(ptr) => M::expose_ptr(self, ptr)?,
             Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP.
         };
-        Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, cast_to))
+        interp_ok(ImmTy::from_scalar(
+            self.cast_from_int_like(scalar, src.layout, cast_to.ty)?,
+            cast_to,
+        ))
     }
 
     pub fn pointer_with_exposed_provenance_cast(
@@ -258,7 +262,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
         // Then turn address into pointer.
         let ptr = M::ptr_from_addr_cast(self, addr)?;
-        Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), cast_to))
+        interp_ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), cast_to))
     }
 
     /// Low-level cast helper function. This works directly on scalars and can take 'int-like' input
@@ -280,7 +284,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             _ => span_bug!(self.cur_span(), "invalid int-like cast from {}", src_layout.ty),
         };
 
-        Ok(match *cast_ty.kind() {
+        interp_ok(match *cast_ty.kind() {
             // int -> int
             Int(_) | Uint(_) => {
                 let size = match *cast_ty.kind() {
@@ -505,7 +509,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                         self.unsize_into(&src_field, cast_ty_field, &dst_field)?;
                     }
                 }
-                Ok(())
+                interp_ok(())
             }
             _ => {
                 // Do not ICE if we are not monomorphic enough.
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index 3bab2b3261e..81e0b1e12ca 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -7,7 +7,8 @@ use rustc_target::abi::{self, TagEncoding, VariantIdx, Variants};
 use tracing::{instrument, trace};
 
 use super::{
-    ImmTy, InterpCx, InterpResult, Machine, Projectable, Scalar, Writeable, err_ub, throw_ub,
+    ImmTy, InterpCx, InterpResult, Machine, Projectable, Scalar, Writeable, err_ub, interp_ok,
+    throw_ub,
 };
 
 impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
@@ -48,7 +49,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 if actual_variant != variant_index {
                     throw_ub!(InvalidNichedEnumVariantWritten { enum_ty: dest.layout().ty });
                 }
-                Ok(())
+                interp_ok(())
             }
         }
     }
@@ -89,7 +90,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                         throw_ub!(UninhabitedEnumVariantRead(index))
                     }
                 }
-                return Ok(index);
+                return interp_ok(index);
             }
             Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => {
                 (tag, tag_encoding, tag_field)
@@ -205,7 +206,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         if op.layout().for_variant(self, index).abi.is_uninhabited() {
             throw_ub!(UninhabitedEnumVariantRead(index))
         }
-        Ok(index)
+        interp_ok(index)
     }
 
     pub fn discriminant_for_variant(
@@ -226,7 +227,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 Scalar::from_uint(variant.as_u32(), discr_layout.size)
             }
         };
-        Ok(ImmTy::from_scalar(discr_value, discr_layout))
+        interp_ok(ImmTy::from_scalar(discr_value, discr_layout))
     }
 
     /// Computes how to write the tag of a given variant of enum `ty`:
@@ -247,7 +248,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 // discriminant is encoded implicitly, so any attempt to write
                 // the wrong discriminant for a `Single` enum will reliably
                 // result in UB.
-                Ok(None)
+                interp_ok(None)
             }
 
             abi::Variants::Multiple {
@@ -265,7 +266,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let tag_size = tag_layout.size(self);
                 let tag_val = tag_size.truncate(discr_val);
                 let tag = ScalarInt::try_from_uint(tag_val, tag_size).unwrap();
-                Ok(Some((tag, tag_field)))
+                interp_ok(Some((tag, tag_field)))
             }
 
             abi::Variants::Multiple {
@@ -274,7 +275,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             } if untagged_variant == variant_index => {
                 // The untagged variant is implicitly encoded simply by having a
                 // value that is outside the niche variants.
-                Ok(None)
+                interp_ok(None)
             }
 
             abi::Variants::Multiple {
@@ -299,7 +300,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let tag = self
                     .binary_op(mir::BinOp::Add, &variant_index_relative_val, &niche_start_val)?
                     .to_scalar_int()?;
-                Ok(Some((tag, tag_field)))
+                interp_ok(Some((tag, tag_field)))
             }
         }
     }
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index f4c4a6fb0bf..5165f95afd5 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -19,9 +19,9 @@ use rustc_trait_selection::traits::ObligationCtxt;
 use tracing::{debug, instrument, trace};
 
 use super::{
-    Frame, FrameInfo, GlobalId, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlaceMeta,
-    Memory, OpTy, Place, PlaceTy, PointerArithmetic, Projectable, Provenance, err_inval,
-    throw_inval, throw_ub, throw_ub_custom,
+    Frame, FrameInfo, GlobalId, InterpError, InterpErrorInfo, InterpResult, MPlaceTy, Machine,
+    MemPlaceMeta, Memory, OpTy, Place, PlaceTy, PointerArithmetic, Projectable, Provenance,
+    err_inval, interp_ok, throw_inval, throw_ub, throw_ub_custom,
 };
 use crate::{ReportErrorExt, fluent_generated as fluent, util};
 
@@ -73,7 +73,7 @@ where
 }
 
 impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> {
-    type LayoutOfResult = InterpResult<'tcx, TyAndLayout<'tcx>>;
+    type LayoutOfResult = Result<TyAndLayout<'tcx>, InterpError<'tcx>>;
 
     #[inline]
     fn layout_tcx_at_span(&self) -> Span {
@@ -82,29 +82,24 @@ impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> {
     }
 
     #[inline]
-    fn handle_layout_err(
-        &self,
-        err: LayoutError<'tcx>,
-        _: Span,
-        _: Ty<'tcx>,
-    ) -> InterpErrorInfo<'tcx> {
-        err_inval!(Layout(err)).into()
+    fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> InterpError<'tcx> {
+        err_inval!(Layout(err))
     }
 }
 
 impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> {
-    type FnAbiOfResult = InterpResult<'tcx, &'tcx FnAbi<'tcx, Ty<'tcx>>>;
+    type FnAbiOfResult = Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, InterpError<'tcx>>;
 
     fn handle_fn_abi_err(
         &self,
         err: FnAbiError<'tcx>,
         _span: Span,
         _fn_abi_request: FnAbiRequest<'tcx>,
-    ) -> InterpErrorInfo<'tcx> {
+    ) -> InterpError<'tcx> {
         match err {
-            FnAbiError::Layout(err) => err_inval!(Layout(err)).into(),
+            FnAbiError::Layout(err) => err_inval!(Layout(err)),
             FnAbiError::AdjustForForeignAbi(err) => {
-                err_inval!(FnAbiAdjustForForeignAbi(err)).into()
+                err_inval!(FnAbiAdjustForForeignAbi(err))
             }
         }
     }
@@ -160,7 +155,7 @@ pub(super) fn from_known_layout<'tcx>(
                     );
                 }
             }
-            Ok(known_layout)
+            interp_ok(known_layout)
         }
     }
 }
@@ -262,7 +257,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         if let Some(err) = body.tainted_by_errors {
             throw_inval!(AlreadyReported(ReportedErrorInfo::tainted_by_errors(err)));
         }
-        Ok(body)
+        interp_ok(body)
     }
 
     /// Call this on things you got out of the MIR (so it is as generic as the current
@@ -305,7 +300,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         trace!("param_env: {:#?}", self.param_env);
         trace!("args: {:#?}", args);
         match ty::Instance::try_resolve(*self.tcx, self.param_env, def, args) {
-            Ok(Some(instance)) => Ok(instance),
+            Ok(Some(instance)) => interp_ok(instance),
             Ok(None) => throw_inval!(TooGeneric),
 
             // FIXME(eddyb) this could be a bit more specific than `AlreadyReported`.
@@ -401,7 +396,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         layout: &TyAndLayout<'tcx>,
     ) -> InterpResult<'tcx, Option<(Size, Align)>> {
         if layout.is_sized() {
-            return Ok(Some((layout.size, layout.align.abi)));
+            return interp_ok(Some((layout.size, layout.align.abi)));
         }
         match layout.ty.kind() {
             ty::Adt(..) | ty::Tuple(..) => {
@@ -425,7 +420,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 else {
                     // A field with an extern type. We don't know the actual dynamic size
                     // or the alignment.
-                    return Ok(None);
+                    return interp_ok(None);
                 };
 
                 // # First compute the dynamic alignment
@@ -456,12 +451,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 if full_size > self.max_size_of_val() {
                     throw_ub!(InvalidMeta(InvalidMetaKind::TooBig));
                 }
-                Ok(Some((full_size, full_align)))
+                interp_ok(Some((full_size, full_align)))
             }
             ty::Dynamic(expected_trait, _, ty::Dyn) => {
                 let vtable = metadata.unwrap_meta().to_pointer(self)?;
                 // Read size and align from vtable (already checks size).
-                Ok(Some(self.get_vtable_size_and_align(vtable, Some(expected_trait))?))
+                interp_ok(Some(self.get_vtable_size_and_align(vtable, Some(expected_trait))?))
             }
 
             ty::Slice(_) | ty::Str => {
@@ -474,10 +469,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 if size > self.max_size_of_val() {
                     throw_ub!(InvalidMeta(InvalidMetaKind::SliceTooBig));
                 }
-                Ok(Some((size, elem.align.abi)))
+                interp_ok(Some((size, elem.align.abi)))
             }
 
-            ty::Foreign(_) => Ok(None),
+            ty::Foreign(_) => interp_ok(None),
 
             _ => span_bug!(self.cur_span(), "size_and_align_of::<{}> not supported", layout.ty),
         }
@@ -503,7 +498,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     pub fn return_to_block(&mut self, target: Option<mir::BasicBlock>) -> InterpResult<'tcx> {
         if let Some(target) = target {
             self.go_to_block(target);
-            Ok(())
+            interp_ok(())
         } else {
             throw_ub!(Unreachable)
         }
@@ -530,10 +525,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 M::unwind_terminate(self, reason)?;
                 // This might have pushed a new stack frame, or it terminated execution.
                 // Either way, `loc` will not be updated.
-                return Ok(());
+                return interp_ok(());
             }
         };
-        Ok(())
+        interp_ok(())
     }
 
     /// Call a query that can return `ErrorHandled`. Should be used for statics and other globals.
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 81659df7c53..7a1b92601a4 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -26,7 +26,9 @@ use rustc_span::def_id::LocalDefId;
 use rustc_span::sym;
 use tracing::{instrument, trace};
 
-use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, err_ub};
+use super::{
+    AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, err_ub, interp_ok,
+};
 use crate::const_eval;
 use crate::errors::NestedStaticInThreadLocal;
 
@@ -307,7 +309,7 @@ pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>>
 ) -> InterpResult<'tcx, ()> {
     if ecx.tcx.try_get_global_alloc(alloc_id).is_some() {
         // The constant is already in global memory. Do nothing.
-        return Ok(());
+        return interp_ok(());
     }
     // Move allocation to `tcx`.
     if let Some(_) =
@@ -318,7 +320,7 @@ pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>>
         // proper recursive interning loop -- or just call `intern_const_alloc_recursive`.
         panic!("`intern_const_alloc_for_constprop` called on allocation with nested provenance")
     }
-    Ok(())
+    interp_ok(())
 }
 
 impl<'tcx, M: super::intern::CompileTimeMachine<'tcx, !>> InterpCx<'tcx, M> {
@@ -342,6 +344,6 @@ impl<'tcx, M: super::intern::CompileTimeMachine<'tcx, !>> InterpCx<'tcx, M> {
                 panic!("`intern_with_temp_alloc` with nested allocations");
             }
         }
-        Ok(alloc_id)
+        interp_ok(alloc_id)
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index e1fd8bea1f3..52780cc6a3a 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -18,7 +18,7 @@ use super::util::ensure_monomorphic_enough;
 use super::{
     Allocation, CheckInAllocMsg, ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult,
     MPlaceTy, Machine, OpTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval,
-    err_ub_custom, err_unsup_format, throw_inval, throw_ub_custom, throw_ub_format,
+    err_ub_custom, err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format,
 };
 use crate::fluent_generated as fluent;
 
@@ -39,7 +39,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
 ) -> InterpResult<'tcx, ConstValue<'tcx>> {
     let tp_ty = args.type_at(0);
     let name = tcx.item_name(def_id);
-    Ok(match name {
+    interp_ok(match name {
         sym::type_name => {
             ensure_monomorphic_enough(tcx, tp_ty)?;
             let alloc = alloc_type_name(tcx, tp_ty);
@@ -329,6 +329,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                         fluent::const_eval_offset_from_different_allocations,
                         name = intrinsic_name,
                     )
+                    .into()
                 })?;
 
                 // Perform division by size to compute return value.
@@ -378,7 +379,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
                     M::panic_nounwind(self, &msg)?;
                     // Skip the `return_to_block` at the end (we panicked, we do not return).
-                    return Ok(true);
+                    return interp_ok(true);
                 }
             }
             sym::simd_insert => {
@@ -396,11 +397,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
                 for i in 0..dest_len {
                     let place = self.project_index(&dest, i)?;
-                    let value = if i == index {
-                        elem.clone()
-                    } else {
-                        self.project_index(&input, i)?.into()
-                    };
+                    let value =
+                        if i == index { elem.clone() } else { self.project_index(&input, i)? };
                     self.copy_op(&value, &place)?;
                 }
             }
@@ -441,12 +439,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
 
             // Unsupported intrinsic: skip the return_to_block below.
-            _ => return Ok(false),
+            _ => return interp_ok(false),
         }
 
         trace!("{:?}", self.dump_place(&dest.clone().into()));
         self.return_to_block(ret)?;
-        Ok(true)
+        interp_ok(true)
     }
 
     pub(super) fn eval_nondiverging_intrinsic(
@@ -460,7 +458,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 if !cond {
                     throw_ub_custom!(fluent::const_eval_assume_false);
                 }
-                Ok(())
+                interp_ok(())
             }
             NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
                 count,
@@ -502,7 +500,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
             _ => bug!("not a numeric intrinsic: {}", name),
         };
-        Ok(Scalar::from_uint(bits_out, ret_layout.size))
+        interp_ok(Scalar::from_uint(bits_out, ret_layout.size))
     }
 
     pub fn exact_div(
@@ -543,7 +541,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
         let (val, overflowed) =
             self.binary_op(mir_op.wrapping_to_overflowing().unwrap(), l, r)?.to_scalar_pair();
-        Ok(if overflowed.to_bool()? {
+        interp_ok(if overflowed.to_bool()? {
             let size = l.layout.size;
             if l.layout.abi.is_signed() {
                 // For signed ints the saturated value depends on the sign of the first
@@ -585,7 +583,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // The offset must be in bounds starting from `ptr`.
         self.check_ptr_access_signed(ptr, offset_bytes, CheckInAllocMsg::PointerArithmeticTest)?;
         // This also implies that there is no overflow, so we are done.
-        Ok(ptr.wrapping_signed_offset(offset_bytes, self))
+        interp_ok(ptr.wrapping_signed_offset(offset_bytes, self))
     }
 
     /// Copy `count*size_of::<T>()` many bytes from `*src` to `*dst`.
@@ -631,7 +629,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         self.copy_op(&right, &left)?;
         self.copy_op(&temp, &right)?;
         self.deallocate_ptr(temp.ptr(), None, kind)?;
-        Ok(())
+        interp_ok(())
     }
 
     pub fn write_bytes_intrinsic(
@@ -672,7 +670,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
         // `Ordering`'s discriminants are -1/0/+1, so casting does the right thing.
         let result = Ord::cmp(left_bytes, right_bytes) as i32;
-        Ok(Scalar::from_i32(result))
+        interp_ok(Scalar::from_i32(result))
     }
 
     pub(crate) fn raw_eq_intrinsic(
@@ -690,13 +688,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             this.check_ptr_align(ptr, layout.align.abi)?;
             let Some(alloc_ref) = self.get_ptr_alloc(ptr, layout.size)? else {
                 // zero-sized access
-                return Ok(&[]);
+                return interp_ok(&[]);
             };
             alloc_ref.get_bytes_strip_provenance()
         };
 
         let lhs_bytes = get_bytes(self, lhs)?;
         let rhs_bytes = get_bytes(self, rhs)?;
-        Ok(Scalar::from_bool(lhs_bytes == rhs_bytes))
+        interp_ok(Scalar::from_bool(lhs_bytes == rhs_bytes))
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index a809f74e8eb..89d49ba046e 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -20,7 +20,8 @@ use rustc_target::spec::abi::Abi as CallAbi;
 use super::{
     AllocBytes, AllocId, AllocKind, AllocRange, Allocation, CTFE_ALLOC_SALT, ConstAllocation,
     CtfeProvenance, FnArg, Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, MemoryKind,
-    Misalignment, OpTy, PlaceTy, Pointer, Provenance, RangeSet, throw_unsup, throw_unsup_format,
+    Misalignment, OpTy, PlaceTy, Pointer, Provenance, RangeSet, interp_ok, throw_unsup,
+    throw_unsup_format,
 };
 
 /// Data returned by [`Machine::after_stack_pop`], and consumed by
@@ -185,7 +186,7 @@ pub trait Machine<'tcx>: Sized {
         ecx: &InterpCx<'tcx, Self>,
         instance: ty::InstanceKind<'tcx>,
     ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
-        Ok(ecx.tcx.instance_mir(instance))
+        interp_ok(ecx.tcx.instance_mir(instance))
     }
 
     /// Entry point to all function calls.
@@ -280,7 +281,7 @@ pub trait Machine<'tcx>: Sized {
     /// Called before a basic block terminator is executed.
     #[inline]
     fn before_terminator(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
-        Ok(())
+        interp_ok(())
     }
 
     /// Determines the result of a `NullaryOp::UbChecks` invocation.
@@ -290,7 +291,7 @@ pub trait Machine<'tcx>: Sized {
     /// You can use this to detect long or endlessly running programs.
     #[inline]
     fn increment_const_eval_counter(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
-        Ok(())
+        interp_ok(())
     }
 
     /// Called before a global allocation is accessed.
@@ -304,7 +305,7 @@ pub trait Machine<'tcx>: Sized {
         _static_def_id: Option<DefId>,
         _is_write: bool,
     ) -> InterpResult<'tcx> {
-        Ok(())
+        interp_ok(())
     }
 
     /// Return the `AllocId` for the given thread-local static in the current thread.
@@ -394,7 +395,7 @@ pub trait Machine<'tcx>: Sized {
     ///
     /// This should take care of jumping to the next block (one of `targets`) when asm goto
     /// is triggered, `targets[0]` when the assembly falls through, or diverge in case of
-    /// `InlineAsmOptions::NORETURN` being set.
+    /// naked_asm! or `InlineAsmOptions::NORETURN` being set.
     fn eval_inline_asm(
         _ecx: &mut InterpCx<'tcx, Self>,
         _template: &'tcx [InlineAsmTemplatePiece],
@@ -422,7 +423,7 @@ pub trait Machine<'tcx>: Sized {
         _prov: (AllocId, Self::ProvenanceExtra),
         _range: AllocRange,
     ) -> InterpResult<'tcx> {
-        Ok(())
+        interp_ok(())
     }
 
     /// Hook for performing extra checks on any memory read access,
@@ -433,7 +434,7 @@ pub trait Machine<'tcx>: Sized {
     /// Used to prevent statics from self-initializing by reading from their own memory
     /// as it is being initialized.
     fn before_alloc_read(_ecx: &InterpCx<'tcx, Self>, _alloc_id: AllocId) -> InterpResult<'tcx> {
-        Ok(())
+        interp_ok(())
     }
 
     /// Hook for performing extra checks on a memory write access.
@@ -446,7 +447,7 @@ pub trait Machine<'tcx>: Sized {
         _prov: (AllocId, Self::ProvenanceExtra),
         _range: AllocRange,
     ) -> InterpResult<'tcx> {
-        Ok(())
+        interp_ok(())
     }
 
     /// Hook for performing extra operations on a memory deallocation.
@@ -460,7 +461,7 @@ pub trait Machine<'tcx>: Sized {
         _align: Align,
         _kind: MemoryKind<Self::MemoryKind>,
     ) -> InterpResult<'tcx> {
-        Ok(())
+        interp_ok(())
     }
 
     /// Executes a retagging operation for a single pointer.
@@ -471,7 +472,7 @@ pub trait Machine<'tcx>: Sized {
         _kind: mir::RetagKind,
         val: &ImmTy<'tcx, Self::Provenance>,
     ) -> InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> {
-        Ok(val.clone())
+        interp_ok(val.clone())
     }
 
     /// Executes a retagging operation on a compound value.
@@ -482,7 +483,7 @@ pub trait Machine<'tcx>: Sized {
         _kind: mir::RetagKind,
         _place: &PlaceTy<'tcx, Self::Provenance>,
     ) -> InterpResult<'tcx> {
-        Ok(())
+        interp_ok(())
     }
 
     /// Called on places used for in-place function argument and return value handling.
@@ -516,7 +517,7 @@ pub trait Machine<'tcx>: Sized {
 
     /// Called immediately after a stack frame got pushed and its locals got initialized.
     fn after_stack_push(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
-        Ok(())
+        interp_ok(())
     }
 
     /// Called just before the return value is copied to the caller-provided return place.
@@ -524,7 +525,7 @@ pub trait Machine<'tcx>: Sized {
         _ecx: &InterpCx<'tcx, Self>,
         _frame: &Frame<'tcx, Self::Provenance, Self::FrameExtra>,
     ) -> InterpResult<'tcx> {
-        Ok(())
+        interp_ok(())
     }
 
     /// Called immediately after a stack frame got popped, but before jumping back to the caller.
@@ -537,14 +538,14 @@ pub trait Machine<'tcx>: Sized {
     ) -> InterpResult<'tcx, ReturnAction> {
         // By default, we do not support unwinding from panics
         assert!(!unwinding);
-        Ok(ReturnAction::Normal)
+        interp_ok(ReturnAction::Normal)
     }
 
     /// Called immediately after an "immediate" local variable is read
     /// (i.e., this is called for reads that do not end up accessing addressable memory).
     #[inline(always)]
     fn after_local_read(_ecx: &InterpCx<'tcx, Self>, _local: mir::Local) -> InterpResult<'tcx> {
-        Ok(())
+        interp_ok(())
     }
 
     /// Called immediately after an "immediate" local variable is assigned a new value
@@ -556,7 +557,7 @@ pub trait Machine<'tcx>: Sized {
         _local: mir::Local,
         _storage_live: bool,
     ) -> InterpResult<'tcx> {
-        Ok(())
+        interp_ok(())
     }
 
     /// Called immediately after actual memory was allocated for a local
@@ -567,7 +568,7 @@ pub trait Machine<'tcx>: Sized {
         _local: mir::Local,
         _mplace: &MPlaceTy<'tcx, Self::Provenance>,
     ) -> InterpResult<'tcx> {
-        Ok(())
+        interp_ok(())
     }
 
     /// Evaluate the given constant. The `eval` function will do all the required evaluation,
@@ -645,7 +646,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
     ) -> InterpResult<$tcx> {
         // For now we don't do any checking here. We can't use `tcx.sess` because that can differ
         // between crates, and we need to ensure that const-eval always behaves the same.
-        Ok(())
+        interp_ok(())
     }
 
     #[inline(always)]
@@ -665,7 +666,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
     fn ub_checks(_ecx: &InterpCx<$tcx, Self>) -> InterpResult<$tcx, bool> {
         // We can't look at `tcx.sess` here as that can differ across crates, which can lead to
         // unsound differences in evaluating the same constant at different instantiation sites.
-        Ok(true)
+        interp_ok(true)
     }
 
     #[inline(always)]
@@ -675,7 +676,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
         alloc: &'b Allocation,
     ) -> InterpResult<$tcx, Cow<'b, Allocation<Self::Provenance>>> {
         // Overwrite default implementation: no need to adjust anything.
-        Ok(Cow::Borrowed(alloc))
+        interp_ok(Cow::Borrowed(alloc))
     }
 
     fn init_alloc_extra(
@@ -685,7 +686,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
         _size: Size,
         _align: Align,
     ) -> InterpResult<$tcx, Self::AllocExtra> {
-        Ok(())
+        interp_ok(())
     }
 
     fn extern_static_pointer(
@@ -693,7 +694,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
         def_id: DefId,
     ) -> InterpResult<$tcx, Pointer> {
         // Use the `AllocId` associated with the `DefId`. Any actual *access* will fail.
-        Ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id).into(), Size::ZERO))
+        interp_ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id).into(), Size::ZERO))
     }
 
     #[inline(always)]
@@ -702,7 +703,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
         ptr: Pointer<CtfeProvenance>,
         _kind: Option<MemoryKind<Self::MemoryKind>>,
     ) -> InterpResult<$tcx, Pointer<CtfeProvenance>> {
-        Ok(ptr)
+        interp_ok(ptr)
     }
 
     #[inline(always)]
@@ -713,7 +714,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
         // Allow these casts, but make the pointer not dereferenceable.
         // (I.e., they behave like transmutation.)
         // This is correct because no pointers can ever be exposed in compile-time evaluation.
-        Ok(Pointer::from_addr_invalid(addr))
+        interp_ok(Pointer::from_addr_invalid(addr))
     }
 
     #[inline(always)]
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index c3b506d848c..e6ab8ca12a8 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -23,7 +23,7 @@ use tracing::{debug, instrument, trace};
 use super::{
     AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg, CheckInAllocMsg,
     CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer,
-    PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, err_ub_custom, throw_ub,
+    PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, err_ub_custom, interp_ok, throw_ub,
     throw_ub_custom, throw_unsup, throw_unsup_format,
 };
 use crate::fluent_generated as fluent;
@@ -82,7 +82,7 @@ pub enum FnVal<'tcx, Other> {
 impl<'tcx, Other> FnVal<'tcx, Other> {
     pub fn as_instance(self) -> InterpResult<'tcx, Instance<'tcx>> {
         match self {
-            FnVal::Instance(instance) => Ok(instance),
+            FnVal::Instance(instance) => interp_ok(instance),
             FnVal::Other(_) => {
                 throw_unsup_format!("'foreign' function pointers are not supported in this context")
             }
@@ -284,7 +284,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         self.mem_copy(ptr, new_ptr.into(), old_size.min(new_size), /*nonoverlapping*/ true)?;
         self.deallocate_ptr(ptr, old_size_and_align, kind)?;
 
-        Ok(new_ptr)
+        interp_ok(new_ptr)
     }
 
     #[instrument(skip(self), level = "debug")]
@@ -330,8 +330,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     )
                 }
                 None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccessTest)),
-            }
-            .into());
+            })
+            .into();
         };
 
         if alloc.mutability.is_not() {
@@ -376,7 +376,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             bug!("Nothing can be deallocated twice");
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     /// Internal helper function to determine the allocation and offset of a pointer (if any).
@@ -395,7 +395,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             |this, alloc_id, offset, prov| {
                 let (size, align) = this
                     .get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?;
-                Ok((size, align, (alloc_id, offset, prov)))
+                interp_ok((size, align, (alloc_id, offset, prov)))
             },
         )
     }
@@ -412,9 +412,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let size = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes
         Self::check_and_deref_ptr(self, ptr, size, msg, |this, alloc_id, _, _| {
             let (size, align) = this.get_live_alloc_size_and_align(alloc_id, msg)?;
-            Ok((size, align, ()))
+            interp_ok((size, align, ()))
         })?;
-        Ok(())
+        interp_ok(())
     }
 
     /// Check whether the given pointer points to live memory for a signed amount of bytes.
@@ -428,9 +428,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ) -> InterpResult<'tcx> {
         Self::check_and_deref_ptr(self, ptr, size, msg, |this, alloc_id, _, _| {
             let (size, align) = this.get_live_alloc_size_and_align(alloc_id, msg)?;
-            Ok((size, align, ()))
+            interp_ok((size, align, ()))
         })?;
-        Ok(())
+        interp_ok(())
     }
 
     /// Low-level helper function to check if a ptr is in-bounds and potentially return a reference
@@ -455,10 +455,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ) -> InterpResult<'tcx, Option<T>> {
         // Everything is okay with size 0.
         if size == 0 {
-            return Ok(None);
+            return interp_ok(None);
         }
 
-        Ok(match this.borrow().ptr_try_get_alloc_id(ptr, size) {
+        interp_ok(match this.borrow().ptr_try_get_alloc_id(ptr, size) {
             Err(addr) => {
                 // We couldn't get a proper allocation.
                 throw_ub!(DanglingIntPointer { addr, inbounds_size: size, msg });
@@ -498,7 +498,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         if let Some(misaligned) = misaligned {
             throw_ub!(AlignmentCheckFailed(misaligned, msg))
         }
-        Ok(())
+        interp_ok(())
     }
 
     pub(super) fn is_ptr_misaligned(
@@ -634,7 +634,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // `get_global_alloc` that we can actually use directly without inserting anything anywhere.
         // So the error type is `InterpResult<'tcx, &Allocation<M::Provenance>>`.
         let a = self.memory.alloc_map.get_or(id, || {
-            let alloc = self.get_global_alloc(id, /*is_write*/ false).map_err(Err)?;
+            // We have to funnel the `InterpErrorInfo` through a `Result` to match the `get_or` API,
+            // so we use `report_err` for that.
+            let alloc = self.get_global_alloc(id, /*is_write*/ false).report_err().map_err(Err)?;
             match alloc {
                 Cow::Borrowed(alloc) => {
                     // We got a ref, cheaply return that as an "error" so that the
@@ -653,8 +655,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         });
         // Now unpack that funny error type
         match a {
-            Ok(a) => Ok(&a.1),
-            Err(a) => a,
+            Ok(a) => interp_ok(&a.1),
+            Err(a) => a.into(),
         }
     }
 
@@ -662,7 +664,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// The caller is responsible for calling the access hooks!
     pub fn get_alloc_bytes_unchecked_raw(&self, id: AllocId) -> InterpResult<'tcx, *const u8> {
         let alloc = self.get_alloc_raw(id)?;
-        Ok(alloc.get_bytes_unchecked_raw())
+        interp_ok(alloc.get_bytes_unchecked_raw())
     }
 
     /// Bounds-checked *but not align-checked* allocation access.
@@ -680,7 +682,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             CheckInAllocMsg::MemoryAccessTest,
             |this, alloc_id, offset, prov| {
                 let alloc = this.get_alloc_raw(alloc_id)?;
-                Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc)))
+                interp_ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc)))
             },
         )?;
         // We want to call the hook on *all* accesses that involve an AllocId, including zero-sized
@@ -703,20 +705,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     range,
                 )?;
             }
-            Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id }))
+            interp_ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id }))
         } else {
-            Ok(None)
+            interp_ok(None)
         }
     }
 
     /// Return the `extra` field of the given allocation.
     pub fn get_alloc_extra<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, &'a M::AllocExtra> {
-        Ok(&self.get_alloc_raw(id)?.extra)
+        interp_ok(&self.get_alloc_raw(id)?.extra)
     }
 
     /// Return the `mutability` field of the given allocation.
     pub fn get_alloc_mutability<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, Mutability> {
-        Ok(self.get_alloc_raw(id)?.mutability)
+        interp_ok(self.get_alloc_raw(id)?.mutability)
     }
 
     /// Gives raw mutable access to the `Allocation`, without bounds or alignment checks.
@@ -750,7 +752,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         if alloc.mutability.is_not() {
             throw_ub!(WriteToReadOnly(id))
         }
-        Ok((alloc, &mut self.machine))
+        interp_ok((alloc, &mut self.machine))
     }
 
     /// Gives raw, mutable access to the `Allocation` address, without bounds or alignment checks.
@@ -760,7 +762,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         id: AllocId,
     ) -> InterpResult<'tcx, *mut u8> {
         let alloc = self.get_alloc_raw_mut(id)?.0;
-        Ok(alloc.get_bytes_unchecked_raw_mut())
+        interp_ok(alloc.get_bytes_unchecked_raw_mut())
     }
 
     /// Bounds-checked *but not align-checked* allocation access.
@@ -781,7 +783,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             CheckInAllocMsg::MemoryAccessTest,
             |this, alloc_id, offset, prov| {
                 let (alloc, machine) = this.get_alloc_raw_mut(alloc_id)?;
-                Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc, machine)))
+                interp_ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc, machine)))
             },
         )?;
 
@@ -790,9 +792,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             if !validation_in_progress {
                 M::before_memory_write(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?;
             }
-            Ok(Some(AllocRefMut { alloc, range, tcx: *tcx, alloc_id }))
+            interp_ok(Some(AllocRefMut { alloc, range, tcx: *tcx, alloc_id }))
         } else {
-            Ok(None)
+            interp_ok(None)
         }
     }
 
@@ -802,7 +804,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         id: AllocId,
     ) -> InterpResult<'tcx, (&'a mut M::AllocExtra, &'a mut M)> {
         let (alloc, machine) = self.get_alloc_raw_mut(id)?;
-        Ok((&mut alloc.extra, machine))
+        interp_ok((&mut alloc.extra, machine))
     }
 
     /// Check whether an allocation is live. This is faster than calling
@@ -904,7 +906,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         if matches!(kind, AllocKind::Dead) {
             throw_ub!(PointerUseAfterFree(id, msg))
         }
-        Ok((size, align))
+        interp_ok((size, align))
     }
 
     fn get_fn_alloc(&self, id: AllocId) -> Option<FnVal<'tcx, M::ExtraFnVal>> {
@@ -928,7 +930,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset)))
         }
         self.get_fn_alloc(alloc_id)
-            .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into())
+            .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))))
+            .into()
     }
 
     /// Get the dynamic type of the given vtable pointer.
@@ -951,12 +954,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         if let Some(expected_dyn_type) = expected_trait {
             self.check_vtable_for_type(vtable_dyn_type, expected_dyn_type)?;
         }
-        Ok(ty)
+        interp_ok(ty)
     }
 
     pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> {
         self.get_alloc_raw_mut(id)?.0.mutability = Mutability::Not;
-        Ok(())
+        interp_ok(())
     }
 
     /// Create a lazy debug printer that prints the given allocation and all allocations it points
@@ -1144,10 +1147,11 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>
     pub fn write_scalar(&mut self, range: AllocRange, val: Scalar<Prov>) -> InterpResult<'tcx> {
         let range = self.range.subrange(range);
         debug!("write_scalar at {:?}{range:?}: {val:?}", self.alloc_id);
-        Ok(self
-            .alloc
+
+        self.alloc
             .write_scalar(&self.tcx, range, val)
-            .map_err(|e| e.to_interp_error(self.alloc_id))?)
+            .map_err(|e| e.to_interp_error(self.alloc_id))
+            .into()
     }
 
     /// `offset` is relative to this allocation reference, not the base of the allocation.
@@ -1158,26 +1162,27 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>
     /// Mark the given sub-range (relative to this allocation reference) as uninitialized.
     pub fn write_uninit(&mut self, range: AllocRange) -> InterpResult<'tcx> {
         let range = self.range.subrange(range);
-        Ok(self
-            .alloc
+
+        self.alloc
             .write_uninit(&self.tcx, range)
-            .map_err(|e| e.to_interp_error(self.alloc_id))?)
+            .map_err(|e| e.to_interp_error(self.alloc_id))
+            .into()
     }
 
     /// Mark the entire referenced range as uninitialized
     pub fn write_uninit_full(&mut self) -> InterpResult<'tcx> {
-        Ok(self
-            .alloc
+        self.alloc
             .write_uninit(&self.tcx, self.range)
-            .map_err(|e| e.to_interp_error(self.alloc_id))?)
+            .map_err(|e| e.to_interp_error(self.alloc_id))
+            .into()
     }
 
     /// Remove all provenance in the reference range.
     pub fn clear_provenance(&mut self) -> InterpResult<'tcx> {
-        Ok(self
-            .alloc
+        self.alloc
             .clear_provenance(&self.tcx, self.range)
-            .map_err(|e| e.to_interp_error(self.alloc_id))?)
+            .map_err(|e| e.to_interp_error(self.alloc_id))
+            .into()
     }
 }
 
@@ -1189,12 +1194,10 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Pr
         read_provenance: bool,
     ) -> InterpResult<'tcx, Scalar<Prov>> {
         let range = self.range.subrange(range);
-        let res = self
-            .alloc
+        self.alloc
             .read_scalar(&self.tcx, range, read_provenance)
-            .map_err(|e| e.to_interp_error(self.alloc_id))?;
-        debug!("read_scalar at {:?}{range:?}: {res:?}", self.alloc_id);
-        Ok(res)
+            .map_err(|e| e.to_interp_error(self.alloc_id))
+            .into()
     }
 
     /// `range` is relative to this allocation reference, not the base of the allocation.
@@ -1212,10 +1215,10 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Pr
 
     /// `range` is relative to this allocation reference, not the base of the allocation.
     pub fn get_bytes_strip_provenance<'b>(&'b self) -> InterpResult<'tcx, &'a [u8]> {
-        Ok(self
-            .alloc
+        self.alloc
             .get_bytes_strip_provenance(&self.tcx, self.range)
-            .map_err(|e| e.to_interp_error(self.alloc_id))?)
+            .map_err(|e| e.to_interp_error(self.alloc_id))
+            .into()
     }
 
     /// Returns whether the allocation has provenance anywhere in the range of the `AllocRef`.
@@ -1236,14 +1239,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ) -> InterpResult<'tcx, &[u8]> {
         let Some(alloc_ref) = self.get_ptr_alloc(ptr, size)? else {
             // zero-sized access
-            return Ok(&[]);
+            return interp_ok(&[]);
         };
         // Side-step AllocRef and directly access the underlying bytes more efficiently.
         // (We are staying inside the bounds here so all is good.)
-        Ok(alloc_ref
-            .alloc
-            .get_bytes_strip_provenance(&alloc_ref.tcx, alloc_ref.range)
-            .map_err(|e| e.to_interp_error(alloc_ref.alloc_id))?)
+        interp_ok(
+            alloc_ref
+                .alloc
+                .get_bytes_strip_provenance(&alloc_ref.tcx, alloc_ref.range)
+                .map_err(|e| e.to_interp_error(alloc_ref.alloc_id))?,
+        )
     }
 
     /// Writes the given stream of bytes into memory.
@@ -1263,7 +1268,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let Some(alloc_ref) = self.get_ptr_alloc_mut(ptr, size)? else {
             // zero-sized access
             assert_matches!(src.next(), None, "iterator said it was empty but returned an element");
-            return Ok(());
+            return interp_ok(());
         };
 
         // Side-step AllocRef and directly access the underlying bytes more efficiently.
@@ -1279,7 +1284,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             *dest = src.next().expect("iterator was shorter than it said it would be");
         }
         assert_matches!(src.next(), None, "iterator was longer than it said it would be");
-        Ok(())
+        interp_ok(())
     }
 
     pub fn mem_copy(
@@ -1316,7 +1321,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // Source alloc preparations and access hooks.
         let Some((src_alloc_id, src_offset, src_prov)) = src_parts else {
             // Zero-sized *source*, that means dest is also zero-sized and we have nothing to do.
-            return Ok(());
+            return interp_ok(());
         };
         let src_alloc = self.get_alloc_raw(src_alloc_id)?;
         let src_range = alloc_range(src_offset, size);
@@ -1332,7 +1337,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // We already did the source checks and called the hooks so we are good to return early.
         let Some((dest_alloc_id, dest_offset, dest_prov)) = dest_parts else {
             // Zero-sized *destination*.
-            return Ok(());
+            return interp_ok(());
         };
 
         // Prepare getting source provenance.
@@ -1375,7 +1380,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 .write_uninit(&tcx, dest_range)
                 .map_err(|e| e.to_interp_error(dest_alloc_id))?;
             // We can forget about the provenance, this is all not initialized anyway.
-            return Ok(());
+            return interp_ok(());
         }
 
         // SAFE: The above indexing would have panicked if there weren't at least `size` bytes
@@ -1432,7 +1437,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // copy the provenance to the destination
         dest_alloc.provenance_apply_copy(provenance);
 
-        Ok(())
+        interp_ok(())
     }
 }
 
@@ -1441,7 +1446,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// Test if this value might be null.
     /// If the machine does not support ptr-to-int casts, this is conservative.
     pub fn scalar_may_be_null(&self, scalar: Scalar<M::Provenance>) -> InterpResult<'tcx, bool> {
-        Ok(match scalar.try_to_scalar_int() {
+        interp_ok(match scalar.try_to_scalar_int() {
             Ok(int) => int.is_null(),
             Err(_) => {
                 // Can only happen during CTFE.
@@ -1508,13 +1513,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         ptr: Pointer<Option<M::Provenance>>,
         size: i64,
     ) -> InterpResult<'tcx, (AllocId, Size, M::ProvenanceExtra)> {
-        self.ptr_try_get_alloc_id(ptr, size).map_err(|offset| {
-            err_ub!(DanglingIntPointer {
-                addr: offset,
-                inbounds_size: size,
-                msg: CheckInAllocMsg::InboundsTest
+        self.ptr_try_get_alloc_id(ptr, size)
+            .map_err(|offset| {
+                err_ub!(DanglingIntPointer {
+                    addr: offset,
+                    inbounds_size: size,
+                    msg: CheckInAllocMsg::InboundsTest
+                })
             })
             .into()
-        })
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 31ee3e6519a..3b5af113e99 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -16,7 +16,7 @@ use tracing::trace;
 use super::{
     CtfeProvenance, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode,
     PlaceTy, Pointer, Projectable, Provenance, Scalar, alloc_range, err_ub, from_known_layout,
-    mir_assign_valid_types, throw_ub,
+    interp_ok, mir_assign_valid_types, throw_ub,
 };
 
 /// An `Immediate` represents a single immediate self-contained Rust value.
@@ -113,27 +113,47 @@ impl<Prov: Provenance> Immediate<Prov> {
     }
 
     /// Assert that this immediate is a valid value for the given ABI.
-    pub fn assert_matches_abi(self, abi: Abi, cx: &impl HasDataLayout) {
+    pub fn assert_matches_abi(self, abi: Abi, msg: &str, cx: &impl HasDataLayout) {
         match (self, abi) {
             (Immediate::Scalar(scalar), Abi::Scalar(s)) => {
-                assert_eq!(scalar.size(), s.size(cx));
+                assert_eq!(scalar.size(), s.size(cx), "{msg}: scalar value has wrong size");
                 if !matches!(s.primitive(), abi::Pointer(..)) {
-                    assert!(matches!(scalar, Scalar::Int(..)));
+                    // This is not a pointer, it should not carry provenance.
+                    assert!(
+                        matches!(scalar, Scalar::Int(..)),
+                        "{msg}: scalar value should be an integer, but has provenance"
+                    );
                 }
             }
             (Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => {
-                assert_eq!(a_val.size(), a.size(cx));
+                assert_eq!(
+                    a_val.size(),
+                    a.size(cx),
+                    "{msg}: first component of scalar pair has wrong size"
+                );
                 if !matches!(a.primitive(), abi::Pointer(..)) {
-                    assert!(matches!(a_val, Scalar::Int(..)));
+                    assert!(
+                        matches!(a_val, Scalar::Int(..)),
+                        "{msg}: first component of scalar pair should be an integer, but has provenance"
+                    );
                 }
-                assert_eq!(b_val.size(), b.size(cx));
+                assert_eq!(
+                    b_val.size(),
+                    b.size(cx),
+                    "{msg}: second component of scalar pair has wrong size"
+                );
                 if !matches!(b.primitive(), abi::Pointer(..)) {
-                    assert!(matches!(b_val, Scalar::Int(..)));
+                    assert!(
+                        matches!(b_val, Scalar::Int(..)),
+                        "{msg}: second component of scalar pair should be an integer, but has provenance"
+                    );
                 }
             }
-            (Immediate::Uninit, _) => {}
+            (Immediate::Uninit, _) => {
+                assert!(abi.is_sized(), "{msg}: unsized immediates are not a thing");
+            }
             _ => {
-                bug!("value {self:?} does not match ABI {abi:?})",)
+                bug!("{msg}: value {self:?} does not match ABI {abi:?})",)
             }
         }
     }
@@ -149,7 +169,7 @@ impl<Prov: Provenance> Immediate<Prov> {
             }
             Immediate::Uninit => {}
         }
-        Ok(())
+        interp_ok(())
     }
 }
 
@@ -240,6 +260,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
 
     #[inline(always)]
     pub fn from_immediate(imm: Immediate<Prov>, layout: TyAndLayout<'tcx>) -> Self {
+        // Without a `cx` we cannot call `assert_matches_abi`.
         debug_assert!(
             match (imm, layout.abi) {
                 (Immediate::Scalar(..), Abi::Scalar(..)) => true,
@@ -260,7 +281,6 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
 
     #[inline]
     pub fn from_scalar_int(s: ScalarInt, layout: TyAndLayout<'tcx>) -> Self {
-        assert_eq!(s.size(), layout.size);
         Self::from_scalar(Scalar::from(s), layout)
     }
 
@@ -307,7 +327,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
                 data_size: s.size().bytes(),
             }));
         }
-        Ok(s)
+        interp_ok(s)
     }
 
     #[inline]
@@ -333,7 +353,10 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
     /// given layout.
     // Not called `offset` to avoid confusion with the trait method.
     fn offset_(&self, offset: Size, layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout) -> Self {
-        debug_assert!(layout.is_sized(), "unsized immediates are not a thing");
+        // Verify that the input matches its type.
+        if cfg!(debug_assertions) {
+            self.assert_matches_abi(self.layout.abi, "invalid input to Immediate::offset", cx);
+        }
         // `ImmTy` have already been checked to be in-bounds, so we can just check directly if this
         // remains in-bounds. This cannot actually be violated since projections are type-checked
         // and bounds-checked.
@@ -367,32 +390,14 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
             // the field covers the entire type
             _ if layout.size == self.layout.size => {
                 assert_eq!(offset.bytes(), 0);
-                assert!(
-                    match (self.layout.abi, layout.abi) {
-                        (Abi::Scalar(l), Abi::Scalar(r)) => l.size(cx) == r.size(cx),
-                        (Abi::ScalarPair(l1, l2), Abi::ScalarPair(r1, r2)) =>
-                            l1.size(cx) == r1.size(cx) && l2.size(cx) == r2.size(cx),
-                        _ => false,
-                    },
-                    "cannot project into {} immediate with equally-sized field {}\nouter ABI: {:#?}\nfield ABI: {:#?}",
-                    self.layout.ty,
-                    layout.ty,
-                    self.layout.abi,
-                    layout.abi,
-                );
                 **self
             }
             // extract fields from types with `ScalarPair` ABI
             (Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => {
-                assert_matches!(layout.abi, Abi::Scalar(..));
                 Immediate::from(if offset.bytes() == 0 {
-                    // It is "okay" to transmute from `usize` to a pointer (GVN relies on that).
-                    // So only compare the size.
-                    assert_eq!(layout.size, a.size(cx));
                     a_val
                 } else {
                     assert_eq!(offset, a.size(cx).align_to(b.align(cx).abi));
-                    assert_eq!(layout.size, b.size(cx));
                     b_val
                 })
             }
@@ -404,6 +409,8 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
                 self.layout
             ),
         };
+        // Ensure the new layout matches the new value.
+        inner_val.assert_matches_abi(layout.abi, "invalid field type in Immediate::offset", cx);
 
         ImmTy::from_immediate(inner_val, layout)
     }
@@ -430,7 +437,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> {
         ecx: &InterpCx<'tcx, M>,
     ) -> InterpResult<'tcx, Self> {
         assert_matches!(meta, MemPlaceMeta::None); // we can't store this anywhere anyway
-        Ok(self.offset_(offset, layout, ecx))
+        interp_ok(self.offset_(offset, layout, ecx))
     }
 
     #[inline(always)]
@@ -438,7 +445,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> {
         &self,
         _ecx: &InterpCx<'tcx, M>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
-        Ok(self.clone().into())
+        interp_ok(self.clone().into())
     }
 }
 
@@ -514,11 +521,13 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> {
         ecx: &InterpCx<'tcx, M>,
     ) -> InterpResult<'tcx, Self> {
         match self.as_mplace_or_imm() {
-            Left(mplace) => Ok(mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into()),
+            Left(mplace) => {
+                interp_ok(mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into())
+            }
             Right(imm) => {
                 assert_matches!(meta, MemPlaceMeta::None); // no place to store metadata here
                 // Every part of an uninit is uninit.
-                Ok(imm.offset_(offset, layout, ecx).into())
+                interp_ok(imm.offset_(offset, layout, ecx).into())
             }
         }
     }
@@ -528,7 +537,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> {
         &self,
         _ecx: &InterpCx<'tcx, M>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
-        Ok(self.clone())
+        interp_ok(self.clone())
     }
 }
 
@@ -543,12 +552,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ) -> InterpResult<'tcx, Option<ImmTy<'tcx, M::Provenance>>> {
         if mplace.layout.is_unsized() {
             // Don't touch unsized
-            return Ok(None);
+            return interp_ok(None);
         }
 
         let Some(alloc) = self.get_place_alloc(mplace)? else {
             // zero-sized type can be left uninit
-            return Ok(Some(ImmTy::uninit(mplace.layout)));
+            return interp_ok(Some(ImmTy::uninit(mplace.layout)));
         };
 
         // It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point.
@@ -557,7 +566,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // case where some of the bytes are initialized and others are not. So, we need an extra
         // check that walks over the type of `mplace` to make sure it is truly correct to treat this
         // like a `Scalar` (or `ScalarPair`).
-        Ok(match mplace.layout.abi {
+        interp_ok(match mplace.layout.abi {
             Abi::Scalar(abi::Scalar::Initialized { value: s, .. }) => {
                 let size = s.size(self);
                 assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size");
@@ -606,7 +615,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         &self,
         src: &impl Projectable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, Either<MPlaceTy<'tcx, M::Provenance>, ImmTy<'tcx, M::Provenance>>> {
-        Ok(match src.to_op(self)?.as_mplace_or_imm() {
+        interp_ok(match src.to_op(self)?.as_mplace_or_imm() {
             Left(ref mplace) => {
                 if let Some(val) = self.read_immediate_from_mplace_raw(mplace)? {
                     Right(val)
@@ -637,7 +646,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         if matches!(*imm, Immediate::Uninit) {
             throw_ub!(InvalidUninitBytes(None));
         }
-        Ok(imm)
+        interp_ok(imm)
     }
 
     /// Read a scalar from a place
@@ -645,7 +654,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         &self,
         op: &impl Projectable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
-        Ok(self.read_immediate(op)?.to_scalar())
+        interp_ok(self.read_immediate(op)?.to_scalar())
     }
 
     // Pointer-sized reads are fairly common and need target layout access, so we wrap them in
@@ -678,7 +687,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let len = mplace.len(self)?;
         let bytes = self.read_bytes_ptr_strip_provenance(mplace.ptr(), Size::from_bytes(len))?;
         let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?;
-        Ok(str)
+        interp_ok(str)
     }
 
     /// Read from a local of the current frame.
@@ -698,7 +707,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             assert!(!layout.is_unsized());
         }
         M::after_local_read(self, local)?;
-        Ok(OpTy { op, layout })
+        interp_ok(OpTy { op, layout })
     }
 
     /// Every place can be read from, so we can turn them into an operand.
@@ -709,12 +718,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         place: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         match place.as_mplace_or_local() {
-            Left(mplace) => Ok(mplace.into()),
+            Left(mplace) => interp_ok(mplace.into()),
             Right((local, offset, locals_addr, _)) => {
                 debug_assert!(place.layout.is_sized()); // only sized locals can ever be `Place::Local`.
                 debug_assert_eq!(locals_addr, self.frame().locals_addr());
                 let base = self.local_to_op(local, None)?;
-                Ok(match offset {
+                interp_ok(match offset {
                     Some(offset) => base.offset(offset, place.layout, self)?,
                     None => {
                         // In the common case this hasn't been projected.
@@ -764,7 +773,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 )
             }
         }
-        Ok(op)
+        interp_ok(op)
     }
 
     /// Evaluate the operand, returning a place where you can then find the data.
@@ -794,7 +803,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
         };
         trace!("{:?}: {:?}", mir_op, op);
-        Ok(op)
+        interp_ok(op)
     }
 
     pub(crate) fn const_val_to_op(
@@ -805,12 +814,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         // Other cases need layout.
         let adjust_scalar = |scalar| -> InterpResult<'tcx, _> {
-            Ok(match scalar {
+            interp_ok(match scalar {
                 Scalar::Ptr(ptr, size) => Scalar::Ptr(self.global_root_pointer(ptr)?, size),
                 Scalar::Int(int) => Scalar::Int(int),
             })
         };
-        let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?;
+        let layout =
+            from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty).into())?;
         let imm = match val_val {
             mir::ConstValue::Indirect { alloc_id, offset } => {
                 // This is const data, no mutation allowed.
@@ -818,7 +828,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     CtfeProvenance::from(alloc_id).as_immutable(),
                     offset,
                 ))?;
-                return Ok(self.ptr_to_mplace(ptr.into(), layout).into());
+                return interp_ok(self.ptr_to_mplace(ptr.into(), layout).into());
             }
             mir::ConstValue::Scalar(x) => adjust_scalar(x)?.into(),
             mir::ConstValue::ZeroSized => Immediate::Uninit,
@@ -829,7 +839,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 Immediate::new_slice(self.global_root_pointer(ptr)?.into(), meta, self)
             }
         };
-        Ok(OpTy { op: Operand::Immediate(imm), layout })
+        interp_ok(OpTy { op: Operand::Immediate(imm), layout })
     }
 }
 
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index 863b330a74c..52cd9b898bb 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -9,7 +9,7 @@ use rustc_span::symbol::sym;
 use rustc_target::abi::Size;
 use tracing::trace;
 
-use super::{ImmTy, InterpCx, Machine, MemPlaceMeta, throw_ub};
+use super::{ImmTy, InterpCx, Machine, MemPlaceMeta, interp_ok, throw_ub};
 
 impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     fn three_way_compare<T: Ord>(&self, lhs: T, rhs: T) -> ImmTy<'tcx, M::Provenance> {
@@ -156,7 +156,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 });
             }
 
-            return Ok(ImmTy::from_scalar_int(result, left.layout));
+            return interp_ok(ImmTy::from_scalar_int(result, left.layout));
         }
 
         // For the remaining ops, the types must be the same on both sides
@@ -181,10 +181,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 _ => None,
             };
             if let Some(op) = op {
-                return Ok(ImmTy::from_bool(op(&l_signed(), &r_signed()), *self.tcx));
+                return interp_ok(ImmTy::from_bool(op(&l_signed(), &r_signed()), *self.tcx));
             }
             if bin_op == Cmp {
-                return Ok(self.three_way_compare(l_signed(), r_signed()));
+                return interp_ok(self.three_way_compare(l_signed(), r_signed()));
             }
             let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
                 Div if r.is_null() => throw_ub!(DivisionByZero),
@@ -221,7 +221,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     throw_ub!(ArithOverflow { intrinsic });
                 }
                 let res = ImmTy::from_scalar_int(result, left.layout);
-                return Ok(if with_overflow {
+                return interp_ok(if with_overflow {
                     let overflow = ImmTy::from_bool(overflow, *self.tcx);
                     ImmTy::from_pair(res, overflow, *self.tcx)
                 } else {
@@ -234,10 +234,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let r = r_unsigned();
 
         if bin_op == Cmp {
-            return Ok(self.three_way_compare(l, r));
+            return interp_ok(self.three_way_compare(l, r));
         }
 
-        Ok(match bin_op {
+        interp_ok(match bin_op {
             Eq => ImmTy::from_bool(l == r, *self.tcx),
             Ne => ImmTy::from_bool(l != r, *self.tcx),
 
@@ -339,7 +339,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     throw_ub!(PointerArithOverflow)
                 }
                 let offset_ptr = self.ptr_offset_inbounds(ptr, offset_bytes)?;
-                Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, self), left.layout))
+                interp_ok(ImmTy::from_scalar(
+                    Scalar::from_maybe_pointer(offset_ptr, self),
+                    left.layout,
+                ))
             }
 
             // Fall back to machine hook so Miri can support more pointer ops.
@@ -366,20 +369,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 assert_eq!(left.layout.ty, right.layout.ty);
                 let left = left.to_scalar();
                 let right = right.to_scalar();
-                Ok(self.binary_char_op(bin_op, left.to_char()?, right.to_char()?))
+                interp_ok(self.binary_char_op(bin_op, left.to_char()?, right.to_char()?))
             }
             ty::Bool => {
                 assert_eq!(left.layout.ty, right.layout.ty);
                 let left = left.to_scalar();
                 let right = right.to_scalar();
-                Ok(self.binary_bool_op(bin_op, left.to_bool()?, right.to_bool()?))
+                interp_ok(self.binary_bool_op(bin_op, left.to_bool()?, right.to_bool()?))
             }
             ty::Float(fty) => {
                 assert_eq!(left.layout.ty, right.layout.ty);
                 let layout = left.layout;
                 let left = left.to_scalar();
                 let right = right.to_scalar();
-                Ok(match fty {
+                interp_ok(match fty {
                     FloatTy::F16 => {
                         self.binary_float_op(bin_op, layout, left.to_f16()?, right.to_f16()?)
                     }
@@ -447,7 +450,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     Not => !val,
                     _ => span_bug!(self.cur_span(), "Invalid bool op {:?}", un_op),
                 };
-                Ok(ImmTy::from_bool(res, *self.tcx))
+                interp_ok(ImmTy::from_bool(res, *self.tcx))
             }
             ty::Float(fty) => {
                 let val = val.to_scalar();
@@ -462,7 +465,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     FloatTy::F64 => Scalar::from_f64(-val.to_f64()?),
                     FloatTy::F128 => Scalar::from_f128(-val.to_f128()?),
                 };
-                Ok(ImmTy::from_scalar(res, layout))
+                interp_ok(ImmTy::from_scalar(res, layout))
             }
             ty::Int(..) => {
                 let val = val.to_scalar().to_int(layout.size)?;
@@ -472,7 +475,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     _ => span_bug!(self.cur_span(), "Invalid integer op {:?}", un_op),
                 };
                 let res = ScalarInt::truncate_from_int(res, layout.size).0;
-                Ok(ImmTy::from_scalar(res.into(), layout))
+                interp_ok(ImmTy::from_scalar(res.into(), layout))
             }
             ty::Uint(..) => {
                 let val = val.to_scalar().to_uint(layout.size)?;
@@ -481,12 +484,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     _ => span_bug!(self.cur_span(), "Invalid unsigned integer op {:?}", un_op),
                 };
                 let res = ScalarInt::truncate_from_uint(res, layout.size).0;
-                Ok(ImmTy::from_scalar(res.into(), layout))
+                interp_ok(ImmTy::from_scalar(res.into(), layout))
             }
             ty::RawPtr(..) | ty::Ref(..) => {
                 assert_eq!(un_op, PtrMetadata);
                 let (_, meta) = val.to_scalar_and_meta();
-                Ok(match meta {
+                interp_ok(match meta {
                     MemPlaceMeta::Meta(scalar) => {
                         let ty = un_op.ty(*self.tcx, val.layout.ty);
                         let layout = self.layout_of(ty)?;
@@ -514,7 +517,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let layout = self.layout_of(arg_ty)?;
         let usize_layout = || self.layout_of(self.tcx.types.usize).unwrap();
 
-        Ok(match null_op {
+        interp_ok(match null_op {
             SizeOf => {
                 if !layout.abi.is_sized() {
                     span_bug!(self.cur_span(), "unsized type for `NullaryOp::SizeOf`");
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 32f90254a94..81b926a1b65 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -15,7 +15,7 @@ use tracing::{instrument, trace};
 use super::{
     AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, ImmTy, Immediate, InterpCx, InterpResult,
     Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, Projectable, Provenance,
-    Scalar, alloc_range, mir_assign_valid_types,
+    Scalar, alloc_range, interp_ok, mir_assign_valid_types,
 };
 
 #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
@@ -90,7 +90,7 @@ impl<Prov: Provenance> MemPlace<Prov> {
             }
             OffsetMode::Wrapping => self.ptr.wrapping_offset(offset, ecx),
         };
-        Ok(MemPlace { ptr, meta, misaligned: self.misaligned })
+        interp_ok(MemPlace { ptr, meta, misaligned: self.misaligned })
     }
 }
 
@@ -163,7 +163,10 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> {
         layout: TyAndLayout<'tcx>,
         ecx: &InterpCx<'tcx, M>,
     ) -> InterpResult<'tcx, Self> {
-        Ok(MPlaceTy { mplace: self.mplace.offset_with_meta_(offset, mode, meta, ecx)?, layout })
+        interp_ok(MPlaceTy {
+            mplace: self.mplace.offset_with_meta_(offset, mode, meta, ecx)?,
+            layout,
+        })
     }
 
     #[inline(always)]
@@ -171,7 +174,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> {
         &self,
         _ecx: &InterpCx<'tcx, M>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
-        Ok(self.clone().into())
+        interp_ok(self.clone().into())
     }
 }
 
@@ -279,7 +282,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for PlaceTy<'tcx, Prov> {
         layout: TyAndLayout<'tcx>,
         ecx: &InterpCx<'tcx, M>,
     ) -> InterpResult<'tcx, Self> {
-        Ok(match self.as_mplace_or_local() {
+        interp_ok(match self.as_mplace_or_local() {
             Left(mplace) => mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into(),
             Right((local, old_offset, locals_addr, _)) => {
                 debug_assert!(layout.is_sized(), "unsized locals should live in memory");
@@ -367,7 +370,7 @@ impl<'tcx, Prov: Provenance> Writeable<'tcx, Prov> for MPlaceTy<'tcx, Prov> {
         &self,
         _ecx: &mut InterpCx<'tcx, M>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>> {
-        Ok(self.clone())
+        interp_ok(self.clone())
     }
 }
 
@@ -425,7 +428,7 @@ where
         // `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced;
         // we hence can't call `size_and_align_of` since that asserts more validity than we want.
         let ptr = ptr.to_pointer(self)?;
-        Ok(self.ptr_with_meta_to_mplace(ptr, meta, layout, /*unaligned*/ false))
+        interp_ok(self.ptr_with_meta_to_mplace(ptr, meta, layout, /*unaligned*/ false))
     }
 
     /// Turn a mplace into a (thin or wide) mutable raw pointer, pointing to the same space.
@@ -437,7 +440,7 @@ where
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
         let imm = mplace.mplace.to_ref(self);
         let layout = self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, mplace.layout.ty))?;
-        Ok(ImmTy::from_immediate(imm, layout))
+        interp_ok(ImmTy::from_immediate(imm, layout))
     }
 
     /// Take an operand, representing a pointer, and dereference it to a place.
@@ -458,7 +461,7 @@ where
         trace!("deref to {} on {:?}", val.layout.ty, *val);
 
         let mplace = self.ref_to_mplace(&val)?;
-        Ok(mplace)
+        interp_ok(mplace)
     }
 
     #[inline]
@@ -474,7 +477,7 @@ where
         // If an access is both OOB and misaligned, we want to see the bounds error.
         let a = self.get_ptr_alloc(mplace.ptr(), size)?;
         self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn)?;
-        Ok(a)
+        interp_ok(a)
     }
 
     #[inline]
@@ -489,10 +492,10 @@ where
         // We check alignment separately, and raise that error *after* checking everything else.
         // If an access is both OOB and misaligned, we want to see the bounds error.
         // However we have to call `check_misalign` first to make the borrow checker happy.
-        let misalign_err = self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn);
-        let a = self.get_ptr_alloc_mut(mplace.ptr(), size)?;
-        misalign_err?;
-        Ok(a)
+        let misalign_res = self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn);
+        // An error from get_ptr_alloc_mut takes precedence.
+        let (a, ()) = self.get_ptr_alloc_mut(mplace.ptr(), size).and(misalign_res)?;
+        interp_ok(a)
     }
 
     /// Turn a local in the current frame into a place.
@@ -512,7 +515,7 @@ where
                 Operand::Indirect(mplace) => Place::Ptr(*mplace),
             }
         };
-        Ok(PlaceTy { place, layout })
+        interp_ok(PlaceTy { place, layout })
     }
 
     /// Computes a place. You should only use this if you intend to write into this
@@ -549,7 +552,7 @@ where
                 )
             }
         }
-        Ok(place)
+        interp_ok(place)
     }
 
     /// Given a place, returns either the underlying mplace or a reference to where the value of
@@ -565,7 +568,7 @@ where
             (&mut Immediate<M::Provenance>, TyAndLayout<'tcx>, mir::Local),
         >,
     > {
-        Ok(match place.to_place().as_mplace_or_local() {
+        interp_ok(match place.to_place().as_mplace_or_local() {
             Left(mplace) => Left(mplace),
             Right((local, offset, locals_addr, layout)) => {
                 if offset.is_some() {
@@ -610,7 +613,7 @@ where
             )?;
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     /// Write a scalar to a place
@@ -652,15 +655,21 @@ where
                     M::after_local_write(self, local, /*storage_live*/ false)?;
                 }
                 // Double-check that the value we are storing and the local fit to each other.
+                // Things can ge wrong in quite weird ways when this is violated.
+                // Unfortunately this is too expensive to do in release builds.
                 if cfg!(debug_assertions) {
-                    src.assert_matches_abi(local_layout.abi, self);
+                    src.assert_matches_abi(
+                        local_layout.abi,
+                        "invalid immediate for given destination place",
+                        self,
+                    );
                 }
             }
             Left(mplace) => {
                 self.write_immediate_to_mplace_no_validate(src, mplace.layout, mplace.mplace)?;
             }
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Write an immediate to memory.
@@ -672,9 +681,9 @@ where
         layout: TyAndLayout<'tcx>,
         dest: MemPlace<M::Provenance>,
     ) -> InterpResult<'tcx> {
-        if cfg!(debug_assertions) {
-            value.assert_matches_abi(layout.abi, self);
-        }
+        // We use the sizes from `value` below.
+        // Ensure that matches the type of the place it is written to.
+        value.assert_matches_abi(layout.abi, "invalid immediate for given destination place", self);
         // Note that it is really important that the type here is the right one, and matches the
         // type things are read at. In case `value` is a `ScalarPair`, we don't do any magic here
         // to handle padding properly, which is only correct if we never look at this data with the
@@ -683,7 +692,7 @@ where
         let tcx = *self.tcx;
         let Some(mut alloc) = self.get_place_alloc_mut(&MPlaceTy { mplace: dest, layout })? else {
             // zero-sized access
-            return Ok(());
+            return interp_ok(());
         };
 
         match value {
@@ -708,7 +717,7 @@ where
                 alloc.write_scalar(alloc_range(Size::ZERO, a_val.size()), a_val)?;
                 alloc.write_scalar(alloc_range(b_offset, b_val.size()), b_val)?;
                 // We don't have to reset padding here, `write_immediate` will anyway do a validation run.
-                Ok(())
+                interp_ok(())
             }
             Immediate::Uninit => alloc.write_uninit_full(),
         }
@@ -729,12 +738,12 @@ where
             Left(mplace) => {
                 let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else {
                     // Zero-sized access
-                    return Ok(());
+                    return interp_ok(());
                 };
                 alloc.write_uninit_full()?;
             }
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Remove all provenance in the given place.
@@ -753,12 +762,12 @@ where
             Left(mplace) => {
                 let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else {
                     // Zero-sized access
-                    return Ok(());
+                    return interp_ok(());
                 };
                 alloc.clear_provenance()?;
             }
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Copies the data from an operand to a place.
@@ -841,7 +850,7 @@ where
             )?;
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     /// Copies the data from an operand to a place.
@@ -918,7 +927,7 @@ where
         self.mem_copy(src.ptr(), dest.ptr(), dest_size, /*nonoverlapping*/ true)?;
         self.check_misalign(src.mplace.misaligned, CheckAlignMsg::BasedOn)?;
         self.check_misalign(dest.mplace.misaligned, CheckAlignMsg::BasedOn)?;
-        Ok(())
+        interp_ok(())
     }
 
     /// Ensures that a place is in memory, and returns where it is.
@@ -980,7 +989,7 @@ where
             Place::Ptr(mplace) => mplace,
         };
         // Return with the original layout and align, so that the caller can go on
-        Ok(MPlaceTy { mplace, layout: place.layout })
+        interp_ok(MPlaceTy { mplace, layout: place.layout })
     }
 
     pub fn allocate_dyn(
@@ -993,7 +1002,7 @@ where
             span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known")
         };
         let ptr = self.allocate_ptr(size, align, kind)?;
-        Ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout, /*unaligned*/ false))
+        interp_ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout, /*unaligned*/ false))
     }
 
     pub fn allocate(
@@ -1028,7 +1037,7 @@ where
         };
         let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self);
         let layout = self.layout_of(self.tcx.types.str_).unwrap();
-        Ok(self.ptr_with_meta_to_mplace(
+        interp_ok(self.ptr_with_meta_to_mplace(
             ptr.into(),
             MemPlaceMeta::Meta(meta),
             layout,
@@ -1044,7 +1053,7 @@ where
         let _ = self.tcx.global_alloc(raw.alloc_id);
         let ptr = self.global_root_pointer(Pointer::from(raw.alloc_id))?;
         let layout = self.layout_of(raw.ty)?;
-        Ok(self.ptr_to_mplace(ptr.into(), layout))
+        interp_ok(self.ptr_to_mplace(ptr.into(), layout))
     }
 }
 
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index 621afdb1050..e636090a324 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -18,7 +18,7 @@ use tracing::{debug, instrument};
 
 use super::{
     InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar, err_ub,
-    throw_ub, throw_unsup,
+    interp_ok, throw_ub, throw_unsup,
 };
 
 /// Describes the constraints placed on offset-projections.
@@ -54,7 +54,7 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug {
             // Go through the layout. There are lots of types that support a length,
             // e.g., SIMD types. (But not all repr(simd) types even have FieldsShape::Array!)
             match layout.fields {
-                abi::FieldsShape::Array { count, .. } => Ok(count),
+                abi::FieldsShape::Array { count, .. } => interp_ok(count),
                 _ => bug!("len not supported on sized type {:?}", layout.ty),
             }
         }
@@ -82,6 +82,10 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug {
         self.offset_with_meta(offset, OffsetMode::Inbounds, MemPlaceMeta::None, layout, ecx)
     }
 
+    /// This does an offset-by-zero, which is effectively a transmute. Note however that
+    /// not all transmutes are supported by all projectables -- specifically, if this is an
+    /// `OpTy` or `ImmTy`, the new layout must have almost the same ABI as the old one
+    /// (only changing the `valid_range` is allowed and turning integers into pointers).
     fn transmute<M: Machine<'tcx, Provenance = Prov>>(
         &self,
         layout: TyAndLayout<'tcx>,
@@ -115,9 +119,9 @@ impl<'a, 'tcx, Prov: Provenance, P: Projectable<'tcx, Prov>> ArrayIterator<'a, '
         &mut self,
         ecx: &InterpCx<'tcx, M>,
     ) -> InterpResult<'tcx, Option<(u64, P)>> {
-        let Some(idx) = self.range.next() else { return Ok(None) };
+        let Some(idx) = self.range.next() else { return interp_ok(None) };
         // We use `Wrapping` here since the offset has already been checked when the iterator was created.
-        Ok(Some((
+        interp_ok(Some((
             idx,
             self.base.offset_with_meta(
                 self.stride * idx,
@@ -258,7 +262,7 @@ where
         // SIMD types must be newtypes around arrays, so all we have to do is project to their only field.
         let array = self.project_field(base, 0)?;
         let len = array.len(self)?;
-        Ok((array, len))
+        interp_ok((array, len))
     }
 
     fn project_constant_index<P: Projectable<'tcx, M::Provenance>>(
@@ -300,7 +304,13 @@ where
         debug!("project_array_fields: {base:?} {len}");
         base.offset(len * stride, self.layout_of(self.tcx.types.unit).unwrap(), self)?;
         // Create the iterator.
-        Ok(ArrayIterator { base, range: 0..len, stride, field_layout, _phantom: PhantomData })
+        interp_ok(ArrayIterator {
+            base,
+            range: 0..len,
+            stride,
+            field_layout,
+            _phantom: PhantomData,
+        })
     }
 
     /// Subslicing
@@ -367,7 +377,7 @@ where
         P: Projectable<'tcx, M::Provenance> + From<MPlaceTy<'tcx, M::Provenance>> + std::fmt::Debug,
     {
         use rustc_middle::mir::ProjectionElem::*;
-        Ok(match proj_elem {
+        interp_ok(match proj_elem {
             OpaqueCast(ty) => {
                 span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck")
             }
diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs
index 15868f1b02d..3bc9f46aea0 100644
--- a/compiler/rustc_const_eval/src/interpret/stack.rs
+++ b/compiler/rustc_const_eval/src/interpret/stack.rs
@@ -17,7 +17,7 @@ use tracing::{info_span, instrument, trace};
 use super::{
     AllocId, CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace,
     MemPlaceMeta, MemoryKind, Operand, Pointer, Provenance, ReturnAction, Scalar,
-    from_known_layout, throw_ub, throw_unsup,
+    from_known_layout, interp_ok, throw_ub, throw_unsup,
 };
 use crate::errors;
 
@@ -189,7 +189,7 @@ impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> {
     pub(super) fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> {
         match &self.value {
             LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"?
-            LocalValue::Live(val) => Ok(val),
+            LocalValue::Live(val) => interp_ok(val),
         }
     }
 
@@ -199,7 +199,7 @@ impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> {
     pub(super) fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Prov>> {
         match &mut self.value {
             LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"?
-            LocalValue::Live(val) => Ok(val),
+            LocalValue::Live(val) => interp_ok(val),
         }
     }
 }
@@ -391,7 +391,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let span = info_span!("frame", "{}", instance);
         self.frame_mut().tracing_span.enter(span);
 
-        Ok(())
+        interp_ok(())
     }
 
     /// Low-level helper that pops a stack frame from the stack and returns some information about
@@ -426,7 +426,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             return_action = ReturnAction::NoCleanup;
         };
 
-        Ok(StackPopInfo { return_action, return_to_block, return_place })
+        interp_ok(StackPopInfo { return_action, return_to_block, return_place })
     }
 
     /// A private helper for [`pop_stack_frame_raw`](InterpCx::pop_stack_frame_raw).
@@ -449,7 +449,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
         }
 
-        Ok(cleanup)
+        interp_ok(cleanup)
     }
 
     /// In the current stack frame, mark all locals as live that are not arguments and don't have
@@ -464,7 +464,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 self.storage_live(local)?;
             }
         }
-        Ok(())
+        interp_ok(())
     }
 
     pub fn storage_live_dyn(
@@ -550,7 +550,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // If the local is already live, deallocate its old memory.
         let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val);
         self.deallocate_local(old)?;
-        Ok(())
+        interp_ok(())
     }
 
     /// Mark a storage as live, killing the previous content.
@@ -566,7 +566,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // If the local is already dead, this is a NOP.
         let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead);
         self.deallocate_local(old)?;
-        Ok(())
+        interp_ok(())
     }
 
     fn deallocate_local(&mut self, local: LocalValue<M::Provenance>) -> InterpResult<'tcx> {
@@ -581,7 +581,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             );
             self.deallocate_ptr(ptr, None, MemoryKind::Stack)?;
         };
-        Ok(())
+        interp_ok(())
     }
 
     #[inline(always)]
@@ -593,19 +593,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
         let state = &frame.locals[local];
         if let Some(layout) = state.layout.get() {
-            return Ok(layout);
+            return interp_ok(layout);
         }
 
         let layout = from_known_layout(self.tcx, self.param_env, layout, || {
             let local_ty = frame.body.local_decls[local].ty;
             let local_ty =
                 self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
-            self.layout_of(local_ty)
+            self.layout_of(local_ty).into()
         })?;
 
         // Layouts of locals are requested a lot, so we cache them.
         state.layout.set(Some(layout));
-        Ok(layout)
+        interp_ok(layout)
     }
 }
 
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 8e2367e0d21..aa752955675 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -14,7 +14,7 @@ use tracing::{info, instrument, trace};
 
 use super::{
     FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy,
-    Projectable, Scalar, throw_ub,
+    Projectable, Scalar, interp_ok, throw_ub,
 };
 use crate::util;
 
@@ -36,7 +36,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     #[inline(always)]
     pub fn step(&mut self) -> InterpResult<'tcx, bool> {
         if self.stack().is_empty() {
-            return Ok(false);
+            return interp_ok(false);
         }
 
         let Either::Left(loc) = self.frame().loc else {
@@ -44,7 +44,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             // Just go on unwinding.
             trace!("unwinding: skipping frame");
             self.return_from_current_stack_frame(/* unwinding */ true)?;
-            return Ok(true);
+            return interp_ok(true);
         };
         let basic_block = &self.body().basic_blocks[loc.block];
 
@@ -55,7 +55,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             assert_eq!(old_frames, self.frame_idx());
             // Advance the program counter.
             self.frame_mut().loc.as_mut().left().unwrap().statement_index += 1;
-            return Ok(true);
+            return interp_ok(true);
         }
 
         M::before_terminator(self)?;
@@ -67,7 +67,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 info!("// executing {:?}", loc.block);
             }
         }
-        Ok(true)
+        interp_ok(true)
     }
 
     /// Runs the interpretation logic for the given `mir::Statement` at the current frame and
@@ -145,7 +145,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             Nop => {}
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     /// Evaluate an assignment statement.
@@ -277,7 +277,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
         trace!("{:?}", self.dump_place(&dest));
 
-        Ok(())
+        interp_ok(())
     }
 
     /// Writes the aggregate to the destination.
@@ -313,7 +313,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let ptr_imm = Immediate::new_pointer_with_meta(data, meta, self);
                 let ptr = ImmTy::from_immediate(ptr_imm, dest.layout);
                 self.copy_op(&ptr, dest)?;
-                return Ok(());
+                return interp_ok(());
             }
             _ => (FIRST_VARIANT, dest.clone(), None),
         };
@@ -365,7 +365,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             )?;
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     /// Evaluate the arguments of a function call
@@ -373,7 +373,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         &self,
         op: &mir::Operand<'tcx>,
     ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> {
-        Ok(match op {
+        interp_ok(match op {
             mir::Operand::Copy(_) | mir::Operand::Constant(_) => {
                 // Make a regular copy.
                 let op = self.eval_operand(op, None)?;
@@ -442,7 +442,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
         };
 
-        Ok(EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location })
+        interp_ok(EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location })
     }
 
     fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
@@ -537,7 +537,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     // generic. In order to make sure that generic and non-generic code behaves
                     // roughly the same (and in keeping with Mir semantics) we do nothing here.
                     self.go_to_block(target);
-                    return Ok(());
+                    return interp_ok(());
                 }
                 trace!("TerminatorKind::drop: {:?}, type {}", place, place.layout.ty);
                 self.init_drop_in_place_call(&place, instance, target, unwind)?;
@@ -566,7 +566,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 // By definition, a Resume terminator means
                 // that we're unwinding
                 self.return_from_current_stack_frame(/* unwinding */ true)?;
-                return Ok(());
+                return interp_ok(());
             }
 
             // It is UB to ever encounter this.
@@ -584,6 +584,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
         }
 
-        Ok(())
+        interp_ok(())
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs
index 8eead6018ac..da7d6853c0e 100644
--- a/compiler/rustc_const_eval/src/interpret/traits.rs
+++ b/compiler/rustc_const_eval/src/interpret/traits.rs
@@ -5,7 +5,9 @@ use rustc_target::abi::{Align, Size};
 use tracing::trace;
 
 use super::util::ensure_monomorphic_enough;
-use super::{InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable, throw_ub};
+use super::{
+    InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable, interp_ok, throw_ub,
+};
 
 impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// Creates a dynamic vtable for the given type and vtable origin. This is used only for
@@ -31,7 +33,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let salt = M::get_global_alloc_salt(self, None);
         let vtable_symbolic_allocation = self.tcx.reserve_and_set_vtable_alloc(ty, dyn_ty, salt);
         let vtable_ptr = self.global_root_pointer(Pointer::from(vtable_symbolic_allocation))?;
-        Ok(vtable_ptr.into())
+        interp_ok(vtable_ptr.into())
     }
 
     pub fn get_vtable_size_and_align(
@@ -42,7 +44,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let ty = self.get_ptr_vtable_ty(vtable, expected_trait)?;
         let layout = self.layout_of(ty)?;
         assert!(layout.is_sized(), "there are no vtables for unsized types");
-        Ok((layout.size, layout.align.abi))
+        interp_ok((layout.size, layout.align.abi))
     }
 
     pub(super) fn vtable_entries(
@@ -102,7 +104,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
@@ -127,7 +129,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             layout,
             self,
         )?;
-        Ok(mplace)
+        interp_ok(mplace)
     }
 
     /// Turn a `dyn* Trait` type into an value with the actual dynamic type.
@@ -147,6 +149,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // `data` is already the right thing but has the wrong type. So we transmute it.
         let layout = self.layout_of(ty)?;
         let data = data.transmute(layout, self)?;
-        Ok(data)
+        interp_ok(data)
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index 2d53badf0f9..8bb5f173a56 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -9,7 +9,7 @@ use rustc_middle::ty::{
 };
 use tracing::debug;
 
-use super::{InterpCx, MPlaceTy, MemoryKind, throw_inval};
+use super::{InterpCx, MPlaceTy, MemoryKind, interp_ok, throw_inval};
 use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult};
 
 /// Checks whether a type contains generic parameters which must be instantiated.
@@ -23,7 +23,7 @@ where
 {
     debug!("ensure_monomorphic_enough: ty={:?}", ty);
     if !ty.has_param() {
-        return Ok(());
+        return interp_ok(());
     }
 
     struct FoundParam;
@@ -78,7 +78,7 @@ where
     if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) {
         throw_inval!(TooGeneric);
     } else {
-        Ok(())
+        interp_ok(())
     }
 }
 
@@ -103,5 +103,5 @@ pub(crate) fn create_static_alloc<'tcx>(
     assert_eq!(ecx.machine.static_root_ids, None);
     ecx.machine.static_root_ids = Some((alloc_id, static_def_id));
     assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none());
-    Ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout))
+    interp_ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout))
 }
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 203cceccd9d..13641ef2bd3 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -17,8 +17,8 @@ use rustc_hir as hir;
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::ValidationErrorKind::{self, *};
 use rustc_middle::mir::interpret::{
-    ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance,
-    UnsupportedOpInfo, ValidationErrorInfo, alloc_range,
+    ExpectedKind, InterpError, InterpErrorInfo, InvalidMetaKind, Misalignment, PointerKind,
+    Provenance, UnsupportedOpInfo, ValidationErrorInfo, alloc_range, interp_ok,
 };
 use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, Ty};
@@ -32,7 +32,7 @@ use super::machine::AllocMap;
 use super::{
     AllocId, AllocKind, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult,
     MPlaceTy, Machine, MemPlaceMeta, PlaceTy, Pointer, Projectable, Scalar, ValueVisitor, err_ub,
-    format_interp_error, throw_ub,
+    format_interp_error,
 };
 
 // for the validation errors
@@ -42,7 +42,7 @@ use super::InterpError::Unsupported as Unsup;
 use super::UndefinedBehaviorInfo::*;
 use super::UnsupportedOpInfo::*;
 
-macro_rules! throw_validation_failure {
+macro_rules! err_validation_failure {
     ($where:expr, $kind: expr) => {{
         let where_ = &$where;
         let path = if !where_.is_empty() {
@@ -53,10 +53,16 @@ macro_rules! throw_validation_failure {
             None
         };
 
-        throw_ub!(ValidationError(ValidationErrorInfo { path, kind: $kind }))
+        err_ub!(ValidationError(ValidationErrorInfo { path, kind: $kind }))
     }};
 }
 
+macro_rules! throw_validation_failure {
+    ($where:expr, $kind: expr) => {
+        do yeet err_validation_failure!($where, $kind)
+    };
+}
+
 /// If $e throws an error matching the pattern, throw a validation failure.
 /// Other errors are passed back to the caller, unchanged -- and if they reach the root of
 /// the visitor, we make sure only validation errors and `InvalidProgram` errors are left.
@@ -91,22 +97,22 @@ macro_rules! try_validation {
     ($e:expr, $where:expr,
     $( $( $p:pat_param )|+ => $kind: expr ),+ $(,)?
     ) => {{
-        match $e {
-            Ok(x) => x,
+        $e.map_err(|e| {
             // We catch the error and turn it into a validation failure. We are okay with
             // allocation here as this can only slow down builds that fail anyway.
-            Err(e) => match e.kind() {
+            let (kind, backtrace) = e.into_parts();
+            match kind {
                 $(
-                    $($p)|+ =>
-                       throw_validation_failure!(
+                    $($p)|+ => {
+                        err_validation_failure!(
                             $where,
                             $kind
-                        )
+                        ).into()
+                    }
                 ),+,
-                #[allow(unreachable_patterns)]
-                _ => Err::<!, _>(e)?,
+                _ => InterpErrorInfo::from_parts(kind, backtrace),
             }
-        }
+        })?
     }};
 }
 
@@ -378,7 +384,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
         // Undo changes
         self.path.truncate(path_len);
         // Done
-        Ok(r)
+        interp_ok(r)
     }
 
     fn read_immediate(
@@ -386,7 +392,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
         val: &PlaceTy<'tcx, M::Provenance>,
         expected: ExpectedKind,
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
-        Ok(try_validation!(
+        interp_ok(try_validation!(
             self.ecx.read_immediate(val),
             self.path,
             Ub(InvalidUninitBytes(None)) =>
@@ -404,7 +410,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
         val: &PlaceTy<'tcx, M::Provenance>,
         expected: ExpectedKind,
     ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
-        Ok(self.read_immediate(val, expected)?.to_scalar())
+        interp_ok(self.read_immediate(val, expected)?.to_scalar())
     }
 
     fn deref_pointer(
@@ -469,7 +475,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
             _ => bug!("Unexpected unsized type tail: {:?}", tail),
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     /// Check a reference or `Box`.
@@ -510,7 +516,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
             Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance {
                 ptr_kind,
                 // FIXME this says "null pointer" when null but we need translate
-                pointer: format!("{}", Pointer::<Option<AllocId>>::from_addr_invalid(*i))
+                pointer: format!("{}", Pointer::<Option<AllocId>>::from_addr_invalid(i))
             },
             Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds {
                 ptr_kind
@@ -632,7 +638,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                 }
                 // Potentially skip recursive check.
                 if skip_recursive_check {
-                    return Ok(());
+                    return interp_ok(());
                 }
             } else {
                 // This is not CTFE, so it's Miri with recursive checking.
@@ -641,7 +647,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                 // FIXME: should we also skip `UnsafeCell` behind shared references? Currently that is not
                 // needed since validation reads bypass Stacked Borrows and data race checks.
                 if matches!(ptr_kind, PointerKind::Box) {
-                    return Ok(());
+                    return interp_ok(());
                 }
             }
             let path = &self.path;
@@ -654,7 +660,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                 new_path
             });
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Check if this is a value of primitive type, and if yes check the validity of the value
@@ -681,7 +687,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                     self.ecx.clear_provenance(value)?;
                     self.add_data_range_place(value);
                 }
-                Ok(true)
+                interp_ok(true)
             }
             ty::Char => {
                 let scalar = self.read_scalar(value, ExpectedKind::Char)?;
@@ -696,7 +702,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                     self.ecx.clear_provenance(value)?;
                     self.add_data_range_place(value);
                 }
-                Ok(true)
+                interp_ok(true)
             }
             ty::Float(_) | ty::Int(_) | ty::Uint(_) => {
                 // NOTE: Keep this in sync with the array optimization for int/float
@@ -713,18 +719,18 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                     self.ecx.clear_provenance(value)?;
                     self.add_data_range_place(value);
                 }
-                Ok(true)
+                interp_ok(true)
             }
             ty::RawPtr(..) => {
                 let place = self.deref_pointer(value, ExpectedKind::RawPtr)?;
                 if place.layout.is_unsized() {
                     self.check_wide_ptr_meta(place.meta(), place.layout)?;
                 }
-                Ok(true)
+                interp_ok(true)
             }
             ty::Ref(_, _ty, mutbl) => {
                 self.check_safe_pointer(value, PointerKind::Ref(*mutbl))?;
-                Ok(true)
+                interp_ok(true)
             }
             ty::FnPtr(..) => {
                 let scalar = self.read_scalar(value, ExpectedKind::FnPtr)?;
@@ -753,12 +759,12 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                     }
                     self.add_data_range_place(value);
                 }
-                Ok(true)
+                interp_ok(true)
             }
             ty::Never => throw_validation_failure!(self.path, NeverVal),
             ty::Foreign(..) | ty::FnDef(..) => {
                 // Nothing to check.
-                Ok(true)
+                interp_ok(true)
             }
             // The above should be all the primitive types. The rest is compound, we
             // check them by visiting their fields/variants.
@@ -771,7 +777,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
             | ty::Closure(..)
             | ty::Pat(..)
             | ty::CoroutineClosure(..)
-            | ty::Coroutine(..) => Ok(false),
+            | ty::Coroutine(..) => interp_ok(false),
             // Some types only occur during typechecking, they have no layout.
             // We should not see them here and we could not check them anyway.
             ty::Error(_)
@@ -808,11 +814,11 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                             max_value
                         })
                     } else {
-                        return Ok(());
+                        return interp_ok(());
                     }
                 } else if scalar_layout.is_always_valid(self.ecx) {
                     // Easy. (This is reachable if `enforce_number_validity` is set.)
-                    return Ok(());
+                    return interp_ok(());
                 } else {
                     // Conservatively, we reject, because the pointer *could* have a bad
                     // value.
@@ -825,7 +831,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
         };
         // Now compare.
         if valid_range.contains(bits) {
-            Ok(())
+            interp_ok(())
         } else {
             throw_validation_failure!(self.path, OutOfRange {
                 value: format!("{bits}"),
@@ -884,7 +890,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
     }
 
     fn reset_padding(&mut self, place: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
-        let Some(data_bytes) = self.data_bytes.as_mut() else { return Ok(()) };
+        let Some(data_bytes) = self.data_bytes.as_mut() else { return interp_ok(()) };
         // Our value must be in memory, otherwise we would not have set up `data_bytes`.
         let mplace = self.ecx.force_allocation(place)?;
         // Determine starting offset and size.
@@ -896,14 +902,14 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
         // If there is no padding at all, we can skip the rest: check for
         // a single data range covering the entire value.
         if data_bytes.0 == &[(start_offset, size)] {
-            return Ok(());
+            return interp_ok(());
         }
         // Get a handle for the allocation. Do this only once, to avoid looking up the same
         // allocation over and over again. (Though to be fair, iterating the value already does
         // exactly that.)
         let Some(mut alloc) = self.ecx.get_ptr_alloc_mut(mplace.ptr(), size)? else {
             // A ZST, no padding to clear.
-            return Ok(());
+            return interp_ok(());
         };
         // Add a "finalizer" data range at the end, so that the iteration below finds all gaps
         // between ranges.
@@ -930,7 +936,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
             padding_cleared_until = offset + size;
         }
         assert!(padding_cleared_until == start_offset + size);
-        Ok(())
+        interp_ok(())
     }
 
     /// Computes the data range of this union type:
@@ -1070,7 +1076,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
         val: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, VariantIdx> {
         self.with_elem(PathElem::EnumTag, move |this| {
-            Ok(try_validation!(
+            interp_ok(try_validation!(
                 this.ecx.read_discriminant(val),
                 this.path,
                 Ub(InvalidTag(val)) => InvalidEnumTag {
@@ -1134,7 +1140,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
                 data_bytes.add_range(base_offset + offset, size);
             }
         }
-        Ok(())
+        interp_ok(())
     }
 
     #[inline]
@@ -1144,7 +1150,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
         val: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         self.check_safe_pointer(val, PointerKind::Box)?;
-        Ok(())
+        interp_ok(())
     }
 
     #[inline]
@@ -1157,7 +1163,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
         // We assume that the Scalar validity range does not restrict these values
         // any further than `try_visit_primitive` does!
         if self.try_visit_primitive(val)? {
-            return Ok(());
+            return interp_ok(());
         }
 
         // Special check preventing `UnsafeCell` in the inner part of constants
@@ -1204,7 +1210,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
                 // If the size is 0, there is nothing to check.
                 // (`size` can only be 0 if `len` is 0, and empty arrays are always valid.)
                 if size == Size::ZERO {
-                    return Ok(());
+                    return interp_ok(());
                 }
                 // Now that we definitely have a non-ZST array, we know it lives in memory -- except it may
                 // be an uninitialized local variable, those are also "immediate".
@@ -1224,36 +1230,33 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
                 // No need for an alignment check here, this is not an actual memory access.
                 let alloc = self.ecx.get_ptr_alloc(mplace.ptr(), size)?.expect("we already excluded size 0");
 
-                match alloc.get_bytes_strip_provenance() {
-                    // In the happy case, we needn't check anything else.
-                    Ok(_) => {}
+                alloc.get_bytes_strip_provenance().map_err(|err| {
                     // Some error happened, try to provide a more detailed description.
-                    Err(err) => {
-                        // For some errors we might be able to provide extra information.
-                        // (This custom logic does not fit the `try_validation!` macro.)
-                        match err.kind() {
-                            Ub(InvalidUninitBytes(Some((_alloc_id, access)))) | Unsup(ReadPointerAsInt(Some((_alloc_id, access)))) => {
-                                // Some byte was uninitialized, determine which
-                                // element that byte belongs to so we can
-                                // provide an index.
-                                let i = usize::try_from(
-                                    access.bad.start.bytes() / layout.size.bytes(),
-                                )
-                                .unwrap();
-                                self.path.push(PathElem::ArrayElem(i));
-
-                                if matches!(err.kind(), Ub(InvalidUninitBytes(_))) {
-                                    throw_validation_failure!(self.path, Uninit { expected })
-                                } else {
-                                    throw_validation_failure!(self.path, PointerAsInt { expected })
-                                }
+                    // For some errors we might be able to provide extra information.
+                    // (This custom logic does not fit the `try_validation!` macro.)
+                    let (kind, backtrace) = err.into_parts();
+                    match kind {
+                        Ub(InvalidUninitBytes(Some((_alloc_id, access)))) | Unsup(ReadPointerAsInt(Some((_alloc_id, access)))) => {
+                            // Some byte was uninitialized, determine which
+                            // element that byte belongs to so we can
+                            // provide an index.
+                            let i = usize::try_from(
+                                access.bad.start.bytes() / layout.size.bytes(),
+                            )
+                            .unwrap();
+                            self.path.push(PathElem::ArrayElem(i));
+
+                            if matches!(kind, Ub(InvalidUninitBytes(_))) {
+                                err_validation_failure!(self.path, Uninit { expected }).into()
+                            } else {
+                                err_validation_failure!(self.path, PointerAsInt { expected }).into()
                             }
-
-                            // Propagate upwards (that will also check for unexpected errors).
-                            _ => return Err(err),
                         }
+
+                        // Propagate upwards (that will also check for unexpected errors).
+                        _ => return InterpErrorInfo::from_parts(kind, backtrace),
                     }
-                }
+                })?;
 
                 // Don't forget that these are all non-pointer types, and thus do not preserve
                 // provenance.
@@ -1282,7 +1285,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
                     // It's not great to catch errors here, since we can't give a very good path,
                     // but it's better than ICEing.
                     Ub(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }) => {
-                        InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type: *expected_dyn_type }
+                        InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type }
                     },
                 );
             }
@@ -1331,7 +1334,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
             }
         }
 
-        Ok(())
+        interp_ok(())
     }
 }
 
@@ -1347,7 +1350,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         trace!("validate_operand_internal: {:?}, {:?}", *val, val.layout.ty);
 
         // Run the visitor.
-        match self.run_for_validation(|ecx| {
+        self.run_for_validation(|ecx| {
             let reset_padding = reset_provenance_and_padding && {
                 // Check if `val` is actually stored in memory. If not, padding is not even
                 // represented and we need not reset it.
@@ -1363,29 +1366,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             };
             v.visit_value(val)?;
             v.reset_padding(val)?;
-            InterpResult::Ok(())
-        }) {
-            Ok(()) => Ok(()),
-            // Pass through validation failures and "invalid program" issues.
-            Err(err)
-                if matches!(
-                    err.kind(),
-                    err_ub!(ValidationError { .. })
-                        | InterpError::InvalidProgram(_)
-                        | InterpError::Unsupported(UnsupportedOpInfo::ExternTypeField)
-                ) =>
-            {
-                Err(err)
-            }
-            // Complain about any other kind of error -- those are bad because we'd like to
-            // report them in a way that shows *where* in the value the issue lies.
-            Err(err) => {
+            interp_ok(())
+        })
+        .map_err(|err| {
+            if !matches!(
+                err.kind(),
+                err_ub!(ValidationError { .. })
+                    | InterpError::InvalidProgram(_)
+                    | InterpError::Unsupported(UnsupportedOpInfo::ExternTypeField)
+            ) {
                 bug!(
                     "Unexpected error during validation: {}",
                     format_interp_error(self.tcx.dcx(), err)
                 );
             }
-        }
+            err
+        })
     }
 
     /// This function checks the data at `op` to be const-valid.
@@ -1456,6 +1452,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 /*reset_provenance_and_padding*/ false,
             )?;
         }
-        Ok(())
+        interp_ok(())
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs
index d004a3f0892..647917dbb67 100644
--- a/compiler/rustc_const_eval/src/interpret/visitor.rs
+++ b/compiler/rustc_const_eval/src/interpret/visitor.rs
@@ -10,7 +10,7 @@ use rustc_middle::ty::{self, Ty};
 use rustc_target::abi::{FieldIdx, FieldsShape, VariantIdx, Variants};
 use tracing::trace;
 
-use super::{InterpCx, MPlaceTy, Machine, Projectable, throw_inval};
+use super::{InterpCx, MPlaceTy, Machine, Projectable, interp_ok, throw_inval};
 
 /// How to traverse a value and what to do when we are at the leaves.
 pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
@@ -46,14 +46,14 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
     /// Visits the given value as a union. No automatic recursion can happen here.
     #[inline(always)]
     fn visit_union(&mut self, _v: &Self::V, _fields: NonZero<usize>) -> InterpResult<'tcx> {
-        Ok(())
+        interp_ok(())
     }
     /// Visits the given value as the pointer of a `Box`. There is nothing to recurse into.
     /// The type of `v` will be a raw pointer to `T`, but this is a field of `Box<T>` and the
     /// pointee type is the actual `T`. `box_ty` provides the full type of the `Box` itself.
     #[inline(always)]
     fn visit_box(&mut self, _box_ty: Ty<'tcx>, _v: &Self::V) -> InterpResult<'tcx> {
-        Ok(())
+        interp_ok(())
     }
 
     /// Called each time we recurse down to a field of a "product-like" aggregate
@@ -165,7 +165,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
                 self.visit_field(v, 1, &alloc)?;
 
                 // We visited all parts of this one.
-                return Ok(());
+                return interp_ok(());
             }
 
             // Non-normalized types should never show up here.
@@ -222,6 +222,6 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
             Variants::Single { .. } => {}
         }
 
-        Ok(())
+        interp_ok(())
     }
 }
diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
index 19393188c9a..649179d5b1e 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -75,7 +75,8 @@ fn check_validity_requirement_strict<'tcx>(
             /*recursive*/ false,
             /*reset_provenance_and_padding*/ false,
         )
-        .is_ok())
+        .discard_err()
+        .is_some())
 }
 
 /// Implements the 'lax' (default) version of the [`check_validity_requirement`] checks; see that
diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs
index 7ff1339c5ab..3d6d0003483 100644
--- a/compiler/rustc_data_structures/src/stack.rs
+++ b/compiler/rustc_data_structures/src/stack.rs
@@ -5,7 +5,11 @@ const RED_ZONE: usize = 100 * 1024; // 100k
 
 // Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then
 // on. This flag has performance relevant characteristics. Don't set it too high.
+#[cfg(not(target_os = "aix"))]
 const STACK_PER_RECURSION: usize = 1024 * 1024; // 1MB
+// LLVM for AIX doesn't feature TCO, increase recursion size for workaround.
+#[cfg(target_os = "aix")]
+const STACK_PER_RECURSION: usize = 16 * 1024 * 1024; // 16MB
 
 /// Grows the stack on demand to prevent stack overflow. Call this in strategic locations
 /// to "break up" recursive calls. E.g. almost any call to `visit_expr` or equivalent can benefit
diff --git a/compiler/rustc_driver_impl/README.md b/compiler/rustc_driver_impl/README.md
index 6d7fba36fb3..9fa4242de3c 100644
--- a/compiler/rustc_driver_impl/README.md
+++ b/compiler/rustc_driver_impl/README.md
@@ -7,4 +7,4 @@ options).
 
 For more information about how the driver works, see the [rustc dev guide].
 
-[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/rustc-driver.html
+[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/rustc-driver/intro.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0607.md b/compiler/rustc_error_codes/src/error_codes/E0607.md
index 0545246929f..8ebc227114d 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0607.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0607.md
@@ -1,4 +1,4 @@
-A cast between a thin and a fat pointer was attempted.
+A cast between a thin and a wide pointer was attempted.
 
 Erroneous code example:
 
@@ -7,18 +7,18 @@ let v = core::ptr::null::<u8>();
 v as *const [u8];
 ```
 
-First: what are thin and fat pointers?
+First: what are thin and wide pointers?
 
 Thin pointers are "simple" pointers: they are purely a reference to a memory
 address.
 
-Fat pointers are pointers referencing Dynamically Sized Types (also called
+Wide pointers are pointers referencing Dynamically Sized Types (also called
 DSTs). DSTs don't have a statically known size, therefore they can only exist
 behind some kind of pointer that contains additional information. For example,
 slices and trait objects are DSTs. In the case of slices, the additional
-information the fat pointer holds is their size.
+information the wide pointer holds is their size.
 
-To fix this error, don't try to cast directly between thin and fat pointers.
+To fix this error, don't try to cast directly between thin and wide pointers.
 
 For more information about type casts, take a look at the section of the
 [The Rust Reference][1] on type cast expressions.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0787.md b/compiler/rustc_error_codes/src/error_codes/E0787.md
index cee50829270..f5c5faa066b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0787.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0787.md
@@ -11,11 +11,10 @@ pub extern "C" fn f() -> u32 {
 }
 ```
 
-The naked functions must be defined using a single inline assembly
-block.
+The naked function must be defined using a single `naked_asm!` assembly block.
 
 The execution must never fall through past the end of the assembly
-code so the block must use `noreturn` option. The asm block can also
+code, so it must either return or diverge. The asm block can also
 use `att_syntax` and `raw` options, but others options are not allowed.
 
 The asm block must not contain any operands other than `const` and
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index f468fbf4497..335432c9cfe 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -34,8 +34,8 @@ pub struct AnnotateSnippetEmitter {
 }
 
 impl Translate for AnnotateSnippetEmitter {
-    fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
-        self.fluent_bundle.as_ref()
+    fn fluent_bundle(&self) -> Option<&FluentBundle> {
+        self.fluent_bundle.as_deref()
     }
 
     fn fallback_fluent_bundle(&self) -> &FluentBundle {
@@ -69,8 +69,8 @@ impl Emitter for AnnotateSnippetEmitter {
         );
     }
 
-    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
-        self.source_map.as_ref()
+    fn source_map(&self) -> Option<&SourceMap> {
+        self.source_map.as_deref()
     }
 
     fn should_show_explain(&self) -> bool {
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 1dc52c4d0a4..1adb6b9dcfe 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -205,7 +205,7 @@ pub trait Emitter: Translate {
         false
     }
 
-    fn source_map(&self) -> Option<&Lrc<SourceMap>>;
+    fn source_map(&self) -> Option<&SourceMap>;
 
     /// Formats the substitutions of the primary_span
     ///
@@ -481,8 +481,8 @@ pub trait Emitter: Translate {
 }
 
 impl Translate for HumanEmitter {
-    fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
-        self.fluent_bundle.as_ref()
+    fn fluent_bundle(&self) -> Option<&FluentBundle> {
+        self.fluent_bundle.as_deref()
     }
 
     fn fallback_fluent_bundle(&self) -> &FluentBundle {
@@ -491,8 +491,8 @@ impl Translate for HumanEmitter {
 }
 
 impl Emitter for HumanEmitter {
-    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
-        self.sm.as_ref()
+    fn source_map(&self) -> Option<&SourceMap> {
+        self.sm.as_deref()
     }
 
     fn emit_diagnostic(&mut self, mut diag: DiagInner) {
@@ -540,7 +540,7 @@ pub struct SilentEmitter {
 }
 
 impl Translate for SilentEmitter {
-    fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
+    fn fluent_bundle(&self) -> Option<&FluentBundle> {
         None
     }
 
@@ -552,7 +552,7 @@ impl Translate for SilentEmitter {
 }
 
 impl Emitter for SilentEmitter {
-    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
+    fn source_map(&self) -> Option<&SourceMap> {
         None
     }
 
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 1972a522e39..1534e256520 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -111,8 +111,8 @@ enum EmitTyped<'a> {
 }
 
 impl Translate for JsonEmitter {
-    fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
-        self.fluent_bundle.as_ref()
+    fn fluent_bundle(&self) -> Option<&FluentBundle> {
+        self.fluent_bundle.as_deref()
     }
 
     fn fallback_fluent_bundle(&self) -> &FluentBundle {
@@ -172,7 +172,7 @@ impl Emitter for JsonEmitter {
         }
     }
 
-    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
+    fn source_map(&self) -> Option<&SourceMap> {
         Some(&self.sm)
     }
 
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 39acacfbe59..94365a89adc 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -59,7 +59,7 @@ use registry::Registry;
 use rustc_data_structures::AtomicRef;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
-use rustc_data_structures::sync::{Lock, Lrc};
+use rustc_data_structures::sync::Lock;
 pub use rustc_error_messages::{
     DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel,
     SubdiagMessage, fallback_fluent_bundle, fluent_bundle,
@@ -685,13 +685,13 @@ impl DiagCtxt {
                 unimplemented!("false emitter must only used during `wrap_emitter`")
             }
 
-            fn source_map(&self) -> Option<&Lrc<SourceMap>> {
+            fn source_map(&self) -> Option<&SourceMap> {
                 unimplemented!("false emitter must only used during `wrap_emitter`")
             }
         }
 
         impl translation::Translate for FalseEmitter {
-            fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
+            fn fluent_bundle(&self) -> Option<&FluentBundle> {
                 unimplemented!("false emitter must only used during `wrap_emitter`")
             }
 
@@ -925,18 +925,6 @@ impl<'a> DiagCtxtHandle<'a> {
         self.inner.borrow_mut().emit_stashed_diagnostics()
     }
 
-    /// This excludes lint errors, and delayed bugs.
-    #[inline]
-    pub fn err_count_excluding_lint_errs(&self) -> usize {
-        let inner = self.inner.borrow();
-        inner.err_guars.len()
-            + inner
-                .stashed_diagnostics
-                .values()
-                .filter(|(diag, guar)| guar.is_some() && diag.is_lint.is_none())
-                .count()
-    }
-
     /// This excludes delayed bugs.
     #[inline]
     pub fn err_count(&self) -> usize {
diff --git a/compiler/rustc_errors/src/tests.rs b/compiler/rustc_errors/src/tests.rs
index 17a1635bd11..70179237e5d 100644
--- a/compiler/rustc_errors/src/tests.rs
+++ b/compiler/rustc_errors/src/tests.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
+use rustc_data_structures::sync::IntoDynSyncSend;
 use rustc_error_messages::fluent_bundle::resolver::errors::{ReferenceKind, ResolverError};
 use rustc_error_messages::{DiagMessage, langid};
 
@@ -12,7 +12,7 @@ struct Dummy {
 }
 
 impl Translate for Dummy {
-    fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
+    fn fluent_bundle(&self) -> Option<&FluentBundle> {
         None
     }
 
diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs
index e0b64b276eb..156f5e5d26e 100644
--- a/compiler/rustc_errors/src/translation.rs
+++ b/compiler/rustc_errors/src/translation.rs
@@ -2,7 +2,6 @@ use std::borrow::Cow;
 use std::env;
 use std::error::Report;
 
-use rustc_data_structures::sync::Lrc;
 pub use rustc_error_messages::FluentArgs;
 use tracing::{debug, trace};
 
@@ -33,7 +32,7 @@ pub trait Translate {
     /// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no
     /// language was requested by the user then this will be `None` and `fallback_fluent_bundle`
     /// should be used.
-    fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>>;
+    fn fluent_bundle(&self) -> Option<&FluentBundle>;
 
     /// Return `FluentBundle` with localized diagnostics for the default locale of the compiler.
     /// Used when the user has not requested a specific language or when a localized diagnostic is
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 766d96e268f..57bac9d09d5 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -27,6 +27,12 @@ expand_collapse_debuginfo_illegal =
 expand_count_repetition_misplaced =
     `count` can not be placed inside the inner-most repetition
 
+expand_crate_name_in_cfg_attr =
+    `crate_name` within an `#![cfg_attr]` attribute is forbidden
+
+expand_crate_type_in_cfg_attr =
+    `crate_type` within an `#![cfg_attr]` attribute is forbidden
+
 expand_custom_attribute_panicked =
     custom attribute panicked
     .help = message: {$message}
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 32088374277..21dbc251b06 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -5,7 +5,9 @@ use rustc_ast::token::{Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::{
     AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree,
 };
-use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NodeId};
+use rustc_ast::{
+    self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NestedMetaItem, NodeId,
+};
 use rustc_attr as attr;
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_feature::{
@@ -21,8 +23,9 @@ use thin_vec::ThinVec;
 use tracing::instrument;
 
 use crate::errors::{
-    FeatureNotAllowed, FeatureRemoved, FeatureRemovedReason, InvalidCfg, MalformedFeatureAttribute,
-    MalformedFeatureAttributeHelp, RemoveExprNotSupported,
+    CrateNameInCfgAttr, CrateTypeInCfgAttr, FeatureNotAllowed, FeatureRemoved,
+    FeatureRemovedReason, InvalidCfg, MalformedFeatureAttribute, MalformedFeatureAttributeHelp,
+    RemoveExprNotSupported,
 };
 
 /// A folder that strips out items that do not belong in the current configuration.
@@ -358,20 +361,10 @@ impl<'a> StripUnconfigured<'a> {
             item_span,
         );
         if attr.has_name(sym::crate_type) {
-            self.sess.psess.buffer_lint(
-                rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
-                attr.span,
-                ast::CRATE_NODE_ID,
-                BuiltinLintDiag::CrateTypeInCfgAttr,
-            );
+            self.sess.dcx().emit_err(CrateTypeInCfgAttr { span: attr.span });
         }
         if attr.has_name(sym::crate_name) {
-            self.sess.psess.buffer_lint(
-                rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
-                attr.span,
-                ast::CRATE_NODE_ID,
-                BuiltinLintDiag::CrateNameInCfgAttr,
-            );
+            self.sess.dcx().emit_err(CrateNameInCfgAttr { span: attr.span });
         }
         attr
     }
@@ -449,7 +442,7 @@ impl<'a> StripUnconfigured<'a> {
     }
 }
 
-pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItem> {
+pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a NestedMetaItem> {
     let span = meta_item.span;
     match meta_item.meta_item_list() {
         None => {
@@ -464,7 +457,7 @@ pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a Meta
             sess.dcx().emit_err(InvalidCfg::MultiplePredicates { span: l.span() });
             None
         }
-        Some([single]) => match single.meta_item() {
+        Some([single]) => match single.meta_item_or_bool() {
             Some(meta_item) => Some(meta_item),
             None => {
                 sess.dcx().emit_err(InvalidCfg::PredicateLiteral { span: single.span() });
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 0fdccb08918..5682c574552 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -468,6 +468,20 @@ pub(crate) struct GlobDelegationOutsideImpls {
 }
 
 #[derive(Diagnostic)]
+#[diag(expand_crate_name_in_cfg_attr)]
+pub(crate) struct CrateNameInCfgAttr {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(expand_crate_type_in_cfg_attr)]
+pub(crate) struct CrateTypeInCfgAttr {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(expand_glob_delegation_traitless_qpath)]
 pub(crate) struct GlobDelegationTraitlessQpath {
     #[primary_span]
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index b1d898b6949..1498b9cbd5d 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -119,7 +119,7 @@ use rustc_span::symbol::{MacroRulesNormalizedIdent, kw};
 use rustc_span::{ErrorGuaranteed, Span};
 use smallvec::SmallVec;
 
-use super::quoted::VALID_FRAGMENT_NAMES_MSG_2021;
+use super::quoted::VALID_FRAGMENT_NAMES_MSG;
 use crate::errors;
 use crate::mbe::{KleeneToken, TokenTree};
 
@@ -274,7 +274,7 @@ fn check_binders(
                     psess.dcx().emit_err(errors::MissingFragmentSpecifier {
                         span,
                         add_span: span.shrink_to_hi(),
-                        valid: VALID_FRAGMENT_NAMES_MSG_2021,
+                        valid: VALID_FRAGMENT_NAMES_MSG,
                     });
                 } else {
                     psess.buffer_lint(
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index f0a6c841f31..2edd289625e 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -1,4 +1,3 @@
-use rustc_ast::token::NtExprKind::*;
 use rustc_ast::token::{self, Delimiter, IdentIsRaw, NonterminalKind, Token};
 use rustc_ast::{NodeId, tokenstream};
 use rustc_ast_pretty::pprust;
@@ -13,12 +12,9 @@ use crate::errors;
 use crate::mbe::macro_parser::count_metavar_decls;
 use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree};
 
-const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
-    `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, \
-    `item` and `vis`";
-pub(crate) const VALID_FRAGMENT_NAMES_MSG_2021: &str = "valid fragment specifiers are \
-    `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, `ty`, `lifetime`, `literal`, `path`, \
-    `meta`, `tt`, `item` and `vis`";
+pub(crate) const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
+    `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, \
+    `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility";
 
 /// Takes a `tokenstream::TokenStream` and returns a `Vec<self::TokenTree>`. Specifically, this
 /// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a
@@ -92,39 +88,13 @@ pub(super) fn parse(
                                     };
                                     let kind = NonterminalKind::from_symbol(fragment.name, edition)
                                         .unwrap_or_else(|| {
-                                            let help = match fragment.name {
-                                                sym::expr_2021 => {
-                                                    format!(
-                                                        "fragment specifier `expr_2021` \
-                                                         requires Rust 2021 or later\n\
-                                                         {VALID_FRAGMENT_NAMES_MSG}"
-                                                    )
-                                                }
-                                                _ if edition().at_least_rust_2021()
-                                                    && features.expr_fragment_specifier_2024 =>
-                                                {
-                                                    VALID_FRAGMENT_NAMES_MSG_2021.into()
-                                                }
-                                                _ => VALID_FRAGMENT_NAMES_MSG.into(),
-                                            };
                                             sess.dcx().emit_err(errors::InvalidFragmentSpecifier {
                                                 span,
                                                 fragment,
-                                                help,
+                                                help: VALID_FRAGMENT_NAMES_MSG.into(),
                                             });
                                             NonterminalKind::Ident
                                         });
-                                    if kind == NonterminalKind::Expr(Expr2021 { inferred: false })
-                                        && !features.expr_fragment_specifier_2024
-                                    {
-                                        rustc_session::parse::feature_err(
-                                            sess,
-                                            sym::expr_fragment_specifier_2024,
-                                            span,
-                                            "fragment specifier `expr_2021` is unstable",
-                                        )
-                                        .emit();
-                                    }
                                     result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
                                     continue;
                                 }
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index a7b251ab252..0dc35618ff8 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -627,8 +627,7 @@ impl server::TokenStream for Rustc<'_, '_> {
         base: Option<Self::TokenStream>,
         trees: Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>>,
     ) -> Self::TokenStream {
-        let mut stream =
-            if let Some(base) = base { base } else { tokenstream::TokenStream::default() };
+        let mut stream = base.unwrap_or_default();
         for tree in trees {
             for tt in (tree, &mut *self).to_internal() {
                 stream.push_tree(tt);
@@ -642,8 +641,7 @@ impl server::TokenStream for Rustc<'_, '_> {
         base: Option<Self::TokenStream>,
         streams: Vec<Self::TokenStream>,
     ) -> Self::TokenStream {
-        let mut stream =
-            if let Some(base) = base { base } else { tokenstream::TokenStream::default() };
+        let mut stream = base.unwrap_or_default();
         for s in streams {
             stream.push_stream(s);
         }
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 5ff002dd7d2..a850eb95620 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -189,6 +189,8 @@ declare_features! (
     (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907)),
     /// Allows explicit generic arguments specification with `impl Trait` present.
     (accepted, explicit_generic_args_with_impl_trait, "1.63.0", Some(83701)),
+    /// Uses 2024 rules for matching `expr` fragments in macros. Also enables `expr_2021` fragment.
+    (accepted, expr_fragment_specifier_2024, "CURRENT_RUSTC_VERSION", Some(123742)),
     /// Allows arbitrary expressions in key-value attributes at parse time.
     (accepted, extended_key_value_attributes, "1.54.0", Some(78835)),
     /// Allows resolving absolute paths as paths from other crates.
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 1ffd35dbf91..380e36fe405 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -371,6 +371,8 @@ declare_features! (
     (unstable, async_for_loop, "1.77.0", Some(118898)),
     /// Allows using C-variadics.
     (unstable, c_variadic, "1.34.0", Some(44930)),
+    /// Allows the use of `#[cfg(<true/false>)]`.
+    (unstable, cfg_boolean_literals, "CURRENT_RUSTC_VERSION", Some(131204)),
     /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
     (unstable, cfg_overflow_checks, "1.71.0", Some(111466)),
     /// Provides the relocation model information as cfg entry
@@ -450,8 +452,6 @@ declare_features! (
     (unstable, exhaustive_patterns, "1.13.0", Some(51085)),
     /// Allows explicit tail calls via `become` expression.
     (incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
-    /// Uses 2024 rules for matching `expr` fragments in macros. Also enables `expr_2021` fragment.
-    (incomplete, expr_fragment_specifier_2024, "1.80.0", Some(123742)),
     /// Allows using `efiapi`, `sysv64` and `win64` as calling convention
     /// for functions with varargs.
     (unstable, extended_varargs_abi_support, "1.65.0", Some(100189)),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 71216023ecc..2ef6fa53f4e 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2632,7 +2632,7 @@ impl<'hir> Ty<'hir> {
             }
             TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty),
             TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(),
-            TyKind::OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args),
+            TyKind::OpaqueDef(_, generic_args) => are_suggestable_generic_args(generic_args),
             TyKind::Path(QPath::TypeRelative(ty, segment)) => {
                 ty.is_suggestable_infer_ty() || are_suggestable_generic_args(segment.args().args)
             }
@@ -2749,6 +2749,8 @@ pub struct BareFnTy<'hir> {
 
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub struct OpaqueTy<'hir> {
+    pub hir_id: HirId,
+    pub def_id: LocalDefId,
     pub generics: &'hir Generics<'hir>,
     pub bounds: GenericBounds<'hir>,
     pub origin: OpaqueTyOrigin,
@@ -2762,10 +2764,7 @@ pub struct OpaqueTy<'hir> {
     /// This mapping associated a captured lifetime (first parameter) with the new
     /// early-bound lifetime that was generated for the opaque.
     pub lifetime_mapping: &'hir [(&'hir Lifetime, LocalDefId)],
-    /// Whether the opaque is a return-position impl trait (or async future)
-    /// originating from a trait method. This makes it so that the opaque is
-    /// lowered as an associated type.
-    pub in_trait: bool,
+    pub span: Span,
 }
 
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
@@ -2802,13 +2801,29 @@ pub struct PreciseCapturingNonLifetimeArg {
     pub res: Res,
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)]
+pub enum RpitContext {
+    Trait,
+    TraitImpl,
+}
+
 /// From whence the opaque type came.
 #[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)]
 pub enum OpaqueTyOrigin {
     /// `-> impl Trait`
-    FnReturn(LocalDefId),
+    FnReturn {
+        /// The defining function.
+        parent: LocalDefId,
+        // Whether this is an RPITIT (return position impl trait in trait)
+        in_trait_or_impl: Option<RpitContext>,
+    },
     /// `async fn`
-    AsyncFn(LocalDefId),
+    AsyncFn {
+        /// The defining function.
+        parent: LocalDefId,
+        // Whether this is an AFIT (async fn in trait)
+        in_trait_or_impl: Option<RpitContext>,
+    },
     /// type aliases: `type Foo = impl Trait;`
     TyAlias {
         /// The type alias or associated type parent of the TAIT/ATPIT
@@ -2856,7 +2871,7 @@ pub enum TyKind<'hir> {
     /// possibly parameters) that are actually bound on the `impl Trait`.
     ///
     /// The last parameter specifies whether this opaque appears in a trait definition.
-    OpaqueDef(ItemId, &'hir [GenericArg<'hir>], bool),
+    OpaqueDef(&'hir OpaqueTy<'hir>, &'hir [GenericArg<'hir>]),
     /// A trait object type `Bound1 + Bound2 + Bound3`
     /// where `Bound` is a trait or a lifetime.
     TraitObject(
@@ -3325,8 +3340,6 @@ impl<'hir> Item<'hir> {
         expect_ty_alias, (&'hir Ty<'hir>, &'hir Generics<'hir>),
             ItemKind::TyAlias(ty, generics), (ty, generics);
 
-        expect_opaque_ty, &OpaqueTy<'hir>, ItemKind::OpaqueTy(ty), ty;
-
         expect_enum, (&EnumDef<'hir>, &'hir Generics<'hir>), ItemKind::Enum(def, generics), (def, generics);
 
         expect_struct, (&VariantData<'hir>, &'hir Generics<'hir>),
@@ -3439,8 +3452,6 @@ pub enum ItemKind<'hir> {
     GlobalAsm(&'hir InlineAsm<'hir>),
     /// A type alias, e.g., `type Foo = Bar<u8>`.
     TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>),
-    /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`.
-    OpaqueTy(&'hir OpaqueTy<'hir>),
     /// An enum definition, e.g., `enum Foo<A, B> {C<A>, D<B>}`.
     Enum(EnumDef<'hir>, &'hir Generics<'hir>),
     /// A struct definition, e.g., `struct Foo<A> {x: A}`.
@@ -3484,7 +3495,6 @@ impl ItemKind<'_> {
             ItemKind::Fn(_, ref generics, _)
             | ItemKind::TyAlias(_, ref generics)
             | ItemKind::Const(_, ref generics, _)
-            | ItemKind::OpaqueTy(OpaqueTy { ref generics, .. })
             | ItemKind::Enum(_, ref generics)
             | ItemKind::Struct(_, ref generics)
             | ItemKind::Union(_, ref generics)
@@ -3507,7 +3517,6 @@ impl ItemKind<'_> {
             ItemKind::ForeignMod { .. } => "extern block",
             ItemKind::GlobalAsm(..) => "global asm item",
             ItemKind::TyAlias(..) => "type alias",
-            ItemKind::OpaqueTy(..) => "opaque type",
             ItemKind::Enum(..) => "enum",
             ItemKind::Struct(..) => "struct",
             ItemKind::Union(..) => "union",
@@ -3794,6 +3803,7 @@ pub enum Node<'hir> {
     Ty(&'hir Ty<'hir>),
     AssocItemConstraint(&'hir AssocItemConstraint<'hir>),
     TraitRef(&'hir TraitRef<'hir>),
+    OpaqueTy(&'hir OpaqueTy<'hir>),
     Pat(&'hir Pat<'hir>),
     PatField(&'hir PatField<'hir>),
     Arm(&'hir Arm<'hir>),
@@ -3859,6 +3869,7 @@ impl<'hir> Node<'hir> {
             | Node::Crate(..)
             | Node::Ty(..)
             | Node::TraitRef(..)
+            | Node::OpaqueTy(..)
             | Node::Infer(..)
             | Node::WhereBoundPredicate(..)
             | Node::ArrayLenInfer(..)
@@ -3984,6 +3995,7 @@ impl<'hir> Node<'hir> {
             | Node::TraitItem(TraitItem { generics, .. })
             | Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
             Node::Item(item) => item.kind.generics(),
+            Node::OpaqueTy(opaque) => Some(opaque.generics),
             _ => None,
         }
     }
@@ -4043,6 +4055,7 @@ impl<'hir> Node<'hir> {
         expect_ty,            &'hir Ty<'hir>,           Node::Ty(n),           n;
         expect_assoc_item_constraint,  &'hir AssocItemConstraint<'hir>,  Node::AssocItemConstraint(n),  n;
         expect_trait_ref,     &'hir TraitRef<'hir>,     Node::TraitRef(n),     n;
+        expect_opaque_ty,     &'hir OpaqueTy<'hir>,     Node::OpaqueTy(n),     n;
         expect_pat,           &'hir Pat<'hir>,          Node::Pat(n),          n;
         expect_pat_field,     &'hir PatField<'hir>,     Node::PatField(n),     n;
         expect_arm,           &'hir Arm<'hir>,          Node::Arm(n),          n;
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 4da32245785..58916d05865 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -111,6 +111,7 @@ impl<'a> FnKind<'a> {
 pub trait Map<'hir> {
     /// Retrieves the `Node` corresponding to `id`.
     fn hir_node(&self, hir_id: HirId) -> Node<'hir>;
+    fn hir_node_by_def_id(&self, def_id: LocalDefId) -> Node<'hir>;
     fn body(&self, id: BodyId) -> &'hir Body<'hir>;
     fn item(&self, id: ItemId) -> &'hir Item<'hir>;
     fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir>;
@@ -123,6 +124,9 @@ impl<'hir> Map<'hir> for ! {
     fn hir_node(&self, _: HirId) -> Node<'hir> {
         *self;
     }
+    fn hir_node_by_def_id(&self, _: LocalDefId) -> Node<'hir> {
+        *self;
+    }
     fn body(&self, _: BodyId) -> &'hir Body<'hir> {
         *self;
     }
@@ -423,6 +427,9 @@ pub trait Visitor<'v>: Sized {
     fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>) -> Self::Result {
         walk_poly_trait_ref(self, t)
     }
+    fn visit_opaque_ty(&mut self, opaque: &'v OpaqueTy<'v>) -> Self::Result {
+        walk_opaque_ty(self, opaque)
+    }
     fn visit_variant_data(&mut self, s: &'v VariantData<'v>) -> Self::Result {
         walk_struct_def(self, s)
     }
@@ -536,11 +543,6 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             try_visit!(visitor.visit_ty(ty));
             try_visit!(visitor.visit_generics(generics));
         }
-        ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, .. }) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
-            try_visit!(walk_generics(visitor, generics));
-            walk_list!(visitor, visit_param_bound, bounds);
-        }
         ItemKind::Enum(ref enum_definition, ref generics) => {
             try_visit!(visitor.visit_generics(generics));
             // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`.
@@ -894,8 +896,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
         TyKind::Path(ref qpath) => {
             try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span));
         }
-        TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => {
-            try_visit!(visitor.visit_nested_item(item_id));
+        TyKind::OpaqueDef(opaque, lifetimes) => {
+            try_visit!(visitor.visit_opaque_ty(opaque));
             walk_list!(visitor, visit_generic_arg, lifetimes);
         }
         TyKind::Array(ref ty, ref length) => {
@@ -1185,6 +1187,15 @@ pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(
     visitor.visit_trait_ref(&trait_ref.trait_ref)
 }
 
+pub fn walk_opaque_ty<'v, V: Visitor<'v>>(visitor: &mut V, opaque: &'v OpaqueTy<'v>) -> V::Result {
+    let &OpaqueTy { hir_id, def_id: _, generics, bounds, origin: _, lifetime_mapping: _, span: _ } =
+        opaque;
+    try_visit!(visitor.visit_id(hir_id));
+    try_visit!(walk_generics(visitor, generics));
+    walk_list!(visitor, visit_param_bound, bounds);
+    V::Result::output()
+}
+
 pub fn walk_struct_def<'v, V: Visitor<'v>>(
     visitor: &mut V,
     struct_definition: &'v VariantData<'v>,
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index 155270ca6a7..6ff57396b4a 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -34,7 +34,6 @@ pub enum Target {
     ForeignMod,
     GlobalAsm,
     TyAlias,
-    OpaqueTy,
     Enum,
     Variant,
     Struct,
@@ -79,7 +78,6 @@ impl Target {
             | Target::ForeignMod
             | Target::GlobalAsm
             | Target::TyAlias
-            | Target::OpaqueTy
             | Target::Enum
             | Target::Variant
             | Target::Struct
@@ -114,7 +112,6 @@ impl Target {
             ItemKind::ForeignMod { .. } => Target::ForeignMod,
             ItemKind::GlobalAsm(..) => Target::GlobalAsm,
             ItemKind::TyAlias(..) => Target::TyAlias,
-            ItemKind::OpaqueTy(..) => Target::OpaqueTy,
             ItemKind::Enum(..) => Target::Enum,
             ItemKind::Struct(..) => Target::Struct,
             ItemKind::Union(..) => Target::Union,
@@ -137,7 +134,6 @@ impl Target {
             DefKind::ForeignMod => Target::ForeignMod,
             DefKind::GlobalAsm => Target::GlobalAsm,
             DefKind::TyAlias => Target::TyAlias,
-            DefKind::OpaqueTy => Target::OpaqueTy,
             DefKind::Enum => Target::Enum,
             DefKind::Struct => Target::Struct,
             DefKind::Union => Target::Union,
@@ -191,7 +187,6 @@ impl Target {
             Target::ForeignMod => "foreign module",
             Target::GlobalAsm => "global asm",
             Target::TyAlias => "type alias",
-            Target::OpaqueTy => "opaque type",
             Target::Enum => "enum",
             Target::Variant => "enum variant",
             Target::Struct => "struct",
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index caf9960741d..8947e7a2216 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -91,12 +91,46 @@ impl<'tcx> Bounds<'tcx> {
                 }
                 tcx.consts.true_
             }
+            (DefKind::Trait, ty::BoundConstness::ConstIfConst) => {
+                // we are in a trait, where `bound_trait_ref` could be:
+                // (1) a super trait `trait Foo: ~const Bar`.
+                //     - This generates `<Self as Foo>::Effects: TyCompat<<Self as Bar>::Effects>`
+                //
+                // (2) a where clause `where for<..> Something: ~const Bar`.
+                //     - This generates `for<..> <Self as Foo>::Effects: TyCompat<<Something as Bar>::Effects>`
+                let Some(own_fx) = tcx.associated_type_for_effects(defining_def_id) else {
+                    tcx.dcx().span_delayed_bug(span, "should not have allowed `~const` on a trait that doesn't have `#[const_trait]`");
+                    return;
+                };
+                let own_fx_ty = Ty::new_projection(
+                    tcx,
+                    own_fx,
+                    ty::GenericArgs::identity_for_item(tcx, own_fx),
+                );
+                let Some(their_fx) = tcx.associated_type_for_effects(bound_trait_ref.def_id())
+                else {
+                    tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc");
+                    return;
+                };
+                let their_fx_ty =
+                    Ty::new_projection(tcx, their_fx, bound_trait_ref.skip_binder().args);
+                let compat = tcx.require_lang_item(LangItem::EffectsTyCompat, Some(span));
+                let clause = bound_trait_ref
+                    .map_bound(|_| {
+                        let trait_ref = ty::TraitRef::new(tcx, compat, [own_fx_ty, their_fx_ty]);
+                        ty::ClauseKind::Trait(ty::TraitPredicate {
+                            trait_ref,
+                            polarity: ty::PredicatePolarity::Positive,
+                        })
+                    })
+                    .upcast(tcx);
+
+                self.clauses.push((clause, span));
+                return;
+            }
 
-            (
-                DefKind::Trait | DefKind::Impl { of_trait: true },
-                ty::BoundConstness::ConstIfConst,
-            ) => {
-                // this is either a where clause on an impl/trait header or on a trait.
+            (DefKind::Impl { of_trait: true }, ty::BoundConstness::ConstIfConst) => {
+                // this is a where clause on an impl header.
                 // push `<T as Tr>::Effects` into the set for the `Min` bound.
                 let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
                     tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc");
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index d725772a5b3..eb62ff86c71 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -252,10 +252,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 /// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
 /// projections that would result in "inheriting lifetimes".
 fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    let item = tcx.hir().expect_item(def_id);
-    let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else {
-        tcx.dcx().span_bug(item.span, "expected opaque item");
-    };
+    let hir::OpaqueTy { origin, .. } = tcx.hir().expect_opaque_ty(def_id);
 
     // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
     // `async-std` (and `pub async fn` in general).
@@ -265,16 +262,16 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         return;
     }
 
-    let span = tcx.def_span(item.owner_id.def_id);
+    let span = tcx.def_span(def_id);
 
-    if tcx.type_of(item.owner_id.def_id).instantiate_identity().references_error() {
+    if tcx.type_of(def_id).instantiate_identity().references_error() {
         return;
     }
-    if check_opaque_for_cycles(tcx, item.owner_id.def_id, span).is_err() {
+    if check_opaque_for_cycles(tcx, def_id, span).is_err() {
         return;
     }
 
-    let _ = check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, origin);
+    let _ = check_opaque_meets_bounds(tcx, def_id, span, origin);
 }
 
 /// Checks that an opaque type does not contain cycles.
@@ -336,9 +333,9 @@ fn check_opaque_meets_bounds<'tcx>(
     origin: &hir::OpaqueTyOrigin,
 ) -> Result<(), ErrorGuaranteed> {
     let defining_use_anchor = match *origin {
-        hir::OpaqueTyOrigin::FnReturn(did)
-        | hir::OpaqueTyOrigin::AsyncFn(did)
-        | hir::OpaqueTyOrigin::TyAlias { parent: did, .. } => did,
+        hir::OpaqueTyOrigin::FnReturn { parent, .. }
+        | hir::OpaqueTyOrigin::AsyncFn { parent, .. }
+        | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent,
     };
     let param_env = tcx.param_env(defining_use_anchor);
 
@@ -346,8 +343,8 @@ fn check_opaque_meets_bounds<'tcx>(
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     let args = match *origin {
-        hir::OpaqueTyOrigin::FnReturn(parent)
-        | hir::OpaqueTyOrigin::AsyncFn(parent)
+        hir::OpaqueTyOrigin::FnReturn { parent, .. }
+        | hir::OpaqueTyOrigin::AsyncFn { parent, .. }
         | hir::OpaqueTyOrigin::TyAlias { parent, .. } => GenericArgs::identity_for_item(
             tcx, parent,
         )
@@ -409,7 +406,7 @@ fn check_opaque_meets_bounds<'tcx>(
     let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
     ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
 
-    if let hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) = origin {
+    if let hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } = origin {
         // HACK: this should also fall through to the hidden type check below, but the original
         // implementation had a bug where equivalent lifetimes are not identical. This caused us
         // to reject existing stable code that is otherwise completely fine. The real fix is to
@@ -481,8 +478,7 @@ fn sanity_check_found_hidden_type<'tcx>(
 /// 2. Checking that all lifetimes that are implicitly captured are mentioned.
 /// 3. Asserting that all parameters mentioned in the captures list are invariant.
 fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) {
-    let hir::OpaqueTy { bounds, .. } =
-        *tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
+    let hir::OpaqueTy { bounds, .. } = *tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty();
     let Some(precise_capturing_args) = bounds.iter().find_map(|bound| match *bound {
         hir::GenericBound::Use(bounds, ..) => Some(bounds),
         _ => None,
@@ -736,8 +732,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             check_opaque_precise_captures(tcx, def_id);
 
             let origin = tcx.opaque_type_origin(def_id);
-            if let hir::OpaqueTyOrigin::FnReturn(fn_def_id)
-            | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin
+            if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
+            | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } = origin
                 && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id)
                 && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
             {
@@ -1105,7 +1101,7 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
         // Check that we use types valid for use in the lanes of a SIMD "vector register"
         // These are scalar types which directly match a "machine" type
         // Yes: Integers, floats, "thin" pointers
-        // No: char, "fat" pointers, compound types
+        // No: char, "wide" pointers, compound types
         match element_ty.kind() {
             ty::Param(_) => (), // pass struct<T>([T; 4]) through, let monomorphization catch errors
             ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) => (), // struct([u8; 4]) is ok
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index e07b587508a..80334c6efe7 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -93,9 +93,9 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
         // it's a refinement to a TAIT.
         if !tcx.hir().get_if_local(impl_opaque.def_id).is_some_and(|node| {
             matches!(
-                node.expect_item().expect_opaque_ty().origin,
-                hir::OpaqueTyOrigin::AsyncFn(def_id)  | hir::OpaqueTyOrigin::FnReturn(def_id)
-                    if def_id == impl_m.def_id.expect_local()
+                node.expect_opaque_ty().origin,
+                hir::OpaqueTyOrigin::AsyncFn { parent, .. }  | hir::OpaqueTyOrigin::FnReturn { parent, .. }
+                    if parent == impl_m.def_id.expect_local()
             )
         }) {
             report_mismatched_rpitit_signature(
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index a71e14ce463..3a9d2640eee 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -2,7 +2,7 @@ use std::cell::LazyCell;
 use std::ops::{ControlFlow, Deref};
 
 use hir::intravisit::{self, Visitor};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
 use rustc_hir::ItemKind;
@@ -185,15 +185,16 @@ where
     }
 }
 
-fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorGuaranteed> {
-    let node = tcx.hir_owner_node(def_id);
+fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
+    let node = tcx.hir_node_by_def_id(def_id);
     let mut res = match node {
-        hir::OwnerNode::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"),
-        hir::OwnerNode::Item(item) => check_item(tcx, item),
-        hir::OwnerNode::TraitItem(item) => check_trait_item(tcx, item),
-        hir::OwnerNode::ImplItem(item) => check_impl_item(tcx, item),
-        hir::OwnerNode::ForeignItem(item) => check_foreign_item(tcx, item),
-        hir::OwnerNode::Synthetic => unreachable!(),
+        hir::Node::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"),
+        hir::Node::Item(item) => check_item(tcx, item),
+        hir::Node::TraitItem(item) => check_trait_item(tcx, item),
+        hir::Node::ImplItem(item) => check_impl_item(tcx, item),
+        hir::Node::ForeignItem(item) => check_foreign_item(tcx, item),
+        hir::Node::OpaqueTy(_) => Ok(crate::check::check::check_item_type(tcx, def_id)),
+        _ => unreachable!(),
     };
 
     if let Some(generics) = node.generics() {
@@ -201,6 +202,7 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorG
             res = res.and(check_param_wf(tcx, param));
         }
     }
+
     res
 }
 
@@ -404,7 +406,7 @@ fn check_trait_item<'tcx>(
 /// ```
 fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
     // Associates every GAT's def_id to a list of possibly missing bounds detected by this lint.
-    let mut required_bounds_by_item = FxHashMap::default();
+    let mut required_bounds_by_item = FxIndexMap::default();
     let associated_items = tcx.associated_items(trait_def_id);
 
     // Loop over all GATs together, because if this lint suggests adding a where-clause bound
@@ -430,7 +432,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
             // Gather the bounds with which all other items inside of this trait constrain the GAT.
             // This is calculated by taking the intersection of the bounds that each item
             // constrains the GAT with individually.
-            let mut new_required_bounds: Option<FxHashSet<ty::Clause<'_>>> = None;
+            let mut new_required_bounds: Option<FxIndexSet<ty::Clause<'_>>> = None;
             for item in associated_items.in_definition_order() {
                 let item_def_id = item.def_id.expect_local();
                 // Skip our own GAT, since it does not constrain itself at all.
@@ -589,7 +591,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
 fn augment_param_env<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    new_predicates: Option<&FxHashSet<ty::Clause<'tcx>>>,
+    new_predicates: Option<&FxIndexSet<ty::Clause<'tcx>>>,
 ) -> ty::ParamEnv<'tcx> {
     let Some(new_predicates) = new_predicates else {
         return param_env;
@@ -625,9 +627,9 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
     wf_tys: &FxIndexSet<Ty<'tcx>>,
     gat_def_id: LocalDefId,
     gat_generics: &'tcx ty::Generics,
-) -> Option<FxHashSet<ty::Clause<'tcx>>> {
+) -> Option<FxIndexSet<ty::Clause<'tcx>>> {
     // The bounds we that we would require from `to_check`
-    let mut bounds = FxHashSet::default();
+    let mut bounds = FxIndexSet::default();
 
     let (regions, types) = GATArgsCollector::visit(gat_def_id.to_def_id(), to_check);
 
@@ -789,18 +791,18 @@ fn test_region_obligations<'tcx>(
 struct GATArgsCollector<'tcx> {
     gat: DefId,
     // Which region appears and which parameter index its instantiated with
-    regions: FxHashSet<(ty::Region<'tcx>, usize)>,
+    regions: FxIndexSet<(ty::Region<'tcx>, usize)>,
     // Which params appears and which parameter index its instantiated with
-    types: FxHashSet<(Ty<'tcx>, usize)>,
+    types: FxIndexSet<(Ty<'tcx>, usize)>,
 }
 
 impl<'tcx> GATArgsCollector<'tcx> {
     fn visit<T: TypeFoldable<TyCtxt<'tcx>>>(
         gat: DefId,
         t: T,
-    ) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) {
+    ) -> (FxIndexSet<(ty::Region<'tcx>, usize)>, FxIndexSet<(Ty<'tcx>, usize)>) {
         let mut visitor =
-            GATArgsCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() };
+            GATArgsCollector { gat, regions: FxIndexSet::default(), types: FxIndexSet::default() };
         t.visit_with(&mut visitor);
         (visitor.regions, visitor.types)
     }
@@ -961,13 +963,20 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
                         hir_ty.span,
                         "using raw pointers as const generic parameters is forbidden",
                     ),
-                    _ => tcx.dcx().struct_span_err(
-                        hir_ty.span,
-                        format!("`{}` is forbidden as the type of a const generic parameter", ty),
-                    ),
+                    _ => {
+                        // Avoid showing "{type error}" to users. See #118179.
+                        ty.error_reported()?;
+
+                        tcx.dcx().struct_span_err(
+                            hir_ty.span,
+                            format!(
+                                "`{ty}` is forbidden as the type of a const generic parameter",
+                            ),
+                        )
+                    }
                 };
 
-                diag.note("the only supported types are integers, `bool` and `char`");
+                diag.note("the only supported types are integers, `bool`, and `char`");
 
                 let cause = ObligationCause::misc(hir_ty.span, param.def_id);
                 let adt_const_params_feature_string =
@@ -2165,10 +2174,14 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
 
 fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> {
     let items = tcx.hir_module_items(module);
-    let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id));
-    res = res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
-    res = res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
-    res = res.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
+    let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id));
+    res =
+        res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)));
+    res =
+        res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)));
+    res = res
+        .and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)));
+    res = res.and(items.par_opaques(|item| tcx.ensure().check_well_formed(item)));
     if module == LocalModDefId::CRATE_DEF_ID {
         super::entry::check_for_entry_fn(tcx);
     }
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index bea8d28a9f7..76c75d976ee 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -424,7 +424,7 @@ pub(crate) fn coerce_unsized_info<'tcx>(
             // Here `U = [i32; 3]` and `V = [i32]`. At runtime,
             // when this coercion occurs, we would be changing the
             // field `ptr` from a thin pointer of type `*mut [i32;
-            // 3]` to a fat pointer of type `*mut [i32]` (with
+            // 3]` to a wide pointer of type `*mut [i32]` (with
             // extra data `3`). **The purpose of this check is to
             // make sure that we know how to do this conversion.**
             //
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
index b8066b4b47d..d1c888a185e 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap, IndexEntry};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
 use rustc_errors::codes::*;
 use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
@@ -215,7 +215,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
 
             struct ConnectedRegion {
                 idents: SmallVec<[Symbol; 8]>,
-                impl_blocks: FxHashSet<usize>,
+                impl_blocks: FxIndexSet<usize>,
             }
             let mut connected_regions: IndexVec<RegionId, _> = Default::default();
             // Reverse map from the Symbol to the connected region id.
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 93b021be245..640907c3e4a 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -260,8 +260,7 @@ fn reject_placeholder_type_signatures_in_item<'tcx>(
         | hir::ItemKind::Trait(_, _, generics, ..)
         | hir::ItemKind::Impl(hir::Impl { generics, .. })
         | hir::ItemKind::Struct(_, generics) => (generics, true),
-        hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. })
-        | hir::ItemKind::TyAlias(_, generics) => (generics, false),
+        hir::ItemKind::TyAlias(_, generics) => (generics, false),
         // `static`, `fn` and `const` are handled elsewhere to suggest appropriate type.
         _ => return,
     };
@@ -328,6 +327,19 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
         intravisit::walk_expr(self, expr);
     }
 
+    /// Don't call `type_of` on opaque types, since that depends on type checking function bodies.
+    /// `check_item_type` ensures that it's called instead.
+    fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) {
+        let def_id = opaque.def_id;
+        self.tcx.ensure().generics_of(def_id);
+        self.tcx.ensure().predicates_of(def_id);
+        self.tcx.ensure().explicit_item_bounds(def_id);
+        self.tcx.ensure().explicit_item_super_predicates(def_id);
+        self.tcx.ensure().item_bounds(def_id);
+        self.tcx.ensure().item_super_predicates(def_id);
+        intravisit::walk_opaque_ty(self, opaque);
+    }
+
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         lower_trait_item(self.tcx, trait_item.trait_item_id());
         intravisit::walk_trait_item(self, trait_item);
@@ -731,18 +743,6 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             }
         }
 
-        // Don't call `type_of` on opaque types, since that depends on type
-        // checking function bodies. `check_item_type` ensures that it's called
-        // instead.
-        hir::ItemKind::OpaqueTy(..) => {
-            tcx.ensure().generics_of(def_id);
-            tcx.ensure().predicates_of(def_id);
-            tcx.ensure().explicit_item_bounds(def_id);
-            tcx.ensure().explicit_item_super_predicates(def_id);
-            tcx.ensure().item_bounds(def_id);
-            tcx.ensure().item_super_predicates(def_id);
-        }
-
         hir::ItemKind::TyAlias(..) => {
             tcx.ensure().generics_of(def_id);
             tcx.ensure().type_of(def_id);
@@ -1852,12 +1852,8 @@ fn coroutine_for_closure(tcx: TyCtxt<'_>, def_id: LocalDefId) -> DefId {
 }
 
 fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
-    match tcx.hir_node_by_def_id(def_id) {
-        Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => {
-            matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. })
-        }
-        _ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id),
-    }
+    let opaque = tcx.hir().expect_opaque_ty(def_id);
+    matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. })
 }
 
 fn rendered_precise_capturing_args<'tcx>(
@@ -1870,12 +1866,10 @@ fn rendered_precise_capturing_args<'tcx>(
         return tcx.rendered_precise_capturing_args(opaque_def_id);
     }
 
-    tcx.hir_node_by_def_id(def_id).expect_item().expect_opaque_ty().bounds.iter().find_map(
-        |bound| match bound {
-            hir::GenericBound::Use(args, ..) => {
-                Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| arg.name())))
-            }
-            _ => None,
-        },
-    )
+    tcx.hir_node_by_def_id(def_id).expect_opaque_ty().bounds.iter().find_map(|bound| match bound {
+        hir::GenericBound::Use(args, ..) => {
+            Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| arg.name())))
+        }
+        _ => None,
+    })
 }
diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs
index d76d9213129..8648a7d1e32 100644
--- a/compiler/rustc_hir_analysis/src/collect/dump.rs
+++ b/compiler/rustc_hir_analysis/src/collect/dump.rs
@@ -1,4 +1,3 @@
-use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
 use rustc_hir::intravisit;
 use rustc_middle::hir::nested_filter::OnlyBodies;
@@ -10,12 +9,10 @@ pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) {
         return;
     }
 
-    for id in tcx.hir().items() {
-        let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue };
-
-        let ty = tcx.type_of(id.owner_id).instantiate_identity();
-
-        tcx.dcx().emit_err(crate::errors::TypeOf { span: tcx.def_span(id.owner_id), ty });
+    for id in tcx.hir_crate_items(()).opaques() {
+        let ty = tcx.type_of(id).instantiate_identity();
+        let span = tcx.def_span(id);
+        tcx.dcx().emit_err(crate::errors::TypeOf { span, ty });
     }
 }
 
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 0a8eef2006d..14b6b17ed18 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -24,6 +24,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
     if let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) =
         tcx.opt_rpitit_info(def_id.to_def_id())
     {
+        debug!("RPITIT fn_def_id={fn_def_id:?} opaque_def_id={opaque_def_id:?}");
         let trait_def_id = tcx.parent(fn_def_id);
         let opaque_ty_generics = tcx.generics_of(opaque_def_id);
         let opaque_ty_parent_count = opaque_ty_generics.parent_count;
@@ -207,36 +208,33 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
         | Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
             Some(tcx.typeck_root_def_id(def_id.to_def_id()))
         }
-        Node::Item(item) => match item.kind {
-            ItemKind::OpaqueTy(&hir::OpaqueTy {
-                origin:
-                    hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
-                in_trait,
-                ..
-            }) => {
-                if in_trait {
-                    assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn);
-                } else {
-                    assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn);
-                }
-                Some(fn_def_id.to_def_id())
+        Node::OpaqueTy(&hir::OpaqueTy {
+            origin:
+                hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, in_trait_or_impl }
+                | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl },
+            ..
+        }) => {
+            if in_trait_or_impl.is_some() {
+                assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn);
+            } else {
+                assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn);
             }
-            ItemKind::OpaqueTy(&hir::OpaqueTy {
-                origin: hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty },
-                ..
-            }) => {
-                if in_assoc_ty {
-                    assert_matches!(tcx.def_kind(parent), DefKind::AssocTy);
-                } else {
-                    assert_matches!(tcx.def_kind(parent), DefKind::TyAlias);
-                }
-                debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent);
-                // Opaque types are always nested within another item, and
-                // inherit the generics of the item.
-                Some(parent.to_def_id())
+            Some(fn_def_id.to_def_id())
+        }
+        Node::OpaqueTy(&hir::OpaqueTy {
+            origin: hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty },
+            ..
+        }) => {
+            if in_assoc_ty {
+                assert_matches!(tcx.def_kind(parent), DefKind::AssocTy);
+            } else {
+                assert_matches!(tcx.def_kind(parent), DefKind::TyAlias);
             }
-            _ => None,
-        },
+            debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent);
+            // Opaque types are always nested within another item, and
+            // inherit the generics of the item.
+            Some(parent.to_def_id())
+        }
         _ => None,
     };
 
@@ -272,13 +270,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                 ItemKind::TyAlias(..)
                 | ItemKind::Enum(..)
                 | ItemKind::Struct(..)
-                | ItemKind::OpaqueTy(..)
                 | ItemKind::Union(..) => (None, Defaults::Allowed),
                 ItemKind::Const(..) => (None, Defaults::Deny),
                 _ => (None, Defaults::FutureCompatDisallowed),
             }
         }
 
+        Node::OpaqueTy(..) => (None, Defaults::Allowed),
+
         // GATs
         Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => {
             (None, Defaults::Deny)
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 7557219aaa6..4346504450d 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -335,8 +335,7 @@ pub(super) fn explicit_item_bounds_with_filter(
         // RPITIT's bounds are the same as opaque type bounds, but with
         // a projection self type.
         Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
-            let item = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_item();
-            let opaque_ty = item.expect_opaque_ty();
+            let opaque_ty = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_opaque_ty();
             let item_ty = Ty::new_projection_from_args(
                 tcx,
                 def_id.to_def_id(),
@@ -347,7 +346,7 @@ pub(super) fn explicit_item_bounds_with_filter(
                 opaque_def_id.expect_local(),
                 opaque_ty.bounds,
                 item_ty,
-                item.span,
+                opaque_ty.span,
                 filter,
             );
             assert_only_contains_predicates_from(filter, bounds, item_ty);
@@ -360,74 +359,55 @@ pub(super) fn explicit_item_bounds_with_filter(
         None => {}
     }
 
-    if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) {
-        let mut predicates = Vec::new();
-
-        let parent = tcx.local_parent(def_id);
-
-        let preds = tcx.explicit_predicates_of(parent);
-
-        if let ty::AssocItemContainer::TraitContainer = tcx.associated_item(def_id).container {
-            // for traits, emit `type Effects: TyCompat<<(T1::Effects, ..) as Min>::Output>`
-            let tup = Ty::new(tcx, ty::Tuple(preds.effects_min_tys));
-            // FIXME(effects) span
-            let span = tcx.def_span(def_id);
-            let assoc = tcx.require_lang_item(hir::LangItem::EffectsIntersectionOutput, Some(span));
-            let proj = Ty::new_projection(tcx, assoc, [tup]);
-            let self_proj = Ty::new_projection(
-                tcx,
-                def_id.to_def_id(),
-                ty::GenericArgs::identity_for_item(tcx, def_id),
-            );
-            let trait_ = tcx.require_lang_item(hir::LangItem::EffectsTyCompat, Some(span));
-            let trait_ref = ty::TraitRef::new(tcx, trait_, [self_proj, proj]);
-            predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span));
-        }
-        return ty::EarlyBinder::bind(tcx.arena.alloc_from_iter(predicates));
-    }
-
     let bounds = match tcx.hir_node_by_def_id(def_id) {
+        _ if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) => {
+            associated_type_bounds(tcx, def_id, &[], tcx.def_span(def_id), filter)
+        }
         hir::Node::TraitItem(hir::TraitItem {
             kind: hir::TraitItemKind::Type(bounds, _),
             span,
             ..
         }) => associated_type_bounds(tcx, def_id, bounds, *span, filter),
-        hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: false, .. }),
-            span,
-            ..
-        }) => {
-            let args = GenericArgs::identity_for_item(tcx, def_id);
-            let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
-            let bounds = opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter);
-            assert_only_contains_predicates_from(filter, bounds, item_ty);
-            bounds
-        }
-        // Since RPITITs are lowered as projections in `<dyn HirTyLowerer>::lower_ty`, when we're
-        // asking for the item bounds of the *opaques* in a trait's default method signature, we
-        // need to map these projections back to opaques.
-        hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: true, origin, .. }),
-            span,
-            ..
-        }) => {
-            let (hir::OpaqueTyOrigin::FnReturn(fn_def_id)
-            | hir::OpaqueTyOrigin::AsyncFn(fn_def_id)) = *origin
-            else {
-                span_bug!(*span, "RPITIT cannot be a TAIT, but got origin {origin:?}");
-            };
-            let args = GenericArgs::identity_for_item(tcx, def_id);
-            let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
-            let bounds = &*tcx.arena.alloc_slice(
-                &opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter)
-                    .to_vec()
-                    .fold_with(&mut AssocTyToOpaque { tcx, fn_def_id: fn_def_id.to_def_id() }),
-            );
-            assert_only_contains_predicates_from(filter, bounds, item_ty);
-            bounds
-        }
+        hir::Node::OpaqueTy(hir::OpaqueTy { bounds, origin, span, .. }) => match origin {
+            // Since RPITITs are lowered as projections in `<dyn HirTyLowerer>::lower_ty`,
+            // when we're asking for the item bounds of the *opaques* in a trait's default
+            // method signature, we need to map these projections back to opaques.
+            rustc_hir::OpaqueTyOrigin::FnReturn {
+                parent,
+                in_trait_or_impl: Some(hir::RpitContext::Trait),
+            }
+            | rustc_hir::OpaqueTyOrigin::AsyncFn {
+                parent,
+                in_trait_or_impl: Some(hir::RpitContext::Trait),
+            } => {
+                let args = GenericArgs::identity_for_item(tcx, def_id);
+                let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
+                let bounds = &*tcx.arena.alloc_slice(
+                    &opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter)
+                        .to_vec()
+                        .fold_with(&mut AssocTyToOpaque { tcx, fn_def_id: parent.to_def_id() }),
+                );
+                assert_only_contains_predicates_from(filter, bounds, item_ty);
+                bounds
+            }
+            rustc_hir::OpaqueTyOrigin::FnReturn {
+                parent: _,
+                in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
+            }
+            | rustc_hir::OpaqueTyOrigin::AsyncFn {
+                parent: _,
+                in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
+            }
+            | rustc_hir::OpaqueTyOrigin::TyAlias { parent: _, .. } => {
+                let args = GenericArgs::identity_for_item(tcx, def_id);
+                let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
+                let bounds = opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter);
+                assert_only_contains_predicates_from(filter, bounds, item_ty);
+                bounds
+            }
+        },
         hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[],
-        _ => bug!("item_bounds called on {:?}", def_id),
+        node => bug!("item_bounds called on {def_id:?} => {node:?}"),
     };
 
     ty::EarlyBinder::bind(bounds)
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 9e970462205..6d30f7c7b9d 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -330,9 +330,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     // Opaque types duplicate some of their generic parameters.
     // We create bi-directional Outlives predicates between the original
     // and the duplicated parameter, to ensure that they do not get out of sync.
-    if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node {
+    if let Node::OpaqueTy(..) = node {
         let opaque_ty_node = tcx.parent_hir_node(hir_id);
-        let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node
+        let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes), .. }) = opaque_ty_node
         else {
             bug!("unexpected {opaque_ty_node:?}")
         };
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index c9b949ad88d..c8852a3a369 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -11,10 +11,13 @@ use std::fmt;
 
 use rustc_ast::visit::walk_list;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
+use rustc_data_structures::sorted_map::SortedMap;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirId, HirIdMap, LifetimeName, Node};
+use rustc_hir::{
+    GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap, LifetimeName, Node,
+};
 use rustc_macros::extension;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_bound_vars::*;
@@ -74,7 +77,7 @@ impl ResolvedArg {
 struct NamedVarMap {
     // maps from every use of a named (not anonymous) bound var to a
     // `ResolvedArg` describing how that variable is bound
-    defs: HirIdMap<ResolvedArg>,
+    defs: ItemLocalMap<ResolvedArg>,
 
     // Maps relevant hir items to the bound vars on them. These include:
     // - function defs
@@ -82,7 +85,7 @@ struct NamedVarMap {
     // - closures
     // - trait refs
     // - bound types (like `T` in `for<'a> T<'a>: Foo`)
-    late_bound_vars: HirIdMap<Vec<ty::BoundVariableKind>>,
+    late_bound_vars: ItemLocalMap<Vec<ty::BoundVariableKind>>,
 }
 
 struct BoundVarContext<'a, 'tcx> {
@@ -225,10 +228,10 @@ pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         resolve_bound_vars,
 
-        named_variable_map: |tcx, id| tcx.resolve_bound_vars(id).defs.get(&id),
+        named_variable_map: |tcx, id| &tcx.resolve_bound_vars(id).defs,
         is_late_bound_map,
         object_lifetime_default,
-        late_bound_vars_map: |tcx, id| tcx.resolve_bound_vars(id).late_bound_vars.get(&id),
+        late_bound_vars_map: |tcx, id| &tcx.resolve_bound_vars(id).late_bound_vars,
 
         ..*providers
     };
@@ -265,16 +268,12 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou
         hir::OwnerNode::Synthetic => unreachable!(),
     }
 
-    let mut rl = ResolveBoundVars::default();
-
-    for (hir_id, v) in named_variable_map.defs {
-        let map = rl.defs.entry(hir_id.owner).or_default();
-        map.insert(hir_id.local_id, v);
-    }
-    for (hir_id, v) in named_variable_map.late_bound_vars {
-        let map = rl.late_bound_vars.entry(hir_id.owner).or_default();
-        map.insert(hir_id.local_id, v);
-    }
+    let defs = named_variable_map.defs.into_sorted_stable_ord();
+    let late_bound_vars = named_variable_map.late_bound_vars.into_sorted_stable_ord();
+    let rl = ResolveBoundVars {
+        defs: SortedMap::from_presorted_elements(defs),
+        late_bound_vars: SortedMap::from_presorted_elements(late_bound_vars),
+    };
 
     debug!(?rl.defs);
     debug!(?rl.late_bound_vars);
@@ -340,7 +339,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 Scope::Binder { hir_id, .. } => {
                     // Nested poly trait refs have the binders concatenated
                     let mut full_binders =
-                        self.map.late_bound_vars.entry(*hir_id).or_default().clone();
+                        self.map.late_bound_vars.entry(hir_id.local_id).or_default().clone();
                     full_binders.extend(supertrait_bound_vars);
                     break (full_binders, BinderScopeType::Concatenating);
                 }
@@ -487,6 +486,31 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
+    fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) {
+        // We want to start our early-bound indices at the end of the parent scope,
+        // not including any parent `impl Trait`s.
+        let mut bound_vars = FxIndexMap::default();
+        debug!(?opaque.generics.params);
+        for param in opaque.generics.params {
+            let (def_id, reg) = ResolvedArg::early(param);
+            bound_vars.insert(def_id, reg);
+        }
+
+        let hir_id = self.tcx.local_def_id_to_hir_id(opaque.def_id);
+        let scope = Scope::Binder {
+            hir_id,
+            bound_vars,
+            s: self.scope,
+            scope_type: BinderScopeType::Normal,
+            where_bound_origin: None,
+        };
+        self.with(scope, |this| {
+            let scope = Scope::TraitRefBoundary { s: this.scope };
+            this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque))
+        })
+    }
+
+    #[instrument(level = "debug", skip(self))]
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         match &item.kind {
             hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => {
@@ -513,38 +537,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                 // These sorts of items have no lifetime parameters at all.
                 intravisit::walk_item(self, item);
             }
-            hir::ItemKind::OpaqueTy(&hir::OpaqueTy {
-                origin:
-                    hir::OpaqueTyOrigin::FnReturn(parent)
-                    | hir::OpaqueTyOrigin::AsyncFn(parent)
-                    | hir::OpaqueTyOrigin::TyAlias { parent, .. },
-                generics,
-                ..
-            }) => {
-                // We want to start our early-bound indices at the end of the parent scope,
-                // not including any parent `impl Trait`s.
-                let mut bound_vars = FxIndexMap::default();
-                debug!(?generics.params);
-                for param in generics.params {
-                    let (def_id, reg) = ResolvedArg::early(param);
-                    bound_vars.insert(def_id, reg);
-                }
-
-                let scope = Scope::Root { opt_parent_item: Some(parent) };
-                self.with(scope, |this| {
-                    let scope = Scope::Binder {
-                        hir_id: item.hir_id(),
-                        bound_vars,
-                        s: this.scope,
-                        scope_type: BinderScopeType::Normal,
-                        where_bound_origin: None,
-                    };
-                    this.with(scope, |this| {
-                        let scope = Scope::TraitRefBoundary { s: this.scope };
-                        this.with(scope, |this| intravisit::walk_item(this, item))
-                    });
-                })
-            }
             hir::ItemKind::TyAlias(_, generics)
             | hir::ItemKind::Const(_, generics, _)
             | hir::ItemKind::Enum(_, generics)
@@ -684,22 +676,19 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
             hir::TyKind::Ref(lifetime_ref, ref mt) => {
                 self.visit_lifetime(lifetime_ref);
                 let scope = Scope::ObjectLifetimeDefault {
-                    lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(),
+                    lifetime: self.map.defs.get(&lifetime_ref.hir_id.local_id).cloned(),
                     s: self.scope,
                 };
                 self.with(scope, |this| this.visit_ty(mt.ty));
             }
-            hir::TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => {
+            hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => {
+                self.visit_opaque_ty(opaque_ty);
+
                 // Resolve the lifetimes in the bounds to the lifetime defs in the generics.
                 // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
                 // `type MyAnonTy<'b> = impl MyTrait<'b>;`
                 //                 ^                  ^ this gets resolved in the scope of
                 //                                      the opaque_ty generics
-                let opaque_ty = self.tcx.hir().item(item_id);
-                match &opaque_ty.kind {
-                    hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin: _, .. }) => {}
-                    i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
-                };
 
                 // Resolve the lifetimes that are applied to the opaque type.
                 // These are resolved in the current scope.
@@ -714,7 +703,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                     // and ban them. Type variables instantiated inside binders aren't
                     // well-supported at the moment, so this doesn't work.
                     // In the future, this should be fixed and this error should be removed.
-                    let def = self.map.defs.get(&lifetime.hir_id).copied();
+                    let def = self.map.defs.get(&lifetime.hir_id.local_id).copied();
                     let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue };
                     let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id);
 
@@ -722,9 +711,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                     {
                         // Opaques do not declare their own lifetimes, so if a lifetime comes from an opaque
                         // it must be a reified late-bound lifetime from a trait goal.
-                        hir::Node::Item(hir::Item {
-                            kind: hir::ItemKind::OpaqueTy { .. }, ..
-                        }) => "higher-ranked lifetime from outer `impl Trait`",
+                        hir::Node::OpaqueTy(_) => "higher-ranked lifetime from outer `impl Trait`",
                         // Other items are fine.
                         hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => {
                             continue;
@@ -740,8 +727,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
 
                     let (span, label) = if lifetime.ident.span == self.tcx.def_span(lifetime_def_id)
                     {
-                        let opaque_span = self.tcx.def_span(item_id.owner_id);
-                        (opaque_span, Some(opaque_span))
+                        (opaque_ty.span, Some(opaque_ty.span))
                     } else {
                         (lifetime.ident.span, None)
                     };
@@ -854,7 +840,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
             let bound_vars: Vec<_> =
                 self.tcx.fn_sig(sig_id).skip_binder().bound_vars().iter().collect();
             let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
-            self.map.late_bound_vars.insert(hir_id, bound_vars);
+            self.map.late_bound_vars.insert(hir_id.local_id, bound_vars);
         }
         self.visit_fn_like_elision(fd.inputs, output, matches!(fk, intravisit::FnKind::Closure));
         intravisit::walk_fn_kind(self, fk);
@@ -1032,10 +1018,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
     }
 
     fn record_late_bound_vars(&mut self, hir_id: HirId, binder: Vec<ty::BoundVariableKind>) {
-        if let Some(old) = self.map.late_bound_vars.insert(hir_id, binder) {
+        if let Some(old) = self.map.late_bound_vars.insert(hir_id.local_id, binder) {
             bug!(
                 "overwrote bound vars for {hir_id:?}:\nold={old:?}\nnew={:?}",
-                self.map.late_bound_vars[&hir_id]
+                self.map.late_bound_vars[&hir_id.local_id]
             )
         }
     }
@@ -1394,9 +1380,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                         kind.descr(param_def_id.to_def_id())
                     ),
                 };
-                self.map.defs.insert(hir_id, ResolvedArg::Error(guar));
+                self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
             } else {
-                self.map.defs.insert(hir_id, def);
+                self.map.defs.insert(hir_id.local_id, def);
             }
             return;
         }
@@ -1429,7 +1415,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                             bug!("unexpected def-kind: {}", kind.descr(param_def_id.to_def_id()))
                         }
                     });
-                    self.map.defs.insert(hir_id, ResolvedArg::Error(guar));
+                    self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
                     return;
                 }
                 Scope::Root { .. } => break,
@@ -1539,7 +1525,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     // This index can be used with `generic_args` since `parent_count == 0`.
                     let index = generics.param_def_id_to_index[&param_def_id] as usize;
                     generic_args.args.get(index).and_then(|arg| match arg {
-                        GenericArg::Lifetime(lt) => map.defs.get(&lt.hir_id).copied(),
+                        GenericArg::Lifetime(lt) => map.defs.get(&lt.hir_id.local_id).copied(),
                         _ => None,
                     })
                 }
@@ -1829,7 +1815,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
     #[instrument(level = "debug", skip(self))]
     fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: ResolvedArg) {
         debug!(span = ?lifetime_ref.ident.span);
-        self.map.defs.insert(lifetime_ref.hir_id, def);
+        self.map.defs.insert(lifetime_ref.hir_id.local_id, def);
     }
 
     /// Sometimes we resolve a lifetime, but later find that it is an
@@ -1840,8 +1826,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         lifetime_ref: &'tcx hir::Lifetime,
         bad_def: ResolvedArg,
     ) {
-        // FIXME(#120456) - is `swap_remove` correct?
-        let old_value = self.map.defs.swap_remove(&lifetime_ref.hir_id);
+        let old_value = self.map.defs.remove(&lifetime_ref.hir_id.local_id);
         assert_eq!(old_value, Some(bad_def));
     }
 
@@ -2011,7 +1996,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         // See where these vars are used in `HirTyLowerer::lower_ty_maybe_return_type_notation`.
         // And this is exercised in:
         // `tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs`.
-        let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id).unwrap();
+        let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id.local_id).unwrap();
         let existing_bound_vars_saved = existing_bound_vars.clone();
         existing_bound_vars.extend(bound_vars);
         self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved);
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 48b5e87cbd0..470bcaeded1 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -529,10 +529,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
                 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
                 Ty::new_adt(tcx, def, args)
             }
-            ItemKind::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else(
-                |CyclePlaceholder(guar)| Ty::new_error(tcx, guar),
-                |ty| ty.instantiate_identity(),
-            ),
             ItemKind::Trait(..)
             | ItemKind::TraitAlias(..)
             | ItemKind::Macro(..)
@@ -545,6 +541,11 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
             }
         },
 
+        Node::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else(
+            |CyclePlaceholder(guar)| Ty::new_error(tcx, guar),
+            |ty| ty.instantiate_identity(),
+        ),
+
         Node::ForeignItem(foreign_item) => match foreign_item.kind {
             ForeignItemKind::Fn(..) => {
                 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
@@ -603,40 +604,25 @@ pub(super) fn type_of_opaque(
     def_id: DefId,
 ) -> Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> {
     if let Some(def_id) = def_id.as_local() {
-        use rustc_hir::*;
-
-        Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) {
-            Node::Item(item) => match item.kind {
-                ItemKind::OpaqueTy(OpaqueTy {
-                    origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. },
-                    ..
-                }) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
-                ItemKind::OpaqueTy(OpaqueTy {
-                    origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. },
-                    ..
-                }) => opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id),
-                // Opaque types desugared from `impl Trait`.
-                ItemKind::OpaqueTy(&OpaqueTy {
-                    origin:
-                        hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner),
-                    in_trait,
-                    ..
-                }) => {
-                    if in_trait && !tcx.defaultness(owner).has_value() {
-                        span_bug!(
-                            tcx.def_span(def_id),
-                            "tried to get type of this RPITIT with no definition"
-                        );
-                    }
-                    opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
-                }
-                _ => {
-                    span_bug!(item.span, "type_of_opaque: unexpected item type: {:?}", item.kind);
+        Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin {
+            hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
+                opaque::find_opaque_ty_constraints_for_tait(tcx, def_id)
+            }
+            hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. } => {
+                opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id)
+            }
+            // Opaque types desugared from `impl Trait`.
+            hir::OpaqueTyOrigin::FnReturn { parent: owner, in_trait_or_impl }
+            | hir::OpaqueTyOrigin::AsyncFn { parent: owner, in_trait_or_impl } => {
+                if in_trait_or_impl == Some(hir::RpitContext::Trait)
+                    && !tcx.defaultness(owner).has_value()
+                {
+                    span_bug!(
+                        tcx.def_span(def_id),
+                        "tried to get type of this RPITIT with no definition"
+                    );
                 }
-            },
-
-            x => {
-                bug!("unexpected sort of node in type_of_opaque(): {:?}", x);
+                opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
             }
         }))
     } else {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index e7b8e6e69b0..394a263fbb5 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -13,6 +13,7 @@ use rustc_middle::ty::{
 use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
 use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations};
+use rustc_type_ir::elaborate::ClauseWithSupertraitSpan;
 use smallvec::{SmallVec, smallvec};
 use tracing::{debug, instrument};
 
@@ -124,16 +125,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             .into_iter()
             .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
 
-        for (base_trait_ref, span) in regular_traits_refs_spans {
+        for (base_trait_ref, original_span) in regular_traits_refs_spans {
             let base_pred: ty::Predicate<'tcx> = base_trait_ref.upcast(tcx);
-            for pred in traits::elaborate(tcx, [base_pred]).filter_only_self() {
+            for ClauseWithSupertraitSpan { pred, original_span, supertrait_span } in
+                traits::elaborate(tcx, [ClauseWithSupertraitSpan::new(base_pred, original_span)])
+                    .filter_only_self()
+            {
                 debug!("observing object predicate `{pred:?}`");
 
                 let bound_predicate = pred.kind();
                 match bound_predicate.skip_binder() {
                     ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
                         let pred = bound_predicate.rebind(pred);
-                        associated_types.entry(span).or_default().extend(
+                        associated_types.entry(original_span).or_default().extend(
                             tcx.associated_items(pred.def_id())
                                 .in_definition_order()
                                 .filter(|item| item.kind == ty::AssocKind::Type)
@@ -172,8 +176,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         // the discussion in #56288 for alternatives.
                         if !references_self {
                             // Include projections defined on supertraits.
-                            projection_bounds.push((pred, span));
+                            projection_bounds.push((pred, original_span));
                         }
+
+                        self.check_elaborated_projection_mentions_input_lifetimes(
+                            pred,
+                            original_span,
+                            supertrait_span,
+                        );
                     }
                     _ => (),
                 }
@@ -360,6 +370,56 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         Ty::new_dynamic(tcx, existential_predicates, region_bound, representation)
     }
+
+    /// Check that elaborating the principal of a trait ref doesn't lead to projections
+    /// that are unconstrained. This can happen because an otherwise unconstrained
+    /// *type variable* can be substituted with a type that has late-bound regions. See
+    /// `elaborated-predicates-unconstrained-late-bound.rs` for a test.
+    fn check_elaborated_projection_mentions_input_lifetimes(
+        &self,
+        pred: ty::PolyProjectionPredicate<'tcx>,
+        span: Span,
+        supertrait_span: Span,
+    ) {
+        let tcx = self.tcx();
+
+        // Find any late-bound regions declared in `ty` that are not
+        // declared in the trait-ref or assoc_item. These are not well-formed.
+        //
+        // Example:
+        //
+        //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
+        //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
+        let late_bound_in_projection_term =
+            tcx.collect_constrained_late_bound_regions(pred.map_bound(|pred| pred.projection_term));
+        let late_bound_in_term =
+            tcx.collect_referenced_late_bound_regions(pred.map_bound(|pred| pred.term));
+        debug!(?late_bound_in_projection_term);
+        debug!(?late_bound_in_term);
+
+        // FIXME: point at the type params that don't have appropriate lifetimes:
+        // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
+        //                         ----  ----     ^^^^^^^
+        // NOTE(associated_const_equality): This error should be impossible to trigger
+        //                                  with associated const equality constraints.
+        self.validate_late_bound_regions(
+            late_bound_in_projection_term,
+            late_bound_in_term,
+            |br_name| {
+                let item_name = tcx.item_name(pred.projection_def_id());
+                struct_span_code_err!(
+                    self.dcx(),
+                    span,
+                    E0582,
+                    "binding for associated type `{}` references {}, \
+                             which does not appear in the trait input types",
+                    item_name,
+                    br_name
+                )
+                .with_span_label(supertrait_span, "due to this supertrait")
+            },
+        );
+    }
 }
 
 fn replace_dummy_self_with_error<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
index a70f881f5fe..5607fe873f6 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -108,17 +108,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let tcx = self.tcx();
         let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
         if let hir::Node::Item(hir::Item {
-            kind:
-                hir::ItemKind::Impl(hir::Impl {
-                    self_ty: impl_self_ty,
-                    of_trait: Some(of_trait_ref),
-                    generics,
-                    ..
-                }),
+            kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, of_trait, generics, .. }),
             ..
         }) = tcx.hir_node_by_def_id(parent_id)
             && self_ty.hir_id == impl_self_ty.hir_id
         {
+            let Some(of_trait_ref) = of_trait else {
+                diag.span_suggestion_verbose(
+                    impl_self_ty.span.shrink_to_hi(),
+                    "you might have intended to implement this trait for a given type",
+                    format!(" for /* Type */"),
+                    Applicability::HasPlaceholders,
+                );
+                return;
+            };
             if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
                 return;
             }
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 2186952720f..28a1fc88741 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -23,7 +23,7 @@ mod lint;
 use std::slice;
 
 use rustc_ast::TraitObjectSyntax;
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::{
     Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err,
@@ -2087,23 +2087,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
                 self.lower_path(opt_self_ty, path, hir_ty.hir_id, false)
             }
-            &hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
-                let opaque_ty = tcx.hir().item(item_id);
-
-                match opaque_ty.kind {
-                    hir::ItemKind::OpaqueTy(&hir::OpaqueTy { .. }) => {
-                        let local_def_id = item_id.owner_id.def_id;
-                        // If this is an RPITIT and we are using the new RPITIT lowering scheme, we
-                        // generate the def_id of an associated type for the trait and return as
-                        // type a projection.
-                        let def_id = if in_trait {
-                            tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id()
-                        } else {
-                            local_def_id.to_def_id()
-                        };
-                        self.lower_opaque_ty(def_id, lifetimes, in_trait)
+            &hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => {
+                let local_def_id = opaque_ty.def_id;
+
+                // If this is an RPITIT and we are using the new RPITIT lowering scheme, we
+                // generate the def_id of an associated type for the trait and return as
+                // type a projection.
+                match opaque_ty.origin {
+                    hir::OpaqueTyOrigin::FnReturn {
+                        in_trait_or_impl: Some(hir::RpitContext::Trait),
+                        ..
+                    }
+                    | hir::OpaqueTyOrigin::AsyncFn {
+                        in_trait_or_impl: Some(hir::RpitContext::Trait),
+                        ..
+                    } => self.lower_opaque_ty(
+                        tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id(),
+                        lifetimes,
+                        true,
+                    ),
+                    hir::OpaqueTyOrigin::FnReturn {
+                        in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
+                        ..
+                    }
+                    | hir::OpaqueTyOrigin::AsyncFn {
+                        in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
+                        ..
+                    }
+                    | hir::OpaqueTyOrigin::TyAlias { .. } => {
+                        self.lower_opaque_ty(local_def_id.to_def_id(), lifetimes, false)
                     }
-                    ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
                 }
             }
             // If we encounter a type relative path with RTN generics, then it must have
@@ -2269,7 +2282,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     span_bug!(
                         tcx.def_span(param.def_id),
                         "only expected lifetime for opaque's own generics, got {:?}",
-                        param.kind
+                        param
                     );
                 };
                 let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else {
@@ -2394,8 +2407,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     #[instrument(level = "trace", skip(self, generate_err))]
     fn validate_late_bound_regions<'cx>(
         &'cx self,
-        constrained_regions: FxHashSet<ty::BoundRegionKind>,
-        referenced_regions: FxHashSet<ty::BoundRegionKind>,
+        constrained_regions: FxIndexSet<ty::BoundRegionKind>,
+        referenced_regions: FxIndexSet<ty::BoundRegionKind>,
         generate_err: impl Fn(&str) -> Diag<'cx>,
     ) {
         for br in referenced_regions.difference(&constrained_regions) {
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 92d85d48a42..71ee77f8f61 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -58,12 +58,10 @@ This API is completely unstable and subject to change.
 // tidy-alphabetical-start
 #![allow(internal_features)]
 #![allow(rustc::diagnostic_outside_of_impl)]
-#![allow(rustc::potential_query_instability)]
 #![allow(rustc::untranslatable_diagnostic)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs
index dbaf9c2c6f0..a0fdf95a831 100644
--- a/compiler/rustc_hir_analysis/src/variance/dump.rs
+++ b/compiler/rustc_hir_analysis/src/variance/dump.rs
@@ -1,6 +1,5 @@
 use std::fmt::Write;
 
-use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
 use rustc_middle::ty::{GenericArgs, TyCtxt};
 use rustc_span::symbol::sym;
@@ -24,18 +23,18 @@ fn format_variances(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String {
 }
 
 pub(crate) fn variances(tcx: TyCtxt<'_>) {
-    if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) {
-        for id in tcx.hir().items() {
-            let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue };
+    let crate_items = tcx.hir_crate_items(());
 
+    if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) {
+        for id in crate_items.opaques() {
             tcx.dcx().emit_err(crate::errors::VariancesOf {
-                span: tcx.def_span(id.owner_id),
-                variances: format_variances(tcx, id.owner_id.def_id),
+                span: tcx.def_span(id),
+                variances: format_variances(tcx, id),
             });
         }
     }
 
-    for id in tcx.hir().items() {
+    for id in crate_items.free_items() {
         if !tcx.has_attr(id.owner_id, sym::rustc_variance) {
             continue;
         }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 1c52283d537..9fe6a8ee342 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -96,6 +96,7 @@ impl<'a> State<'a> {
             Node::Ty(a) => self.print_type(a),
             Node::AssocItemConstraint(a) => self.print_assoc_item_constraint(a),
             Node::TraitRef(a) => self.print_trait_ref(a),
+            Node::OpaqueTy(o) => self.print_opaque_ty(o),
             Node::Pat(a) => self.print_pat(a),
             Node::PatField(a) => self.print_patfield(a),
             Node::Arm(a) => self.print_arm(a),
@@ -568,11 +569,6 @@ impl<'a> State<'a> {
                     state.print_type(ty);
                 });
             }
-            hir::ItemKind::OpaqueTy(opaque_ty) => {
-                self.print_item_type(item, opaque_ty.generics, |state| {
-                    state.print_bounds("= impl", opaque_ty.bounds)
-                });
-            }
             hir::ItemKind::Enum(ref enum_definition, params) => {
                 self.print_enum_def(enum_definition, params, item.ident.name, item.span);
             }
@@ -665,6 +661,15 @@ impl<'a> State<'a> {
         self.print_path(t.path, false);
     }
 
+    fn print_opaque_ty(&mut self, o: &hir::OpaqueTy<'_>) {
+        self.head("opaque");
+        self.print_generic_params(o.generics.params);
+        self.print_where_clause(o.generics);
+        self.word("{");
+        self.print_bounds("impl", o.bounds);
+        self.word("}");
+    }
+
     fn print_formal_generic_params(&mut self, generic_params: &[hir::GenericParam<'_>]) {
         if !generic_params.is_empty() {
             self.word("for");
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 39d430cf73b..3669100ed91 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -23,17 +23,17 @@ hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool`
 
 hir_typeck_cast_enum_drop = cannot cast enum `{$expr_ty}` into integer `{$cast_ty}` because it implements `Drop`
 
-hir_typeck_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}`
+hir_typeck_cast_thin_pointer_to_wide_pointer = cannot cast thin pointer `{$expr_ty}` to wide pointer `{$cast_ty}`
     .teach_help = Thin pointers are "simple" pointers: they are purely a reference to a
         memory address.
 
-        Fat pointers are pointers referencing "Dynamically Sized Types" (also
+        Wide pointers are pointers referencing "Dynamically Sized Types" (also
         called DST). DST don't have a statically known size, therefore they can
         only exist behind some kind of pointers that contain additional
         information. Slices and trait objects are DSTs. In the case of slices,
-        the additional information the fat pointer holds is their size.
+        the additional information the wide pointer holds is their size.
 
-        To fix this error, don't try to cast directly between thin and fat
+        To fix this error, don't try to cast directly between thin and wide
         pointers.
 
         For more information about casts, take a look at The Book:
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index bf8ed017cf7..0d9d1910ae0 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -15,7 +15,7 @@ use crate::{Diverges, Expectation, FnCtxt, Needs};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     #[instrument(skip(self), level = "debug", ret)]
-    pub fn check_match(
+    pub(crate) fn check_match(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         scrut: &'tcx hir::Expr<'tcx>,
@@ -602,7 +602,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .map(|(k, _)| (k.def_id, k.args))?,
             _ => return None,
         };
-        let hir::OpaqueTyOrigin::FnReturn(parent_def_id) = self.tcx.opaque_type_origin(def_id)
+        let hir::OpaqueTyOrigin::FnReturn { parent: parent_def_id, .. } =
+            self.tcx.opaque_type_origin(def_id)
         else {
             return None;
         };
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index fcd2940b83a..407191661a4 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -66,7 +66,7 @@ pub(crate) struct CastCheck<'tcx> {
 }
 
 /// The kind of pointer and associated metadata (thin, length or vtable) - we
-/// only allow casts between fat pointers if their metadata have the same
+/// only allow casts between wide pointers if their metadata have the same
 /// kind.
 #[derive(Debug, Copy, Clone, PartialEq, Eq, TypeVisitable, TypeFoldable)]
 enum PointerKind<'tcx> {
@@ -162,7 +162,7 @@ enum CastError<'tcx> {
         src_kind: PointerKind<'tcx>,
         dst_kind: PointerKind<'tcx>,
     },
-    /// Cast of thin to fat raw ptr (e.g., `*const () as *const [u8]`).
+    /// Cast of thin to wide raw ptr (e.g., `*const () as *const [u8]`).
     SizedUnsizedCast,
     IllegalCast,
     NeedDeref,
@@ -172,12 +172,12 @@ enum CastError<'tcx> {
     NonScalar,
     UnknownExprPtrKind,
     UnknownCastPtrKind,
-    /// Cast of int to (possibly) fat raw pointer.
+    /// Cast of int to (possibly) wide raw pointer.
     ///
     /// Argument is the specific name of the metadata in plain words, such as "a vtable"
     /// or "a length". If this argument is None, then the metadata is unknown, for example,
     /// when we're typechecking a type parameter with a ?Sized bound.
-    IntToFatCast(Option<&'static str>),
+    IntToWideCast(Option<&'static str>),
     ForeignNonExhaustiveAdt,
 }
 
@@ -545,14 +545,14 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 err.emit();
             }
             CastError::SizedUnsizedCast => {
-                fcx.dcx().emit_err(errors::CastThinPointerToFatPointer {
+                fcx.dcx().emit_err(errors::CastThinPointerToWidePointer {
                     span: self.span,
                     expr_ty: self.expr_ty,
                     cast_ty: fcx.ty_to_string(self.cast_ty),
                     teach: fcx.tcx.sess.teach(E0607),
                 });
             }
-            CastError::IntToFatCast(known_metadata) => {
+            CastError::IntToWideCast(known_metadata) => {
                 let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span);
                 let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
                 let expr_ty = fcx.ty_to_string(self.expr_ty);
@@ -671,7 +671,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
     }
 
     #[instrument(skip(fcx), level = "debug")]
-    pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
+    pub(crate) fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
         self.expr_ty = fcx.structurally_resolve_type(self.expr_span, self.expr_ty);
         self.cast_ty = fcx.structurally_resolve_type(self.cast_span, self.cast_ty);
 
@@ -861,7 +861,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             return Ok(CastKind::PtrPtrCast);
         }
 
-        // We can't cast to fat pointer if source pointer kind is unknown
+        // We can't cast to wide pointer if source pointer kind is unknown
         let Some(src_kind) = src_kind else {
             return Err(CastError::UnknownCastPtrKind);
         };
@@ -1054,10 +1054,10 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         match fcx.pointer_kind(m_cast.ty, self.span)? {
             None => Err(CastError::UnknownCastPtrKind),
             Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast),
-            Some(PointerKind::VTable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))),
-            Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))),
+            Some(PointerKind::VTable(_)) => Err(CastError::IntToWideCast(Some("a vtable"))),
+            Some(PointerKind::Length) => Err(CastError::IntToWideCast(Some("a length"))),
             Some(PointerKind::OfAlias(_) | PointerKind::OfParam(_)) => {
-                Err(CastError::IntToFatCast(None))
+                Err(CastError::IntToWideCast(None))
             }
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 3e7ce2955fc..fcaa5751152 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -44,7 +44,7 @@ struct ClosureSignatures<'tcx> {
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     #[instrument(skip(self, closure), level = "debug")]
-    pub fn check_expr_closure(
+    pub(crate) fn check_expr_closure(
         &self,
         closure: &hir::Closure<'tcx>,
         expr_span: Span,
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index fb462eec1b9..642db3f36b5 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -82,6 +82,11 @@ struct Coerce<'a, 'tcx> {
     /// See #47489 and #48598
     /// See docs on the "AllowTwoPhase" type for a more detailed discussion
     allow_two_phase: AllowTwoPhase,
+    /// Whether we allow `NeverToAny` coercions. This is unsound if we're
+    /// coercing a place expression without it counting as a read in the MIR.
+    /// This is a side-effect of HIR not really having a great distinction
+    /// between places and values.
+    coerce_never: bool,
 }
 
 impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> {
@@ -125,8 +130,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         fcx: &'f FnCtxt<'f, 'tcx>,
         cause: ObligationCause<'tcx>,
         allow_two_phase: AllowTwoPhase,
+        coerce_never: bool,
     ) -> Self {
-        Coerce { fcx, cause, allow_two_phase, use_lub: false }
+        Coerce { fcx, cause, allow_two_phase, use_lub: false, coerce_never }
     }
 
     fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
@@ -177,7 +183,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
         // Coercing from `!` to any type is allowed:
         if a.is_never() {
-            return success(simple(Adjust::NeverToAny)(b), b, vec![]);
+            if self.coerce_never {
+                return success(simple(Adjust::NeverToAny)(b), b, vec![]);
+            } else {
+                // Otherwise the only coercion we can do is unification.
+                return self.unify_and(a, b, identity);
+            }
         }
 
         // Coercing *from* an unresolved inference variable means that
@@ -1038,7 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// The expressions *must not* have any preexisting adjustments.
     pub(crate) fn coerce(
         &self,
-        expr: &hir::Expr<'_>,
+        expr: &'tcx hir::Expr<'tcx>,
         expr_ty: Ty<'tcx>,
         mut target: Ty<'tcx>,
         allow_two_phase: AllowTwoPhase,
@@ -1055,7 +1066,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let cause =
             cause.unwrap_or_else(|| self.cause(expr.span, ObligationCauseCode::ExprAssignable));
-        let coerce = Coerce::new(self, cause, allow_two_phase);
+        let coerce = Coerce::new(
+            self,
+            cause,
+            allow_two_phase,
+            self.expr_guaranteed_to_constitute_read_for_never(expr),
+        );
         let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?;
 
         let (adjustments, _) = self.register_infer_ok_obligations(ok);
@@ -1077,8 +1093,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         debug!("coercion::can_with_predicates({:?} -> {:?})", source, target);
 
         let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
-        // We don't ever need two-phase here since we throw out the result of the coercion
-        let coerce = Coerce::new(self, cause, AllowTwoPhase::No);
+        // We don't ever need two-phase here since we throw out the result of the coercion.
+        // We also just always set `coerce_never` to true, since this is a heuristic.
+        let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true);
         self.probe(|_| {
             let Ok(ok) = coerce.coerce(source, target) else {
                 return false;
@@ -1090,12 +1107,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     /// Given a type and a target type, this function will calculate and return
-    /// how many dereference steps needed to achieve `expr_ty <: target`. If
+    /// how many dereference steps needed to coerce `expr_ty` to `target`. If
     /// it's not possible, return `None`.
-    pub(crate) fn deref_steps(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> Option<usize> {
+    pub(crate) fn deref_steps_for_suggestion(
+        &self,
+        expr_ty: Ty<'tcx>,
+        target: Ty<'tcx>,
+    ) -> Option<usize> {
         let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
-        // We don't ever need two-phase here since we throw out the result of the coercion
-        let coerce = Coerce::new(self, cause, AllowTwoPhase::No);
+        // We don't ever need two-phase here since we throw out the result of the coercion.
+        let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true);
         coerce
             .autoderef(DUMMY_SP, expr_ty)
             .find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps))
@@ -1252,7 +1273,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // probably aren't processing function arguments here and even if we were,
         // they're going to get autorefed again anyway and we can apply 2-phase borrows
         // at that time.
-        let mut coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No);
+        //
+        // NOTE: we set `coerce_never` to `true` here because coercion LUBs only
+        // operate on values and not places, so a never coercion is valid.
+        let mut coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No, true);
         coerce.use_lub = true;
 
         // First try to coerce the new expression to the type of the previous ones,
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index cfa8fc4bbf2..777248ff873 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -182,7 +182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
-    pub fn demand_suptype_with_origin(
+    pub(crate) fn demand_suptype_with_origin(
         &'a self,
         cause: &ObligationCause<'tcx>,
         expected: Ty<'tcx>,
@@ -247,7 +247,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!`
     /// will be permitted if the diverges flag is currently "always".
     #[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
-    pub fn demand_coerce_diag(
+    pub(crate) fn demand_coerce_diag(
         &'a self,
         mut expr: &'tcx hir::Expr<'tcx>,
         checked_ty: Ty<'tcx>,
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index a692642ccfc..cceaabaff65 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -699,8 +699,8 @@ pub(crate) struct ReplaceWithName {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_typeck_cast_thin_pointer_to_fat_pointer, code = E0607)]
-pub(crate) struct CastThinPointerToFatPointer<'tcx> {
+#[diag(hir_typeck_cast_thin_pointer_to_wide_pointer, code = E0607)]
+pub(crate) struct CastThinPointerToWidePointer<'tcx> {
     #[primary_span]
     pub span: Span,
     pub expr_ty: Ty<'tcx>,
diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs
index 67f4dbee3cb..4653458b5dd 100644
--- a/compiler/rustc_hir_typeck/src/expectation.rs
+++ b/compiler/rustc_hir_typeck/src/expectation.rs
@@ -55,7 +55,7 @@ impl<'a, 'tcx> Expectation<'tcx> {
     /// be checked higher up, as is the case with `&expr` and `box expr`), but
     /// is useful in determining the concrete type.
     ///
-    /// The primary use case is where the expected type is a fat pointer,
+    /// The primary use case is where the expected type is a wide pointer,
     /// like `&[isize]`. For example, consider the following statement:
     ///
     ///    let x: &[isize] = &[1, 2, 3];
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index b34ed4640db..95ca3e66472 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1,3 +1,6 @@
+// ignore-tidy-filelength
+// FIXME: we should move the field error reporting code somewhere else.
+
 //! Type checking expressions.
 //!
 //! See [`rustc_hir_analysis::check`] for more context on type checking in general.
@@ -62,7 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // While we don't allow *arbitrary* coercions here, we *do* allow
         // coercions from ! to `expected`.
-        if ty.is_never() {
+        if ty.is_never() && self.expr_guaranteed_to_constitute_read_for_never(expr) {
             if let Some(_) = self.typeck_results.borrow().adjustments().get(expr.hir_id) {
                 let reported = self.dcx().span_delayed_bug(
                     expr.span,
@@ -238,8 +241,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             _ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression"),
         }
 
-        // Any expression that produces a value of type `!` must have diverged
-        if ty.is_never() {
+        // Any expression that produces a value of type `!` must have diverged,
+        // unless it's a place expression that isn't being read from, in which case
+        // diverging would be unsound since we may never actually read the `!`.
+        // e.g. `let _ = *never_ptr;` with `never_ptr: *const !`.
+        if ty.is_never() && self.expr_guaranteed_to_constitute_read_for_never(expr) {
             self.diverges.set(self.diverges.get() | Diverges::always(expr.span));
         }
 
@@ -257,6 +263,185 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ty
     }
 
+    /// Whether this expression constitutes a read of value of the type that
+    /// it evaluates to.
+    ///
+    /// This is used to determine if we should consider the block to diverge
+    /// if the expression evaluates to `!`, and if we should insert a `NeverToAny`
+    /// coercion for values of type `!`.
+    ///
+    /// This function generally returns `false` if the expression is a place
+    /// expression and the *parent* expression is the scrutinee of a match or
+    /// the pointee of an `&` addr-of expression, since both of those parent
+    /// expressions take a *place* and not a value.
+    pub(super) fn expr_guaranteed_to_constitute_read_for_never(
+        &self,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) -> bool {
+        // We only care about place exprs. Anything else returns an immediate
+        // which would constitute a read. We don't care about distinguishing
+        // "syntactic" place exprs since if the base of a field projection is
+        // not a place then it would've been UB to read from it anyways since
+        // that constitutes a read.
+        if !expr.is_syntactic_place_expr() {
+            return true;
+        }
+
+        let parent_node = self.tcx.parent_hir_node(expr.hir_id);
+        match parent_node {
+            hir::Node::Expr(parent_expr) => {
+                match parent_expr.kind {
+                    // Addr-of, field projections, and LHS of assignment don't constitute reads.
+                    // Assignment does call `drop_in_place`, though, but its safety
+                    // requirements are not the same.
+                    ExprKind::AddrOf(..) | hir::ExprKind::Field(..) => false,
+                    ExprKind::Assign(lhs, _, _) => {
+                        // Only the LHS does not constitute a read
+                        expr.hir_id != lhs.hir_id
+                    }
+
+                    // See note on `PatKind::Or` below for why this is `all`.
+                    ExprKind::Match(scrutinee, arms, _) => {
+                        assert_eq!(scrutinee.hir_id, expr.hir_id);
+                        arms.iter()
+                            .all(|arm| self.pat_guaranteed_to_constitute_read_for_never(arm.pat))
+                    }
+                    ExprKind::Let(hir::LetExpr { init, pat, .. }) => {
+                        assert_eq!(init.hir_id, expr.hir_id);
+                        self.pat_guaranteed_to_constitute_read_for_never(*pat)
+                    }
+
+                    // Any expression child of these expressions constitute reads.
+                    ExprKind::Array(_)
+                    | ExprKind::Call(_, _)
+                    | ExprKind::MethodCall(_, _, _, _)
+                    | ExprKind::Tup(_)
+                    | ExprKind::Binary(_, _, _)
+                    | ExprKind::Unary(_, _)
+                    | ExprKind::Cast(_, _)
+                    | ExprKind::Type(_, _)
+                    | ExprKind::DropTemps(_)
+                    | ExprKind::If(_, _, _)
+                    | ExprKind::Closure(_)
+                    | ExprKind::Block(_, _)
+                    | ExprKind::AssignOp(_, _, _)
+                    | ExprKind::Index(_, _, _)
+                    | ExprKind::Break(_, _)
+                    | ExprKind::Ret(_)
+                    | ExprKind::Become(_)
+                    | ExprKind::InlineAsm(_)
+                    | ExprKind::Struct(_, _, _)
+                    | ExprKind::Repeat(_, _)
+                    | ExprKind::Yield(_, _) => true,
+
+                    // These expressions have no (direct) sub-exprs.
+                    ExprKind::ConstBlock(_)
+                    | ExprKind::Loop(_, _, _, _)
+                    | ExprKind::Lit(_)
+                    | ExprKind::Path(_)
+                    | ExprKind::Continue(_)
+                    | ExprKind::OffsetOf(_, _)
+                    | ExprKind::Err(_) => unreachable!("no sub-expr expected for {:?}", expr.kind),
+                }
+            }
+
+            // If we have a subpattern that performs a read, we want to consider this
+            // to diverge for compatibility to support something like `let x: () = *never_ptr;`.
+            hir::Node::LetStmt(hir::LetStmt { init: Some(target), pat, .. }) => {
+                assert_eq!(target.hir_id, expr.hir_id);
+                self.pat_guaranteed_to_constitute_read_for_never(*pat)
+            }
+
+            // These nodes (if they have a sub-expr) do constitute a read.
+            hir::Node::Block(_)
+            | hir::Node::Arm(_)
+            | hir::Node::ExprField(_)
+            | hir::Node::AnonConst(_)
+            | hir::Node::ConstBlock(_)
+            | hir::Node::ConstArg(_)
+            | hir::Node::Stmt(_)
+            | hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..),
+                ..
+            })
+            | hir::Node::TraitItem(hir::TraitItem {
+                kind: hir::TraitItemKind::Const(..), ..
+            })
+            | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => true,
+
+            // These nodes do not have direct sub-exprs.
+            hir::Node::Param(_)
+            | hir::Node::Item(_)
+            | hir::Node::ForeignItem(_)
+            | hir::Node::TraitItem(_)
+            | hir::Node::ImplItem(_)
+            | hir::Node::Variant(_)
+            | hir::Node::Field(_)
+            | hir::Node::PathSegment(_)
+            | hir::Node::Ty(_)
+            | hir::Node::AssocItemConstraint(_)
+            | hir::Node::TraitRef(_)
+            | hir::Node::Pat(_)
+            | hir::Node::PatField(_)
+            | hir::Node::LetStmt(_)
+            | hir::Node::Synthetic
+            | hir::Node::Err(_)
+            | hir::Node::Ctor(_)
+            | hir::Node::Lifetime(_)
+            | hir::Node::GenericParam(_)
+            | hir::Node::Crate(_)
+            | hir::Node::Infer(_)
+            | hir::Node::WhereBoundPredicate(_)
+            | hir::Node::ArrayLenInfer(_)
+            | hir::Node::PreciseCapturingNonLifetimeArg(_)
+            | hir::Node::OpaqueTy(_) => {
+                unreachable!("no sub-expr expected for {parent_node:?}")
+            }
+        }
+    }
+
+    /// Whether this pattern constitutes a read of value of the scrutinee that
+    /// it is matching against. This is used to determine whether we should
+    /// perform `NeverToAny` coercions.
+    ///
+    /// See above for the nuances of what happens when this returns true.
+    pub(super) fn pat_guaranteed_to_constitute_read_for_never(&self, pat: &hir::Pat<'_>) -> bool {
+        match pat.kind {
+            // Does not constitute a read.
+            hir::PatKind::Wild => false,
+
+            // This is unnecessarily restrictive when the pattern that doesn't
+            // constitute a read is unreachable.
+            //
+            // For example `match *never_ptr { value => {}, _ => {} }` or
+            // `match *never_ptr { _ if false => {}, value => {} }`.
+            //
+            // It is however fine to be restrictive here; only returning `true`
+            // can lead to unsoundness.
+            hir::PatKind::Or(subpats) => {
+                subpats.iter().all(|pat| self.pat_guaranteed_to_constitute_read_for_never(pat))
+            }
+
+            // Does constitute a read, since it is equivalent to a discriminant read.
+            hir::PatKind::Never => true,
+
+            // All of these constitute a read, or match on something that isn't `!`,
+            // which would require a `NeverToAny` coercion.
+            hir::PatKind::Binding(_, _, _, _)
+            | hir::PatKind::Struct(_, _, _)
+            | hir::PatKind::TupleStruct(_, _, _)
+            | hir::PatKind::Path(_)
+            | hir::PatKind::Tuple(_, _)
+            | hir::PatKind::Box(_)
+            | hir::PatKind::Ref(_, _)
+            | hir::PatKind::Deref(_)
+            | hir::PatKind::Lit(_)
+            | hir::PatKind::Range(_, _, _)
+            | hir::PatKind::Slice(_, _, _)
+            | hir::PatKind::Err(_) => true,
+        }
+    }
+
     #[instrument(skip(self, expr), level = "debug")]
     fn check_expr_kind(
         &self,
@@ -413,7 +598,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => {
                     if oprnd.is_syntactic_place_expr() {
                         // Places may legitimately have unsized types.
-                        // For example, dereferences of a fat pointer and
+                        // For example, dereferences of a wide pointer and
                         // the last field of a struct can be unsized.
                         ExpectHasType(*ty)
                     } else {
@@ -3322,7 +3507,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> {
-        let mut diverge = asm.options.contains(ast::InlineAsmOptions::NORETURN);
+        let mut diverge = asm.asm_macro.diverges(asm.options);
 
         for (op, _op_sp) in asm.operands {
             match op {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 62107877283..380d9126964 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -187,7 +187,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    pub fn write_method_call_and_enforce_effects(
+    pub(crate) fn write_method_call_and_enforce_effects(
         &self,
         hir_id: HirId,
         span: Span,
@@ -214,7 +214,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// occurred**, so that annotations like `Vec<_>` are preserved
     /// properly.
     #[instrument(skip(self), level = "debug")]
-    pub fn write_user_type_annotation_from_args(
+    pub(crate) fn write_user_type_annotation_from_args(
         &self,
         hir_id: HirId,
         def_id: DefId,
@@ -235,7 +235,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
-    pub fn write_user_type_annotation(
+    pub(crate) fn write_user_type_annotation(
         &self,
         hir_id: HirId,
         canonical_user_type_annotation: CanonicalUserType<'tcx>,
@@ -254,7 +254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(skip(self, expr), level = "debug")]
-    pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) {
+    pub(crate) fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) {
         debug!("expr = {:#?}", expr);
 
         if adj.is_empty() {
@@ -448,7 +448,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip_all)]
-    pub fn lower_ty_saving_user_provided_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
+    pub(crate) fn lower_ty_saving_user_provided_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
         let ty = self.lower_ty(hir_ty);
         debug!(?ty);
 
@@ -736,7 +736,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Resolves an associated value path into a base type and associated constant, or method
     /// resolution. The newly resolved definition is written into `type_dependent_defs`.
     #[instrument(level = "trace", skip(self), ret)]
-    pub fn resolve_ty_and_res_fully_qualified_call(
+    pub(crate) fn resolve_ty_and_res_fully_qualified_call(
         &self,
         qpath: &'tcx QPath<'tcx>,
         hir_id: HirId,
@@ -995,7 +995,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     // Instantiates the given path, which must refer to an item with the given
     // number of type parameters and type.
     #[instrument(skip(self, span), level = "debug")]
-    pub fn instantiate_value_path(
+    pub(crate) fn instantiate_value_path(
         &self,
         segments: &'tcx [hir::PathSegment<'tcx>],
         self_ty: Option<LoweredTy<'tcx>>,
@@ -1446,7 +1446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// variable. This is different from `structurally_resolve_type` which errors
     /// in this case.
     #[instrument(level = "debug", skip(self, sp), ret)]
-    pub fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+    pub(crate) fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
         let ty = self.resolve_vars_with_obligations(ty);
 
         if self.next_trait_solver()
@@ -1471,7 +1471,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self, sp), ret)]
-    pub fn try_structurally_resolve_const(&self, sp: Span, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+    pub(crate) fn try_structurally_resolve_const(
+        &self,
+        sp: Span,
+        ct: ty::Const<'tcx>,
+    ) -> ty::Const<'tcx> {
         // FIXME(min_const_generic_exprs): We could process obligations here if `ct` is a var.
 
         if self.next_trait_solver()
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 550c58b5a17..fa471647d02 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -984,7 +984,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             self.suggest_deref_unwrap_or(
                 &mut err,
-                error_span,
                 callee_ty,
                 call_ident,
                 expected_ty,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 487cc7e55cd..1df4d32f3cb 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -847,11 +847,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return true;
             }
             hir::FnRetTy::Return(hir_ty) => {
-                if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind
+                if let hir::TyKind::OpaqueDef(op_ty, ..) = hir_ty.kind
                     // FIXME: account for RPITIT.
-                    && let hir::Node::Item(hir::Item {
-                        kind: hir::ItemKind::OpaqueTy(op_ty), ..
-                    }) = self.tcx.hir_node(item_id.hir_id())
                     && let [hir::GenericBound::Trait(trait_ref, _)] = op_ty.bounds
                     && let Some(hir::PathSegment { args: Some(generic_args), .. }) =
                         trait_ref.trait_ref.path.segments.last()
@@ -1462,7 +1459,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(crate) fn suggest_deref_unwrap_or(
         &self,
         err: &mut Diag<'_>,
-        error_span: Span,
         callee_ty: Option<Ty<'tcx>>,
         call_ident: Option<Ident>,
         expected_ty: Ty<'tcx>,
@@ -2612,7 +2608,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
 
                     if let hir::ExprKind::Unary(hir::UnOp::Deref, inner) = expr.kind
-                        && let Some(1) = self.deref_steps(expected, checked_ty)
+                        && let Some(1) = self.deref_steps_for_suggestion(expected, checked_ty)
                     {
                         // We have `*&T`, check if what was expected was `&T`.
                         // If so, we may want to suggest removing a `*`.
@@ -2742,7 +2738,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             (_, &ty::RawPtr(ty_b, mutbl_b), &ty::Ref(_, ty_a, mutbl_a)) => {
-                if let Some(steps) = self.deref_steps(ty_a, ty_b)
+                if let Some(steps) = self.deref_steps_for_suggestion(ty_a, ty_b)
                     // Only suggest valid if dereferencing needed.
                     && steps > 0
                     // The pointer type implements `Copy` trait so the suggestion is always valid.
@@ -2786,7 +2782,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             _ if sp == expr.span => {
-                if let Some(mut steps) = self.deref_steps(checked_ty, expected) {
+                if let Some(mut steps) = self.deref_steps_for_suggestion(checked_ty, expected) {
                     let mut expr = expr.peel_blocks();
                     let mut prefix_span = expr.span.shrink_to_lo();
                     let mut remove = String::new();
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index f8352d9d44a..6b0a897faba 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -3,7 +3,6 @@
 #![allow(rustc::untranslatable_diagnostic)]
 #![feature(array_windows)]
 #![feature(box_patterns)]
-#![feature(control_flow_enum)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(never_type)]
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 72842075fec..1d7b3433fe5 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -235,6 +235,23 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                     target,
                 });
             }
+
+            Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => {
+                let region = self.next_region_var(infer::Autoref(self.span));
+
+                target = match target.kind() {
+                    ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => {
+                        let inner_ty = match args[0].expect_ty().kind() {
+                            ty::Ref(_, ty, _) => *ty,
+                            _ => bug!("Expected a reference type for argument to Pin"),
+                        };
+                        Ty::new_pinned_ref(self.tcx, region, inner_ty, mutbl)
+                    }
+                    _ => bug!("Cannot adjust receiver type for reborrowing pin of {target:?}"),
+                };
+
+                adjustments.push(Adjustment { kind: Adjust::ReborrowPin(region, mutbl), target });
+            }
             None => {}
         }
 
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 586b753f454..cb8b1df2c6e 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -18,8 +18,8 @@ use rustc_middle::ty::{
     self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TypeVisitableExt,
 };
 use rustc_middle::{bug, span_bug};
-use rustc_span::Span;
 use rustc_span::symbol::Ident;
+use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{self, NormalizeExt};
 use tracing::{debug, instrument};
@@ -46,17 +46,17 @@ pub(crate) struct MethodCallee<'tcx> {
 
 #[derive(Debug)]
 pub(crate) enum MethodError<'tcx> {
-    // Did not find an applicable method, but we did find various near-misses that may work.
+    /// Did not find an applicable method, but we did find various near-misses that may work.
     NoMatch(NoMatchData<'tcx>),
 
-    // Multiple methods might apply.
+    /// Multiple methods might apply.
     Ambiguity(Vec<CandidateSource>),
 
-    // Found an applicable method, but it is not visible. The third argument contains a list of
-    // not-in-scope traits which may work.
+    /// Found an applicable method, but it is not visible. The third argument contains a list of
+    /// not-in-scope traits which may work.
     PrivateMatch(DefKind, DefId, Vec<DefId>),
 
-    // Found a `Self: Sized` bound where `Self` is a trait object.
+    /// Found a `Self: Sized` bound where `Self` is a trait object.
     IllegalSizedBound {
         candidates: Vec<DefId>,
         needs_mut: bool,
@@ -64,8 +64,11 @@ pub(crate) enum MethodError<'tcx> {
         self_expr: &'tcx hir::Expr<'tcx>,
     },
 
-    // Found a match, but the return type is wrong
+    /// Found a match, but the return type is wrong
     BadReturnType,
+
+    /// Error has already been emitted, no need to emit another one.
+    ErrorReported(ErrorGuaranteed),
 }
 
 // Contains a list of static methods that may apply, a list of unsatisfied trait predicates which
@@ -91,7 +94,7 @@ pub(crate) enum CandidateSource {
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Determines whether the type `self_ty` supports a visible method named `method_name` or not.
     #[instrument(level = "debug", skip(self))]
-    pub fn method_exists_for_diagnostic(
+    pub(crate) fn method_exists_for_diagnostic(
         &self,
         method_name: Ident,
         self_ty: Ty<'tcx>,
@@ -120,6 +123,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Err(PrivateMatch(..)) => false,
             Err(IllegalSizedBound { .. }) => true,
             Err(BadReturnType) => false,
+            Err(ErrorReported(_)) => false,
         }
     }
 
@@ -174,7 +178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// * `self_expr`:             the self expression (`foo`)
     /// * `args`:                  the expressions of the arguments (`a, b + 1, ...`)
     #[instrument(level = "debug", skip(self))]
-    pub fn lookup_method(
+    pub(crate) fn lookup_method(
         &self,
         self_ty: Ty<'tcx>,
         segment: &'tcx hir::PathSegment<'tcx>,
@@ -277,7 +281,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self, call_expr))]
-    pub fn lookup_probe(
+    pub(crate) fn lookup_probe(
         &self,
         method_name: Ident,
         self_ty: Ty<'tcx>,
@@ -494,7 +498,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// * `self_ty_span`           the span for the type being searched within (span of `Foo`)
     /// * `expr_id`:               the [`hir::HirId`] of the expression composing the entire call
     #[instrument(level = "debug", skip(self), ret)]
-    pub fn resolve_fully_qualified_call(
+    pub(crate) fn resolve_fully_qualified_call(
         &self,
         span: Span,
         method_name: Ident,
diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
index a8b5b6165db..b20592c85d2 100644
--- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
@@ -121,16 +121,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             mutbl.ref_prefix_str()
                         }
                         Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
+                        Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl {
+                            hir::Mutability::Mut => "Pin<&mut ",
+                            hir::Mutability::Not => "Pin<&",
+                        },
                     };
                     if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
                     {
-                        let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
+                        let mut self_adjusted =
+                            if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
+                                pick.autoref_or_ptr_adjustment
+                            {
+                                format!("{derefs}{self_expr} as *const _")
+                            } else {
+                                format!("{autoref}{derefs}{self_expr}")
+                            };
+
+                        if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) =
                             pick.autoref_or_ptr_adjustment
                         {
-                            format!("{derefs}{self_expr} as *const _")
-                        } else {
-                            format!("{autoref}{derefs}{self_expr}")
-                        };
+                            self_adjusted.push('>');
+                        }
 
                         lint.span_suggestion(
                             sp,
@@ -400,6 +411,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let autoref = match pick.autoref_or_ptr_adjustment {
             Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => mutbl.ref_prefix_str(),
             Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
+            Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl {
+                hir::Mutability::Mut => "Pin<&mut ",
+                hir::Mutability::Not => "Pin<&",
+            },
         };
 
         let (expr_text, precise) = if let Some(expr_text) = expr
@@ -412,7 +427,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ("(..)".to_string(), false)
         };
 
-        let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
+        let mut adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
             pick.autoref_or_ptr_adjustment
         {
             format!("{derefs}{expr_text} as *const _")
@@ -420,6 +435,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             format!("{autoref}{derefs}{expr_text}")
         };
 
+        if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) = pick.autoref_or_ptr_adjustment
+        {
+            adjusted_text.push('>');
+        }
+
         (adjusted_text, precise)
     }
 }
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 371380e575d..ba6bfd3a5e9 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -136,7 +136,7 @@ enum ProbeResult {
 /// `mut`), or it has type `*mut T` and we convert it to `*const T`.
 #[derive(Debug, PartialEq, Copy, Clone)]
 pub(crate) enum AutorefOrPtrAdjustment {
-    /// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it.
+    /// Receiver has type `T`, add `&` or `&mut` (if `T` is `mut`), and maybe also "unsize" it.
     /// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing.
     Autoref {
         mutbl: hir::Mutability,
@@ -147,6 +147,9 @@ pub(crate) enum AutorefOrPtrAdjustment {
     },
     /// Receiver has type `*mut T`, convert to `*const T`
     ToConstPtr,
+
+    /// Reborrow a `Pin<&mut T>` or `Pin<&T>`.
+    ReborrowPin(hir::Mutability),
 }
 
 impl AutorefOrPtrAdjustment {
@@ -154,6 +157,7 @@ impl AutorefOrPtrAdjustment {
         match self {
             AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize,
             AutorefOrPtrAdjustment::ToConstPtr => false,
+            AutorefOrPtrAdjustment::ReborrowPin(_) => false,
         }
     }
 }
@@ -224,7 +228,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// would use to decide if a method is a plausible fit for
     /// ambiguity purposes).
     #[instrument(level = "debug", skip(self, candidate_filter))]
-    pub fn probe_for_return_type_for_diagnostic(
+    pub(crate) fn probe_for_return_type_for_diagnostic(
         &self,
         span: Span,
         mode: Mode,
@@ -267,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    pub fn probe_for_name(
+    pub(crate) fn probe_for_name(
         &self,
         mode: Mode,
         item_name: Ident,
@@ -446,13 +450,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     _ => bug!("unexpected bad final type in method autoderef"),
                 };
                 self.demand_eqtype(span, ty, Ty::new_error(self.tcx, guar));
-                return Err(MethodError::NoMatch(NoMatchData {
-                    static_candidates: Vec::new(),
-                    unsatisfied_predicates: Vec::new(),
-                    out_of_scope_traits: Vec::new(),
-                    similar_candidate: None,
-                    mode,
-                }));
+                return Err(MethodError::ErrorReported(guar));
             }
         }
 
@@ -1109,6 +1107,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                                 unstable_candidates.as_deref_mut(),
                             )
                         })
+                        .or_else(|| {
+                            self.pick_reborrow_pin_method(
+                                step,
+                                self_ty,
+                                unstable_candidates.as_deref_mut(),
+                            )
+                        })
                     })
             })
     }
@@ -1133,13 +1138,28 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
 
-                // Insert a `&*` or `&mut *` if this is a reference type:
-                if let ty::Ref(_, _, mutbl) = *step.self_ty.value.value.kind() {
-                    pick.autoderefs += 1;
-                    pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
-                        mutbl,
-                        unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()),
-                    })
+                match *step.self_ty.value.value.kind() {
+                    // Insert a `&*` or `&mut *` if this is a reference type:
+                    ty::Ref(_, _, mutbl) => {
+                        pick.autoderefs += 1;
+                        pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
+                            mutbl,
+                            unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()),
+                        })
+                    }
+
+                    ty::Adt(def, args)
+                        if self.tcx.features().pin_ergonomics
+                            && self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) =>
+                    {
+                        // make sure this is a pinned reference (and not a `Pin<Box>` or something)
+                        if let ty::Ref(_, _, mutbl) = args[0].expect_ty().kind() {
+                            pick.autoref_or_ptr_adjustment =
+                                Some(AutorefOrPtrAdjustment::ReborrowPin(*mutbl));
+                        }
+                    }
+
+                    _ => (),
                 }
 
                 pick
@@ -1170,6 +1190,43 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         })
     }
 
+    /// Looks for applicable methods if we reborrow a `Pin<&mut T>` as a `Pin<&T>`.
+    #[instrument(level = "debug", skip(self, step, unstable_candidates))]
+    fn pick_reborrow_pin_method(
+        &self,
+        step: &CandidateStep<'tcx>,
+        self_ty: Ty<'tcx>,
+        unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+    ) -> Option<PickResult<'tcx>> {
+        if !self.tcx.features().pin_ergonomics {
+            return None;
+        }
+
+        // make sure self is a Pin<&mut T>
+        let inner_ty = match self_ty.kind() {
+            ty::Adt(def, args) if self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => {
+                match args[0].expect_ty().kind() {
+                    ty::Ref(_, ty, hir::Mutability::Mut) => *ty,
+                    _ => {
+                        return None;
+                    }
+                }
+            }
+            _ => return None,
+        };
+
+        let region = self.tcx.lifetimes.re_erased;
+        let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not);
+        self.pick_method(autopin_ty, unstable_candidates).map(|r| {
+            r.map(|mut pick| {
+                pick.autoderefs = step.autoderefs;
+                pick.autoref_or_ptr_adjustment =
+                    Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not));
+                pick
+            })
+        })
+    }
+
     /// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a
     /// special case for this is because going from `*mut T` to `*const T` with autoderefs and
     /// autorefs would require dereferencing the pointer, which is not safe.
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index e03be4f43f7..4f726f3ed38 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -183,7 +183,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    pub fn report_method_error(
+    pub(crate) fn report_method_error(
         &self,
         call_id: HirId,
         rcvr_ty: Ty<'tcx>,
@@ -229,20 +229,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         match error {
-            MethodError::NoMatch(mut no_match_data) => {
-                return self.report_no_match_method_error(
-                    span,
-                    rcvr_ty,
-                    item_name,
-                    call_id,
-                    source,
-                    args,
-                    sugg_span,
-                    &mut no_match_data,
-                    expected,
-                    trait_missing_method,
-                );
-            }
+            MethodError::NoMatch(mut no_match_data) => self.report_no_match_method_error(
+                span,
+                rcvr_ty,
+                item_name,
+                call_id,
+                source,
+                args,
+                sugg_span,
+                &mut no_match_data,
+                expected,
+                trait_missing_method,
+            ),
 
             MethodError::Ambiguity(mut sources) => {
                 let mut err = struct_span_code_err!(
@@ -263,7 +261,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     &mut sources,
                     Some(sugg_span),
                 );
-                return err.emit();
+                err.emit()
             }
 
             MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
@@ -284,7 +282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .unwrap_or_else(|| self.tcx.def_span(def_id));
                 err.span_label(sp, format!("private {kind} defined here"));
                 self.suggest_valid_traits(&mut err, item_name, out_of_scope_traits, true);
-                return err.emit();
+                err.emit()
             }
 
             MethodError::IllegalSizedBound { candidates, needs_mut, bound_span, self_expr } => {
@@ -383,9 +381,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         }
                     }
                 }
-                return err.emit();
+                err.emit()
             }
 
+            MethodError::ErrorReported(guar) => guar,
+
             MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"),
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index c5843b883a1..63cf483aa22 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -1369,13 +1369,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         for (&var_hir_id, _) in upvars.iter() {
             let mut diagnostics_info = Vec::new();
 
-            let auto_trait_diagnostic = if let Some(diagnostics_info) =
-                self.compute_2229_migrations_for_trait(min_captures, var_hir_id, closure_clause)
-            {
-                diagnostics_info
-            } else {
-                FxIndexMap::default()
-            };
+            let auto_trait_diagnostic = self
+                .compute_2229_migrations_for_trait(min_captures, var_hir_id, closure_clause)
+                .unwrap_or_default();
 
             let drop_reorder_diagnostic = if let Some(diagnostics_info) = self
                 .compute_2229_migrations_for_drop(
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors.rs
index 76ea9c3433d..76ea9c3433d 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors.rs
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 6ce47db8b9b..183973af4f9 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -82,7 +82,6 @@ impl<'tcx> InferCtxt<'tcx> {
             reported_trait_errors: self.reported_trait_errors.clone(),
             reported_signature_mismatch: self.reported_signature_mismatch.clone(),
             tainted_by_errors: self.tainted_by_errors.clone(),
-            err_count_on_creation: self.err_count_on_creation,
             universe: self.universe.clone(),
             intercrate,
             next_trait_solver: self.next_trait_solver,
@@ -382,21 +381,7 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
                 (GenericArgKind::Const(a), GenericArgKind::Const(b)) => {
                     ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into()))
                 }
-
-                (
-                    GenericArgKind::Lifetime(_),
-                    GenericArgKind::Type(_) | GenericArgKind::Const(_),
-                )
-                | (
-                    GenericArgKind::Type(_),
-                    GenericArgKind::Lifetime(_) | GenericArgKind::Const(_),
-                )
-                | (
-                    GenericArgKind::Const(_),
-                    GenericArgKind::Lifetime(_) | GenericArgKind::Type(_),
-                ) => {
-                    bug!("relating different kinds: {a:?} {b:?}")
-                }
+                _ => bug!("relating different kinds: {a:?} {b:?}"),
             },
         }
     }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 5fa1bf51634..e7bd2562a4f 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -14,7 +14,8 @@ use region_constraints::{
     GenericKind, RegionConstraintCollector, RegionConstraintStorage, VarInfos, VerifyBound,
 };
 pub use relate::StructurallyRelateAliases;
-pub use relate::combine::{CombineFields, PredicateEmittingRelation};
+use relate::combine::CombineFields;
+pub use relate::combine::PredicateEmittingRelation;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::sync::Lrc;
@@ -50,23 +51,22 @@ use snapshot::undo_log::InferCtxtUndoLogs;
 use tracing::{debug, instrument};
 use type_variable::TypeVariableOrigin;
 
-use crate::infer::relate::RelateResult;
 use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine};
 
 pub mod at;
 pub mod canonical;
 mod context;
-pub mod free_regions;
+mod free_regions;
 mod freshen;
 mod lexical_region_resolve;
-pub mod opaque_types;
+mod opaque_types;
 pub mod outlives;
 mod projection;
 pub mod region_constraints;
 pub mod relate;
 pub mod resolve;
 pub(crate) mod snapshot;
-pub mod type_variable;
+mod type_variable;
 
 #[must_use]
 #[derive(Debug)]
@@ -76,8 +76,7 @@ pub struct InferOk<'tcx, T> {
 }
 pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>;
 
-pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
-pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
+pub(crate) type FixupResult<T> = Result<T, FixupError>; // "fixup result"
 
 pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable<
     ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut InferCtxtUndoLogs<'tcx>>,
@@ -202,7 +201,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
     }
 
     #[inline]
-    pub fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> {
+    fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> {
         self.opaque_type_storage.with_log(&mut self.undo_log)
     }
 
@@ -280,27 +279,14 @@ pub struct InferCtxt<'tcx> {
     pub reported_signature_mismatch: RefCell<FxHashSet<(Span, Option<Span>)>>,
 
     /// When an error occurs, we want to avoid reporting "derived"
-    /// errors that are due to this original failure. Normally, we
-    /// handle this with the `err_count_on_creation` count, which
-    /// basically just tracks how many errors were reported when we
-    /// started type-checking a fn and checks to see if any new errors
-    /// have been reported since then. Not great, but it works.
-    ///
-    /// However, when errors originated in other passes -- notably
-    /// resolve -- this heuristic breaks down. Therefore, we have this
-    /// auxiliary flag that one can set whenever one creates a
-    /// type-error that is due to an error in a prior pass.
+    /// errors that are due to this original failure. We have this
+    /// flag that one can set whenever one creates a type-error that
+    /// is due to an error in a prior pass.
     ///
     /// Don't read this flag directly, call `is_tainted_by_errors()`
     /// and `set_tainted_by_errors()`.
     tainted_by_errors: Cell<Option<ErrorGuaranteed>>,
 
-    /// Track how many errors were reported when this infcx is created.
-    /// If the number of errors increases, that's also a sign (like
-    /// `tainted_by_errors`) to avoid reporting certain kinds of errors.
-    // FIXME(matthewjasper) Merge into `tainted_by_errors`
-    err_count_on_creation: usize,
-
     /// What is the innermost universe we have created? Starts out as
     /// `UniverseIndex::root()` but grows from there as we enter
     /// universal quantifiers.
@@ -509,46 +495,41 @@ pub enum NllRegionVariableOrigin {
     },
 }
 
-// FIXME(eddyb) investigate overlap between this and `TyOrConstInferVar`.
 #[derive(Copy, Clone, Debug)]
-pub enum FixupError {
-    UnresolvedIntTy(IntVid),
-    UnresolvedFloatTy(FloatVid),
-    UnresolvedTy(TyVid),
-    UnresolvedConst(ConstVid),
-    UnresolvedEffect(EffectVid),
-}
-
-/// See the `region_obligations` field for more information.
-#[derive(Clone, Debug)]
-pub struct RegionObligation<'tcx> {
-    pub sub_region: ty::Region<'tcx>,
-    pub sup_type: Ty<'tcx>,
-    pub origin: SubregionOrigin<'tcx>,
+pub struct FixupError {
+    unresolved: TyOrConstInferVar,
 }
 
 impl fmt::Display for FixupError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use self::FixupError::*;
+        use TyOrConstInferVar::*;
 
-        match *self {
-            UnresolvedIntTy(_) => write!(
+        match self.unresolved {
+            TyInt(_) => write!(
                 f,
                 "cannot determine the type of this integer; \
                  add a suffix to specify the type explicitly"
             ),
-            UnresolvedFloatTy(_) => write!(
+            TyFloat(_) => write!(
                 f,
                 "cannot determine the type of this number; \
                  add a suffix to specify the type explicitly"
             ),
-            UnresolvedTy(_) => write!(f, "unconstrained type"),
-            UnresolvedConst(_) => write!(f, "unconstrained const value"),
-            UnresolvedEffect(_) => write!(f, "unconstrained effect value"),
+            Ty(_) => write!(f, "unconstrained type"),
+            Const(_) => write!(f, "unconstrained const value"),
+            Effect(_) => write!(f, "unconstrained effect value"),
         }
     }
 }
 
+/// See the `region_obligations` field for more information.
+#[derive(Clone, Debug)]
+pub struct RegionObligation<'tcx> {
+    pub sub_region: ty::Region<'tcx>,
+    pub sup_type: Ty<'tcx>,
+    pub origin: SubregionOrigin<'tcx>,
+}
+
 /// Used to configure inference contexts before their creation.
 pub struct InferCtxtBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -588,14 +569,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
         self
     }
 
-    pub fn with_defining_opaque_types(
-        mut self,
-        defining_opaque_types: &'tcx ty::List<LocalDefId>,
-    ) -> Self {
-        self.defining_opaque_types = defining_opaque_types;
-        self
-    }
-
     pub fn with_next_trait_solver(mut self, next_trait_solver: bool) -> Self {
         self.next_trait_solver = next_trait_solver;
         self
@@ -624,14 +597,15 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
     /// the bound values in `C` to their instantiated values in `V`
     /// (in other words, `S(C) = V`).
     pub fn build_with_canonical<T>(
-        self,
+        mut self,
         span: Span,
         canonical: &Canonical<'tcx, T>,
     ) -> (InferCtxt<'tcx>, T, CanonicalVarValues<'tcx>)
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
-        let infcx = self.with_defining_opaque_types(canonical.defining_opaque_types).build();
+        self.defining_opaque_types = canonical.defining_opaque_types;
+        let infcx = self.build();
         let (value, args) = infcx.instantiate_canonical(span, canonical);
         (infcx, value, args)
     }
@@ -657,7 +631,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
             reported_trait_errors: Default::default(),
             reported_signature_mismatch: Default::default(),
             tainted_by_errors: Cell::new(None),
-            err_count_on_creation: tcx.dcx().err_count_excluding_lint_errs(),
             universe: Cell::new(ty::UniverseIndex::ROOT),
             intercrate,
             next_trait_solver,
@@ -776,7 +749,7 @@ impl<'tcx> InferCtxt<'tcx> {
         definition_span: Span,
         hidden_ty: Ty<'tcx>,
         region: ty::Region<'tcx>,
-        in_regions: &Lrc<Vec<ty::Region<'tcx>>>,
+        in_regions: Lrc<Vec<ty::Region<'tcx>>>,
     ) {
         self.inner.borrow_mut().unwrap_region_constraints().member_constraint(
             key,
@@ -919,28 +892,16 @@ impl<'tcx> InferCtxt<'tcx> {
         ty::Const::new_var(self.tcx, vid)
     }
 
-    pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid {
-        self.inner
-            .borrow_mut()
-            .const_unification_table()
-            .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() })
-            .vid
-    }
-
-    fn next_int_var_id(&self) -> IntVid {
-        self.inner.borrow_mut().int_unification_table().new_key(ty::IntVarValue::Unknown)
-    }
-
     pub fn next_int_var(&self) -> Ty<'tcx> {
-        Ty::new_int_var(self.tcx, self.next_int_var_id())
-    }
-
-    fn next_float_var_id(&self) -> FloatVid {
-        self.inner.borrow_mut().float_unification_table().new_key(ty::FloatVarValue::Unknown)
+        let next_int_var_id =
+            self.inner.borrow_mut().int_unification_table().new_key(ty::IntVarValue::Unknown);
+        Ty::new_int_var(self.tcx, next_int_var_id)
     }
 
     pub fn next_float_var(&self) -> Ty<'tcx> {
-        Ty::new_float_var(self.tcx, self.next_float_var_id())
+        let next_float_var_id =
+            self.inner.borrow_mut().float_unification_table().new_key(ty::FloatVarValue::Unknown);
+        Ty::new_float_var(self.tcx, next_float_var_id)
     }
 
     /// Creates a fresh region variable with the next available index.
@@ -1353,7 +1314,7 @@ impl<'tcx> InferCtxt<'tcx> {
     }
 
     /// See the [`region_constraints::RegionConstraintCollector::verify_generic_bound`] method.
-    pub fn verify_generic_bound(
+    pub(crate) fn verify_generic_bound(
         &self,
         origin: SubregionOrigin<'tcx>,
         kind: GenericKind<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index 55c51bc856f..5a2ffbf029e 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -13,16 +13,15 @@ use rustc_middle::ty::{
 use rustc_span::Span;
 use tracing::{debug, instrument};
 
+use super::DefineOpaqueTypes;
 use crate::errors::OpaqueHiddenTypeDiag;
 use crate::infer::{InferCtxt, InferOk};
 use crate::traits::{self, Obligation};
 
 mod table;
 
-pub type OpaqueTypeMap<'tcx> = FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
-pub use table::{OpaqueTypeStorage, OpaqueTypeTable};
-
-use super::DefineOpaqueTypes;
+pub(crate) type OpaqueTypeMap<'tcx> = FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
+pub(crate) use table::{OpaqueTypeStorage, OpaqueTypeTable};
 
 /// Information about the opaque types whose values we
 /// are inferring in this function (these are the `impl Trait` that
@@ -359,7 +358,15 @@ impl<'tcx> InferCtxt<'tcx> {
         // not currently sound until we have existential regions.
         concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
             tcx: self.tcx,
-            op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions),
+            op: |r| {
+                self.member_constraint(
+                    opaque_type_key,
+                    span,
+                    concrete_ty,
+                    r,
+                    choice_regions.clone(),
+                )
+            },
         });
     }
 }
@@ -377,9 +384,9 @@ impl<'tcx> InferCtxt<'tcx> {
 ///
 /// We ignore any type parameters because impl trait values are assumed to
 /// capture all the in-scope type parameters.
-pub struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> {
-    pub tcx: TyCtxt<'tcx>,
-    pub op: OP,
+struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> {
+    tcx: TyCtxt<'tcx>,
+    op: OP,
 }
 
 impl<'tcx, OP> TypeVisitor<TyCtxt<'tcx>> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
@@ -455,20 +462,6 @@ where
     }
 }
 
-pub enum UseKind {
-    DefiningUse,
-    OpaqueUse,
-}
-
-impl UseKind {
-    pub fn is_defining(self) -> bool {
-        match self {
-            UseKind::DefiningUse => true,
-            UseKind::OpaqueUse => false,
-        }
-    }
-}
-
 impl<'tcx> InferCtxt<'tcx> {
     #[instrument(skip(self), level = "debug")]
     fn register_hidden_type(
diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs
index 4aa2ccab0e7..047d8edad3d 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/table.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs
@@ -7,7 +7,7 @@ use super::{OpaqueTypeDecl, OpaqueTypeMap};
 use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog};
 
 #[derive(Default, Debug, Clone)]
-pub struct OpaqueTypeStorage<'tcx> {
+pub(crate) struct OpaqueTypeStorage<'tcx> {
     /// Opaque types found in explicit return types and their
     /// associated fresh inference variable. Writeback resolves these
     /// variables to get the concrete type, which can be used to
@@ -46,7 +46,7 @@ impl<'tcx> Drop for OpaqueTypeStorage<'tcx> {
     }
 }
 
-pub struct OpaqueTypeTable<'a, 'tcx> {
+pub(crate) struct OpaqueTypeTable<'a, 'tcx> {
     storage: &'a mut OpaqueTypeStorage<'tcx>,
 
     undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index f5c873b0375..a270f9322f3 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -14,7 +14,7 @@ pub mod env;
 pub mod for_liveness;
 pub mod obligations;
 pub mod test_type_match;
-pub mod verify;
+pub(crate) mod verify;
 
 #[instrument(level = "debug", skip(param_env), ret)]
 pub fn explicit_outlives_bounds<'tcx>(
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 74a80a1b9aa..247fbc25965 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -15,7 +15,7 @@ use crate::infer::{GenericKind, VerifyBound};
 /// via a "delegate" of type `D` -- this is usually the `infcx`, which
 /// accrues them into the `region_obligations` code, but for NLL we
 /// use something else.
-pub struct VerifyBoundCx<'cx, 'tcx> {
+pub(crate) struct VerifyBoundCx<'cx, 'tcx> {
     tcx: TyCtxt<'tcx>,
     region_bound_pairs: &'cx RegionBoundPairs<'tcx>,
     /// During borrowck, if there are no outlives bounds on a generic
@@ -28,7 +28,7 @@ pub struct VerifyBoundCx<'cx, 'tcx> {
 }
 
 impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
-    pub fn new(
+    pub(crate) fn new(
         tcx: TyCtxt<'tcx>,
         region_bound_pairs: &'cx RegionBoundPairs<'tcx>,
         implicit_region_bound: Option<ty::Region<'tcx>>,
@@ -38,7 +38,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    pub fn param_or_placeholder_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
+    pub(crate) fn param_or_placeholder_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
         // Start with anything like `T: 'a` we can scrape from the
         // environment. If the environment contains something like
         // `for<'a> T: 'a`, then we know that `T` outlives everything.
@@ -92,7 +92,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     /// the clause from the environment only applies if `'0 = 'a`,
     /// which we don't know yet. But we would still include `'b` in
     /// this list.
-    pub fn approx_declared_bounds_from_env(
+    pub(crate) fn approx_declared_bounds_from_env(
         &self,
         alias_ty: ty::AliasTy<'tcx>,
     ) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> {
@@ -101,7 +101,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    pub fn alias_bound(&self, alias_ty: ty::AliasTy<'tcx>) -> VerifyBound<'tcx> {
+    pub(crate) fn alias_bound(&self, alias_ty: ty::AliasTy<'tcx>) -> VerifyBound<'tcx> {
         let alias_ty_as_ty = alias_ty.to_ty(self.tcx);
 
         // Search the env for where clauses like `P: 'a`.
@@ -285,7 +285,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     ///
     /// This is for simplicity, and because we are not really smart
     /// enough to cope with such bounds anywhere.
-    pub fn declared_bounds_from_definition(
+    pub(crate) fn declared_bounds_from_definition(
         &self,
         alias_ty: ty::AliasTy<'tcx>,
     ) -> impl Iterator<Item = ty::Region<'tcx>> {
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 82f7668b2d2..4411f8db72a 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -304,7 +304,7 @@ pub struct RegionVariableInfo {
     pub universe: ty::UniverseIndex,
 }
 
-pub struct RegionSnapshot {
+pub(crate) struct RegionSnapshot {
     any_unifications: bool,
 }
 
@@ -522,7 +522,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
         definition_span: Span,
         hidden_ty: Ty<'tcx>,
         member_region: ty::Region<'tcx>,
-        choice_regions: &Lrc<Vec<ty::Region<'tcx>>>,
+        choice_regions: Lrc<Vec<ty::Region<'tcx>>>,
     ) {
         debug!("member_constraint({:?} in {:#?})", member_region, choice_regions);
 
@@ -535,7 +535,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
             definition_span,
             hidden_ty,
             member_region,
-            choice_regions: choice_regions.clone(),
+            choice_regions,
         });
     }
 
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index e75d7b7db14..450437f2176 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -1,4 +1,4 @@
-//! There are four type combiners: [TypeRelating], [Lub], and [Glb],
+//! There are four type combiners: [TypeRelating], `Lub`, and `Glb`,
 //! and `NllTypeRelating` in rustc_borrowck, which is only used for NLL.
 //!
 //! Each implements the trait [TypeRelation] and contains methods for
@@ -26,24 +26,28 @@ use rustc_middle::ty::{self, InferConst, IntType, Ty, TyCtxt, TypeVisitableExt,
 pub use rustc_next_trait_solver::relate::combine::*;
 use tracing::debug;
 
-use super::glb::Glb;
-use super::lub::Lub;
+use super::lattice::{LatticeOp, LatticeOpKind};
 use super::type_relating::TypeRelating;
 use super::{RelateResult, StructurallyRelateAliases};
 use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace, relate};
 use crate::traits::{Obligation, PredicateObligation};
 
 #[derive(Clone)]
-pub struct CombineFields<'infcx, 'tcx> {
+pub(crate) struct CombineFields<'infcx, 'tcx> {
     pub infcx: &'infcx InferCtxt<'tcx>,
+    // Immutable fields
     pub trace: TypeTrace<'tcx>,
     pub param_env: ty::ParamEnv<'tcx>,
-    pub goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
     pub define_opaque_types: DefineOpaqueTypes,
+    // Mutable fields
+    //
+    // Adding any additional field likely requires
+    // changes to the cache of `TypeRelating`.
+    pub goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
 }
 
 impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
-    pub fn new(
+    pub(crate) fn new(
         infcx: &'infcx InferCtxt<'tcx>,
         trace: TypeTrace<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
@@ -279,41 +283,41 @@ impl<'tcx> InferCtxt<'tcx> {
 }
 
 impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
-    pub fn tcx(&self) -> TyCtxt<'tcx> {
+    pub(crate) fn tcx(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
-    pub fn equate<'a>(
+    pub(crate) fn equate<'a>(
         &'a mut self,
         structurally_relate_aliases: StructurallyRelateAliases,
     ) -> TypeRelating<'a, 'infcx, 'tcx> {
         TypeRelating::new(self, structurally_relate_aliases, ty::Invariant)
     }
 
-    pub fn sub<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> {
+    pub(crate) fn sub<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> {
         TypeRelating::new(self, StructurallyRelateAliases::No, ty::Covariant)
     }
 
-    pub fn sup<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> {
+    pub(crate) fn sup<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> {
         TypeRelating::new(self, StructurallyRelateAliases::No, ty::Contravariant)
     }
 
-    pub fn lub<'a>(&'a mut self) -> Lub<'a, 'infcx, 'tcx> {
-        Lub::new(self)
+    pub(crate) fn lub<'a>(&'a mut self) -> LatticeOp<'a, 'infcx, 'tcx> {
+        LatticeOp::new(self, LatticeOpKind::Lub)
     }
 
-    pub fn glb<'a>(&'a mut self) -> Glb<'a, 'infcx, 'tcx> {
-        Glb::new(self)
+    pub(crate) fn glb<'a>(&'a mut self) -> LatticeOp<'a, 'infcx, 'tcx> {
+        LatticeOp::new(self, LatticeOpKind::Glb)
     }
 
-    pub fn register_obligations(
+    pub(crate) fn register_obligations(
         &mut self,
         obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
     ) {
         self.goals.extend(obligations);
     }
 
-    pub fn register_predicates(
+    pub(crate) fn register_predicates(
         &mut self,
         obligations: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
     ) {
diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs
deleted file mode 100644
index ed108f42969..00000000000
--- a/compiler/rustc_infer/src/infer/relate/glb.rs
+++ /dev/null
@@ -1,159 +0,0 @@
-//! Greatest lower bound. See [`lattice`].
-
-use rustc_middle::traits::solve::Goal;
-use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_span::Span;
-use tracing::{debug, instrument};
-
-use super::StructurallyRelateAliases;
-use super::combine::{CombineFields, PredicateEmittingRelation};
-use super::lattice::{self, LatticeDir};
-use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
-use crate::traits::ObligationCause;
-
-/// "Greatest lower bound" (common subtype)
-pub struct Glb<'combine, 'infcx, 'tcx> {
-    fields: &'combine mut CombineFields<'infcx, 'tcx>,
-}
-
-impl<'combine, 'infcx, 'tcx> Glb<'combine, 'infcx, 'tcx> {
-    pub fn new(fields: &'combine mut CombineFields<'infcx, 'tcx>) -> Glb<'combine, 'infcx, 'tcx> {
-        Glb { fields }
-    }
-}
-
-impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Glb<'_, '_, 'tcx> {
-    fn cx(&self) -> TyCtxt<'tcx> {
-        self.fields.tcx()
-    }
-
-    fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
-        &mut self,
-        variance: ty::Variance,
-        _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
-        a: T,
-        b: T,
-    ) -> RelateResult<'tcx, T> {
-        match variance {
-            ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b),
-            ty::Covariant => self.relate(a, b),
-            // FIXME(#41044) -- not correct, need test
-            ty::Bivariant => Ok(a),
-            ty::Contravariant => self.fields.lub().relate(a, b),
-        }
-    }
-
-    #[instrument(skip(self), level = "trace")]
-    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        lattice::super_lattice_tys(self, a, b)
-    }
-
-    #[instrument(skip(self), level = "trace")]
-    fn regions(
-        &mut self,
-        a: ty::Region<'tcx>,
-        b: ty::Region<'tcx>,
-    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
-        // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8
-        Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions(
-            self.cx(),
-            origin,
-            a,
-            b,
-        ))
-    }
-
-    #[instrument(skip(self), level = "trace")]
-    fn consts(
-        &mut self,
-        a: ty::Const<'tcx>,
-        b: ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
-        self.fields.infcx.super_combine_consts(self, a, b)
-    }
-
-    fn binders<T>(
-        &mut self,
-        a: ty::Binder<'tcx, T>,
-        b: ty::Binder<'tcx, T>,
-    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
-    where
-        T: Relate<TyCtxt<'tcx>>,
-    {
-        // GLB of a binder and itself is just itself
-        if a == b {
-            return Ok(a);
-        }
-
-        debug!("binders(a={:?}, b={:?})", a, b);
-        if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
-            // When higher-ranked types are involved, computing the GLB is
-            // very challenging, switch to invariance. This is obviously
-            // overly conservative but works ok in practice.
-            self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
-            Ok(a)
-        } else {
-            Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
-        }
-    }
-}
-
-impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, 'tcx> {
-    fn infcx(&self) -> &'infcx InferCtxt<'tcx> {
-        self.fields.infcx
-    }
-
-    fn cause(&self) -> &ObligationCause<'tcx> {
-        &self.fields.trace.cause
-    }
-
-    fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
-        let mut sub = self.fields.sub();
-        sub.relate(v, a)?;
-        sub.relate(v, b)?;
-        Ok(())
-    }
-
-    fn define_opaque_types(&self) -> DefineOpaqueTypes {
-        self.fields.define_opaque_types
-    }
-}
-
-impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for Glb<'_, '_, 'tcx> {
-    fn span(&self) -> Span {
-        self.fields.trace.span()
-    }
-
-    fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
-        StructurallyRelateAliases::No
-    }
-
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.fields.param_env
-    }
-
-    fn register_predicates(
-        &mut self,
-        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
-    ) {
-        self.fields.register_predicates(obligations);
-    }
-
-    fn register_goals(
-        &mut self,
-        obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
-    ) {
-        self.fields.register_obligations(obligations);
-    }
-
-    fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
-        self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
-            a.into(),
-            b.into(),
-            // FIXME(deferred_projection_equality): This isn't right, I think?
-            ty::AliasRelationDirection::Equate,
-        ))]);
-    }
-}
diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs
index 1d3f45465d6..9564baa6ab2 100644
--- a/compiler/rustc_infer/src/infer/relate/lattice.rs
+++ b/compiler/rustc_infer/src/infer/relate/lattice.rs
@@ -17,99 +17,247 @@
 //!
 //! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
 
-use rustc_middle::ty::relate::RelateResult;
-use rustc_middle::ty::{self, Ty, TyVar};
-use tracing::instrument;
+use rustc_middle::traits::solve::Goal;
+use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
+use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt};
+use rustc_span::Span;
+use tracing::{debug, instrument};
 
-use super::combine::PredicateEmittingRelation;
-use crate::infer::{DefineOpaqueTypes, InferCtxt};
-use crate::traits::ObligationCause;
+use super::StructurallyRelateAliases;
+use super::combine::{CombineFields, PredicateEmittingRelation};
+use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
 
-/// Trait for returning data about a lattice, and for abstracting
-/// over the "direction" of the lattice operation (LUB/GLB).
-///
-/// GLB moves "down" the lattice (to smaller values); LUB moves
-/// "up" the lattice (to bigger values).
-pub(crate) trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<InferCtxt<'tcx>> {
-    fn infcx(&self) -> &'f InferCtxt<'tcx>;
+#[derive(Clone, Copy)]
+pub(crate) enum LatticeOpKind {
+    Glb,
+    Lub,
+}
+
+impl LatticeOpKind {
+    fn invert(self) -> Self {
+        match self {
+            LatticeOpKind::Glb => LatticeOpKind::Lub,
+            LatticeOpKind::Lub => LatticeOpKind::Glb,
+        }
+    }
+}
+
+/// A greatest lower bound" (common subtype) or least upper bound (common supertype).
+pub(crate) struct LatticeOp<'combine, 'infcx, 'tcx> {
+    fields: &'combine mut CombineFields<'infcx, 'tcx>,
+    kind: LatticeOpKind,
+}
+
+impl<'combine, 'infcx, 'tcx> LatticeOp<'combine, 'infcx, 'tcx> {
+    pub(crate) fn new(
+        fields: &'combine mut CombineFields<'infcx, 'tcx>,
+        kind: LatticeOpKind,
+    ) -> LatticeOp<'combine, 'infcx, 'tcx> {
+        LatticeOp { fields, kind }
+    }
+}
+
+impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx> {
+    fn cx(&self) -> TyCtxt<'tcx> {
+        self.fields.tcx()
+    }
 
-    fn cause(&self) -> &ObligationCause<'tcx>;
+    fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
+        &mut self,
+        variance: ty::Variance,
+        _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
+        a: T,
+        b: T,
+    ) -> RelateResult<'tcx, T> {
+        match variance {
+            ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b),
+            ty::Covariant => self.relate(a, b),
+            // FIXME(#41044) -- not correct, need test
+            ty::Bivariant => Ok(a),
+            ty::Contravariant => {
+                self.kind = self.kind.invert();
+                let res = self.relate(a, b);
+                self.kind = self.kind.invert();
+                res
+            }
+        }
+    }
+
+    /// Relates two types using a given lattice.
+    #[instrument(skip(self), level = "trace")]
+    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        if a == b {
+            return Ok(a);
+        }
+
+        let infcx = self.fields.infcx;
+
+        let a = infcx.shallow_resolve(a);
+        let b = infcx.shallow_resolve(b);
+
+        match (a.kind(), b.kind()) {
+            // If one side is known to be a variable and one is not,
+            // create a variable (`v`) to represent the LUB. Make sure to
+            // relate `v` to the non-type-variable first (by passing it
+            // first to `relate_bound`). Otherwise, we would produce a
+            // subtype obligation that must then be processed.
+            //
+            // Example: if the LHS is a type variable, and RHS is
+            // `Box<i32>`, then we current compare `v` to the RHS first,
+            // which will instantiate `v` with `Box<i32>`. Then when `v`
+            // is compared to the LHS, we instantiate LHS with `Box<i32>`.
+            // But if we did in reverse order, we would create a `v <:
+            // LHS` (or vice versa) constraint and then instantiate
+            // `v`. This would require further processing to achieve same
+            // end-result; in particular, this screws up some of the logic
+            // in coercion, which expects LUB to figure out that the LHS
+            // is (e.g.) `Box<i32>`. A more obvious solution might be to
+            // iterate on the subtype obligations that are returned, but I
+            // think this suffices. -nmatsakis
+            (&ty::Infer(TyVar(..)), _) => {
+                let v = infcx.next_ty_var(self.fields.trace.cause.span);
+                self.relate_bound(v, b, a)?;
+                Ok(v)
+            }
+            (_, &ty::Infer(TyVar(..))) => {
+                let v = infcx.next_ty_var(self.fields.trace.cause.span);
+                self.relate_bound(v, a, b)?;
+                Ok(v)
+            }
+
+            (
+                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
+            ) if a_def_id == b_def_id => infcx.super_combine_tys(self, a, b),
+
+            (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+            | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
+                if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
+                    && def_id.is_local()
+                    && !infcx.next_trait_solver() =>
+            {
+                self.register_goals(infcx.handle_opaque_type(
+                    a,
+                    b,
+                    self.span(),
+                    self.param_env(),
+                )?);
+                Ok(a)
+            }
+
+            _ => infcx.super_combine_tys(self, a, b),
+        }
+    }
 
-    fn define_opaque_types(&self) -> DefineOpaqueTypes;
+    #[instrument(skip(self), level = "trace")]
+    fn regions(
+        &mut self,
+        a: ty::Region<'tcx>,
+        b: ty::Region<'tcx>,
+    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+        let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
+        let mut inner = self.fields.infcx.inner.borrow_mut();
+        let mut constraints = inner.unwrap_region_constraints();
+        Ok(match self.kind {
+            // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8
+            LatticeOpKind::Glb => constraints.lub_regions(self.cx(), origin, a, b),
 
+            // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8
+            LatticeOpKind::Lub => constraints.glb_regions(self.cx(), origin, a, b),
+        })
+    }
+
+    #[instrument(skip(self), level = "trace")]
+    fn consts(
+        &mut self,
+        a: ty::Const<'tcx>,
+        b: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
+        self.fields.infcx.super_combine_consts(self, a, b)
+    }
+
+    fn binders<T>(
+        &mut self,
+        a: ty::Binder<'tcx, T>,
+        b: ty::Binder<'tcx, T>,
+    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
+    where
+        T: Relate<TyCtxt<'tcx>>,
+    {
+        // GLB/LUB of a binder and itself is just itself
+        if a == b {
+            return Ok(a);
+        }
+
+        debug!("binders(a={:?}, b={:?})", a, b);
+        if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
+            // When higher-ranked types are involved, computing the GLB/LUB is
+            // very challenging, switch to invariance. This is obviously
+            // overly conservative but works ok in practice.
+            self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
+            Ok(a)
+        } else {
+            Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
+        }
+    }
+}
+
+impl<'combine, 'infcx, 'tcx> LatticeOp<'combine, 'infcx, 'tcx> {
     // Relates the type `v` to `a` and `b` such that `v` represents
     // the LUB/GLB of `a` and `b` as appropriate.
     //
     // Subtle hack: ordering *may* be significant here. This method
     // relates `v` to `a` first, which may help us to avoid unnecessary
     // type variable obligations. See caller for details.
-    fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
+    fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
+        let mut sub = self.fields.sub();
+        match self.kind {
+            LatticeOpKind::Glb => {
+                sub.relate(v, a)?;
+                sub.relate(v, b)?;
+            }
+            LatticeOpKind::Lub => {
+                sub.relate(a, v)?;
+                sub.relate(b, v)?;
+            }
+        }
+        Ok(())
+    }
 }
 
-/// Relates two types using a given lattice.
-#[instrument(skip(this), level = "debug")]
-pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
-    this: &mut L,
-    a: Ty<'tcx>,
-    b: Ty<'tcx>,
-) -> RelateResult<'tcx, Ty<'tcx>>
-where
-    L: LatticeDir<'a, 'tcx>,
-{
-    if a == b {
-        return Ok(a);
+impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx> {
+    fn span(&self) -> Span {
+        self.fields.trace.span()
     }
 
-    let infcx = this.infcx();
-
-    let a = infcx.shallow_resolve(a);
-    let b = infcx.shallow_resolve(b);
-
-    match (a.kind(), b.kind()) {
-        // If one side is known to be a variable and one is not,
-        // create a variable (`v`) to represent the LUB. Make sure to
-        // relate `v` to the non-type-variable first (by passing it
-        // first to `relate_bound`). Otherwise, we would produce a
-        // subtype obligation that must then be processed.
-        //
-        // Example: if the LHS is a type variable, and RHS is
-        // `Box<i32>`, then we current compare `v` to the RHS first,
-        // which will instantiate `v` with `Box<i32>`. Then when `v`
-        // is compared to the LHS, we instantiate LHS with `Box<i32>`.
-        // But if we did in reverse order, we would create a `v <:
-        // LHS` (or vice versa) constraint and then instantiate
-        // `v`. This would require further processing to achieve same
-        // end-result; in particular, this screws up some of the logic
-        // in coercion, which expects LUB to figure out that the LHS
-        // is (e.g.) `Box<i32>`. A more obvious solution might be to
-        // iterate on the subtype obligations that are returned, but I
-        // think this suffices. -nmatsakis
-        (&ty::Infer(TyVar(..)), _) => {
-            let v = infcx.next_ty_var(this.cause().span);
-            this.relate_bound(v, b, a)?;
-            Ok(v)
-        }
-        (_, &ty::Infer(TyVar(..))) => {
-            let v = infcx.next_ty_var(this.cause().span);
-            this.relate_bound(v, a, b)?;
-            Ok(v)
-        }
+    fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
+        StructurallyRelateAliases::No
+    }
 
-        (
-            &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
-            &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
-        ) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b),
-
-        (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
-        | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
-            if this.define_opaque_types() == DefineOpaqueTypes::Yes
-                && def_id.is_local()
-                && !this.infcx().next_trait_solver() =>
-        {
-            this.register_goals(infcx.handle_opaque_type(a, b, this.span(), this.param_env())?);
-            Ok(a)
-        }
+    fn param_env(&self) -> ty::ParamEnv<'tcx> {
+        self.fields.param_env
+    }
+
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    ) {
+        self.fields.register_predicates(obligations);
+    }
+
+    fn register_goals(
+        &mut self,
+        obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
+    ) {
+        self.fields.register_obligations(obligations);
+    }
 
-        _ => infcx.super_combine_tys(this, a, b),
+    fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
+        self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
+            a.into(),
+            b.into(),
+            // FIXME(deferred_projection_equality): This isn't right, I think?
+            ty::AliasRelationDirection::Equate,
+        ))]);
     }
 }
diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs
deleted file mode 100644
index 35c7ab5000d..00000000000
--- a/compiler/rustc_infer/src/infer/relate/lub.rs
+++ /dev/null
@@ -1,158 +0,0 @@
-//! Least upper bound. See [`lattice`].
-
-use rustc_middle::traits::solve::Goal;
-use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_span::Span;
-use tracing::{debug, instrument};
-
-use super::StructurallyRelateAliases;
-use super::combine::{CombineFields, PredicateEmittingRelation};
-use super::lattice::{self, LatticeDir};
-use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
-use crate::traits::ObligationCause;
-
-/// "Least upper bound" (common supertype)
-pub struct Lub<'combine, 'infcx, 'tcx> {
-    fields: &'combine mut CombineFields<'infcx, 'tcx>,
-}
-
-impl<'combine, 'infcx, 'tcx> Lub<'combine, 'infcx, 'tcx> {
-    pub fn new(fields: &'combine mut CombineFields<'infcx, 'tcx>) -> Lub<'combine, 'infcx, 'tcx> {
-        Lub { fields }
-    }
-}
-
-impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Lub<'_, '_, 'tcx> {
-    fn cx(&self) -> TyCtxt<'tcx> {
-        self.fields.tcx()
-    }
-
-    fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
-        &mut self,
-        variance: ty::Variance,
-        _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
-        a: T,
-        b: T,
-    ) -> RelateResult<'tcx, T> {
-        match variance {
-            ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b),
-            ty::Covariant => self.relate(a, b),
-            // FIXME(#41044) -- not correct, need test
-            ty::Bivariant => Ok(a),
-            ty::Contravariant => self.fields.glb().relate(a, b),
-        }
-    }
-
-    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        lattice::super_lattice_tys(self, a, b)
-    }
-
-    #[instrument(skip(self), level = "trace")]
-    fn regions(
-        &mut self,
-        a: ty::Region<'tcx>,
-        b: ty::Region<'tcx>,
-    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
-        // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8
-        Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions(
-            self.cx(),
-            origin,
-            a,
-            b,
-        ))
-    }
-
-    #[instrument(skip(self), level = "trace")]
-    fn consts(
-        &mut self,
-        a: ty::Const<'tcx>,
-        b: ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
-        self.fields.infcx.super_combine_consts(self, a, b)
-    }
-
-    fn binders<T>(
-        &mut self,
-        a: ty::Binder<'tcx, T>,
-        b: ty::Binder<'tcx, T>,
-    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
-    where
-        T: Relate<TyCtxt<'tcx>>,
-    {
-        // LUB of a binder and itself is just itself
-        if a == b {
-            return Ok(a);
-        }
-
-        debug!("binders(a={:?}, b={:?})", a, b);
-        if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
-            // When higher-ranked types are involved, computing the LUB is
-            // very challenging, switch to invariance. This is obviously
-            // overly conservative but works ok in practice.
-            self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
-            Ok(a)
-        } else {
-            Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
-        }
-    }
-}
-
-impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, 'tcx> {
-    fn infcx(&self) -> &'infcx InferCtxt<'tcx> {
-        self.fields.infcx
-    }
-
-    fn cause(&self) -> &ObligationCause<'tcx> {
-        &self.fields.trace.cause
-    }
-
-    fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
-        let mut sub = self.fields.sub();
-        sub.relate(a, v)?;
-        sub.relate(b, v)?;
-        Ok(())
-    }
-
-    fn define_opaque_types(&self) -> DefineOpaqueTypes {
-        self.fields.define_opaque_types
-    }
-}
-
-impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for Lub<'_, '_, 'tcx> {
-    fn span(&self) -> Span {
-        self.fields.trace.span()
-    }
-
-    fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
-        StructurallyRelateAliases::No
-    }
-
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.fields.param_env
-    }
-
-    fn register_predicates(
-        &mut self,
-        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
-    ) {
-        self.fields.register_predicates(obligations);
-    }
-
-    fn register_goals(
-        &mut self,
-        obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
-    ) {
-        self.fields.register_obligations(obligations)
-    }
-
-    fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
-        self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
-            a.into(),
-            b.into(),
-            // FIXME(deferred_projection_equality): This isn't right, I think?
-            ty::AliasRelationDirection::Equate,
-        ))]);
-    }
-}
diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs
index 183ea5b3309..85158faa65d 100644
--- a/compiler/rustc_infer/src/infer/relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/relate/mod.rs
@@ -5,13 +5,11 @@
 pub use rustc_middle::ty::relate::RelateResult;
 pub use rustc_next_trait_solver::relate::*;
 
-pub use self::combine::{CombineFields, PredicateEmittingRelation};
+pub use self::combine::PredicateEmittingRelation;
 
 #[allow(hidden_glob_reexports)]
 pub(super) mod combine;
 mod generalize;
-mod glb;
 mod higher_ranked;
 mod lattice;
-mod lub;
 mod type_relating;
diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs
index a402a8009ff..7537ceec307 100644
--- a/compiler/rustc_infer/src/infer/relate/type_relating.rs
+++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs
@@ -4,6 +4,7 @@ use rustc_middle::ty::relate::{
 };
 use rustc_middle::ty::{self, Ty, TyCtxt, TyVar};
 use rustc_span::Span;
+use rustc_type_ir::data_structures::DelayedSet;
 use tracing::{debug, instrument};
 
 use super::combine::CombineFields;
@@ -12,19 +13,53 @@ use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases}
 use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
 
 /// Enforce that `a` is equal to or a subtype of `b`.
-pub struct TypeRelating<'combine, 'a, 'tcx> {
+pub(crate) struct TypeRelating<'combine, 'a, 'tcx> {
+    // Immutable except for the `InferCtxt` and the
+    // resulting nested `goals`.
     fields: &'combine mut CombineFields<'a, 'tcx>,
+
+    // Immutable field.
     structurally_relate_aliases: StructurallyRelateAliases,
+    // Mutable field.
     ambient_variance: ty::Variance,
+
+    /// The cache only tracks the `ambient_variance` as it's the
+    /// only field which is mutable and which meaningfully changes
+    /// the result when relating types.
+    ///
+    /// The cache does not track whether the state of the
+    /// `InferCtxt` has been changed or whether we've added any
+    /// obligations to `self.fields.goals`. Whether a goal is added
+    /// once or multiple times is not really meaningful.
+    ///
+    /// Changes in the inference state may delay some type inference to
+    /// the next fulfillment loop. Given that this loop is already
+    /// necessary, this is also not a meaningful change. Consider
+    /// the following three relations:
+    /// ```text
+    /// Vec<?0> sub Vec<?1>
+    /// ?0 eq u32
+    /// Vec<?0> sub Vec<?1>
+    /// ```
+    /// Without a cache, the second `Vec<?0> sub Vec<?1>` would eagerly
+    /// constrain `?1` to `u32`. When using the cache entry from the
+    /// first time we've related these types, this only happens when
+    /// later proving the `Subtype(?0, ?1)` goal from the first relation.
+    cache: DelayedSet<(ty::Variance, Ty<'tcx>, Ty<'tcx>)>,
 }
 
 impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> {
-    pub fn new(
+    pub(crate) fn new(
         f: &'combine mut CombineFields<'infcx, 'tcx>,
         structurally_relate_aliases: StructurallyRelateAliases,
         ambient_variance: ty::Variance,
     ) -> TypeRelating<'combine, 'infcx, 'tcx> {
-        TypeRelating { fields: f, structurally_relate_aliases, ambient_variance }
+        TypeRelating {
+            fields: f,
+            structurally_relate_aliases,
+            ambient_variance,
+            cache: Default::default(),
+        }
     }
 }
 
@@ -78,6 +113,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> {
         let a = infcx.shallow_resolve(a);
         let b = infcx.shallow_resolve(b);
 
+        if self.cache.contains(&(self.ambient_variance, a, b)) {
+            return Ok(a);
+        }
+
         match (a.kind(), b.kind()) {
             (&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => {
                 match self.ambient_variance {
@@ -160,6 +199,8 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> {
             }
         }
 
+        assert!(self.cache.insert((self.ambient_variance, a, b)));
+
         Ok(a)
     }
 
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 34625ffb778..025c3a629fa 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -2,6 +2,7 @@ use rustc_middle::bug;
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
+use rustc_type_ir::data_structures::DelayedMap;
 
 use super::{FixupError, FixupResult, InferCtxt};
 
@@ -15,12 +16,15 @@ use super::{FixupError, FixupResult, InferCtxt};
 /// points for correctness.
 pub struct OpportunisticVarResolver<'a, 'tcx> {
     infcx: &'a InferCtxt<'tcx>,
+    /// We're able to use a cache here as the folder does
+    /// not have any mutable state.
+    cache: DelayedMap<Ty<'tcx>, Ty<'tcx>>,
 }
 
 impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> {
     #[inline]
     pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
-        OpportunisticVarResolver { infcx }
+        OpportunisticVarResolver { infcx, cache: Default::default() }
     }
 }
 
@@ -33,9 +37,13 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticVarResolver<'a, 'tcx> {
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         if !t.has_non_region_infer() {
             t // micro-optimize -- if there is nothing in this type that this fold affects...
+        } else if let Some(&ty) = self.cache.get(&t) {
+            return ty;
         } else {
-            let t = self.infcx.shallow_resolve(t);
-            t.super_fold_with(self)
+            let shallow = self.infcx.shallow_resolve(t);
+            let res = shallow.super_fold_with(self);
+            assert!(self.cache.insert(t, res));
+            res
         }
     }
 
@@ -113,8 +121,6 @@ where
     value.try_fold_with(&mut FullTypeResolver { infcx })
 }
 
-// N.B. This type is not public because the protocol around checking the
-// `err` field is not enforceable otherwise.
 struct FullTypeResolver<'a, 'tcx> {
     infcx: &'a InferCtxt<'tcx>,
 }
@@ -130,11 +136,13 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
         if !t.has_infer() {
             Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
         } else {
+            use super::TyOrConstInferVar::*;
+
             let t = self.infcx.shallow_resolve(t);
             match *t.kind() {
-                ty::Infer(ty::TyVar(vid)) => Err(FixupError::UnresolvedTy(vid)),
-                ty::Infer(ty::IntVar(vid)) => Err(FixupError::UnresolvedIntTy(vid)),
-                ty::Infer(ty::FloatVar(vid)) => Err(FixupError::UnresolvedFloatTy(vid)),
+                ty::Infer(ty::TyVar(vid)) => Err(FixupError { unresolved: Ty(vid) }),
+                ty::Infer(ty::IntVar(vid)) => Err(FixupError { unresolved: TyInt(vid) }),
+                ty::Infer(ty::FloatVar(vid)) => Err(FixupError { unresolved: TyFloat(vid) }),
                 ty::Infer(_) => {
                     bug!("Unexpected type in full type resolver: {:?}", t);
                 }
@@ -163,13 +171,13 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
             let c = self.infcx.shallow_resolve_const(c);
             match c.kind() {
                 ty::ConstKind::Infer(InferConst::Var(vid)) => {
-                    return Err(FixupError::UnresolvedConst(vid));
+                    return Err(FixupError { unresolved: super::TyOrConstInferVar::Const(vid) });
                 }
                 ty::ConstKind::Infer(InferConst::Fresh(_)) => {
                     bug!("Unexpected const in full const resolver: {:?}", c);
                 }
                 ty::ConstKind::Infer(InferConst::EffectVar(evid)) => {
-                    return Err(FixupError::UnresolvedEffect(evid));
+                    return Err(FixupError { unresolved: super::TyOrConstInferVar::Effect(evid) });
                 }
                 _ => {}
             }
diff --git a/compiler/rustc_infer/src/infer/snapshot/mod.rs b/compiler/rustc_infer/src/infer/snapshot/mod.rs
index 964fb1f6819..07a482c2f9a 100644
--- a/compiler/rustc_infer/src/infer/snapshot/mod.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/mod.rs
@@ -5,7 +5,7 @@ use tracing::{debug, instrument};
 use super::InferCtxt;
 use super::region_constraints::RegionSnapshot;
 
-mod fudge;
+pub(crate) mod fudge;
 pub(crate) mod undo_log;
 
 use undo_log::{Snapshot, UndoLog};
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index 7eb2c20e0d8..c50477b2922 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -20,7 +20,7 @@ impl<'tcx> Rollback<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for TypeVariabl
 }
 
 #[derive(Clone)]
-pub struct TypeVariableStorage<'tcx> {
+pub(crate) struct TypeVariableStorage<'tcx> {
     /// The origins of each type variable.
     values: IndexVec<TyVid, TypeVariableData>,
     /// Two variables are unified in `eq_relations` when we have a
@@ -29,7 +29,7 @@ pub struct TypeVariableStorage<'tcx> {
     eq_relations: ut::UnificationTableStorage<TyVidEqKey<'tcx>>,
 }
 
-pub struct TypeVariableTable<'a, 'tcx> {
+pub(crate) struct TypeVariableTable<'a, 'tcx> {
     storage: &'a mut TypeVariableStorage<'tcx>,
 
     undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
@@ -50,7 +50,7 @@ pub(crate) struct TypeVariableData {
 }
 
 #[derive(Copy, Clone, Debug)]
-pub enum TypeVariableValue<'tcx> {
+pub(crate) enum TypeVariableValue<'tcx> {
     Known { value: Ty<'tcx> },
     Unknown { universe: ty::UniverseIndex },
 }
@@ -58,14 +58,14 @@ pub enum TypeVariableValue<'tcx> {
 impl<'tcx> TypeVariableValue<'tcx> {
     /// If this value is known, returns the type it is known to be.
     /// Otherwise, `None`.
-    pub fn known(&self) -> Option<Ty<'tcx>> {
+    pub(crate) fn known(&self) -> Option<Ty<'tcx>> {
         match *self {
             TypeVariableValue::Unknown { .. } => None,
             TypeVariableValue::Known { value } => Some(value),
         }
     }
 
-    pub fn is_unknown(&self) -> bool {
+    pub(crate) fn is_unknown(&self) -> bool {
         match *self {
             TypeVariableValue::Unknown { .. } => true,
             TypeVariableValue::Known { .. } => false,
@@ -74,7 +74,7 @@ impl<'tcx> TypeVariableValue<'tcx> {
 }
 
 impl<'tcx> TypeVariableStorage<'tcx> {
-    pub fn new() -> TypeVariableStorage<'tcx> {
+    pub(crate) fn new() -> TypeVariableStorage<'tcx> {
         TypeVariableStorage {
             values: Default::default(),
             eq_relations: ut::UnificationTableStorage::new(),
@@ -105,14 +105,14 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
     ///
     /// Note that this function does not return care whether
     /// `vid` has been unified with something else or not.
-    pub fn var_origin(&self, vid: ty::TyVid) -> TypeVariableOrigin {
+    pub(crate) fn var_origin(&self, vid: ty::TyVid) -> TypeVariableOrigin {
         self.storage.values[vid].origin
     }
 
     /// Records that `a == b`, depending on `dir`.
     ///
     /// Precondition: neither `a` nor `b` are known.
-    pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) {
+    pub(crate) fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) {
         debug_assert!(self.probe(a).is_unknown());
         debug_assert!(self.probe(b).is_unknown());
         self.eq_relations().union(a, b);
@@ -121,7 +121,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
     /// Instantiates `vid` with the type `ty`.
     ///
     /// Precondition: `vid` must not have been previously instantiated.
-    pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) {
+    pub(crate) fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) {
         let vid = self.root_var(vid);
         debug_assert!(!ty.is_ty_var(), "instantiating ty var with var: {vid:?} {ty:?}");
         debug_assert!(self.probe(vid).is_unknown());
@@ -143,7 +143,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
     /// - `origin`: indicates *why* the type variable was created.
     ///   The code in this module doesn't care, but it can be useful
     ///   for improving error messages.
-    pub fn new_var(
+    pub(crate) fn new_var(
         &mut self,
         universe: ty::UniverseIndex,
         origin: TypeVariableOrigin,
@@ -158,7 +158,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
     }
 
     /// Returns the number of type variables created thus far.
-    pub fn num_vars(&self) -> usize {
+    pub(crate) fn num_vars(&self) -> usize {
         self.storage.values.len()
     }
 
@@ -167,42 +167,29 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
     /// will yield the same root variable (per the union-find
     /// algorithm), so `root_var(a) == root_var(b)` implies that `a ==
     /// b` (transitively).
-    pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid {
+    pub(crate) fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid {
         self.eq_relations().find(vid).vid
     }
 
     /// Retrieves the type to which `vid` has been instantiated, if
     /// any.
-    pub fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> {
+    pub(crate) fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> {
         self.inlined_probe(vid)
     }
 
     /// An always-inlined variant of `probe`, for very hot call sites.
     #[inline(always)]
-    pub fn inlined_probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> {
+    pub(crate) fn inlined_probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> {
         self.eq_relations().inlined_probe_value(vid)
     }
 
-    /// If `t` is a type-inference variable, and it has been
-    /// instantiated, then return the with which it was
-    /// instantiated. Otherwise, returns `t`.
-    pub fn replace_if_possible(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        match *t.kind() {
-            ty::Infer(ty::TyVar(v)) => match self.probe(v) {
-                TypeVariableValue::Unknown { .. } => t,
-                TypeVariableValue::Known { value } => value,
-            },
-            _ => t,
-        }
-    }
-
     #[inline]
     fn eq_relations(&mut self) -> super::UnificationTable<'_, 'tcx, TyVidEqKey<'tcx>> {
         self.storage.eq_relations.with_log(self.undo_log)
     }
 
     /// Returns a range of the type variables created during the snapshot.
-    pub fn vars_since_snapshot(
+    pub(crate) fn vars_since_snapshot(
         &mut self,
         value_count: usize,
     ) -> (Range<TyVid>, Vec<TypeVariableOrigin>) {
@@ -215,7 +202,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
 
     /// Returns indices of all variables that are not yet
     /// instantiated.
-    pub fn unresolved_variables(&mut self) -> Vec<ty::TyVid> {
+    pub(crate) fn unresolved_variables(&mut self) -> Vec<ty::TyVid> {
         (0..self.num_vars())
             .filter_map(|i| {
                 let vid = ty::TyVid::from_usize(i);
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 051bba58518..a04b2bb2b08 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -19,11 +19,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(assert_matches)]
-#![feature(box_patterns)]
-#![feature(control_flow_enum)]
 #![feature(extend_one)]
-#![feature(if_let_guard)]
-#![feature(iter_intersperse)]
 #![feature(iterator_try_collect)]
 #![feature(let_chains)]
 #![feature(rustdoc_internals)]
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index c2241773c8c..3920d3077d3 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -174,7 +174,7 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
             }
         };
 
-        let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::Yes) {
+        let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::No) {
             Ok(meta_item) if parser.token == token::Eof => meta_item,
             Ok(..) => expected_error(),
             Err(err) => {
@@ -389,12 +389,13 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
     let file_loader = config.file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
     let path_mapping = config.opts.file_path_mapping();
     let hash_kind = config.opts.unstable_opts.src_hash_algorithm(&target);
+    let checksum_hash_kind = config.opts.unstable_opts.checksum_hash_algorithm();
 
     util::run_in_thread_pool_with_globals(
         &early_dcx,
         config.opts.edition,
         config.opts.unstable_opts.threads,
-        SourceMapInputs { file_loader, path_mapping, hash_kind },
+        SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind },
         |current_gcx| {
             // The previous `early_dcx` can't be reused here because it doesn't
             // impl `Send`. Creating a new one is fine.
@@ -427,7 +428,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                 Err(e) => early_dcx.early_fatal(format!("failed to load fluent bundle: {e}")),
             };
 
-            let mut locale_resources = Vec::from(config.locale_resources);
+            let mut locale_resources = config.locale_resources;
             locale_resources.push(codegen_backend.locale_resource());
 
             let mut sess = rustc_session::build_session(
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index b81a7402701..1c4dda2a436 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -1,6 +1,7 @@
 // tidy-alphabetical-start
 #![feature(decl_macro)]
 #![feature(file_buffered)]
+#![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(try_blocks)]
 #![warn(unreachable_pub)]
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 84b320975bb..fd850d2f39a 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -32,8 +32,8 @@ use rustc_session::cstore::Untracked;
 use rustc_session::output::{collect_crate_types, filename_for_input, find_crate_name};
 use rustc_session::search_paths::PathKind;
 use rustc_session::{Limit, Session};
-use rustc_span::FileName;
 use rustc_span::symbol::{Symbol, sym};
+use rustc_span::{FileName, SourceFileHash, SourceFileHashAlgorithm};
 use rustc_target::spec::PanicStrategy;
 use rustc_trait_selection::traits;
 use tracing::{info, instrument};
@@ -417,15 +417,23 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
     let result: io::Result<()> = try {
         // Build a list of files used to compile the output and
         // write Makefile-compatible dependency rules
-        let mut files: Vec<String> = sess
+        let mut files: Vec<(String, u64, Option<SourceFileHash>)> = sess
             .source_map()
             .files()
             .iter()
             .filter(|fmap| fmap.is_real_file())
             .filter(|fmap| !fmap.is_imported())
-            .map(|fmap| escape_dep_filename(&fmap.name.prefer_local().to_string()))
+            .map(|fmap| {
+                (
+                    escape_dep_filename(&fmap.name.prefer_local().to_string()),
+                    fmap.source_len.0 as u64,
+                    fmap.checksum_hash,
+                )
+            })
             .collect();
 
+        let checksum_hash_algo = sess.opts.unstable_opts.checksum_hash_algorithm;
+
         // Account for explicitly marked-to-track files
         // (e.g. accessed in proc macros).
         let file_depinfo = sess.psess.file_depinfo.borrow();
@@ -437,22 +445,57 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
 
         // The entries will be used to declare dependencies between files in a
         // Makefile-like output, so the iteration order does not matter.
-        #[allow(rustc::potential_query_instability)]
-        let extra_tracked_files =
-            file_depinfo.iter().map(|path_sym| normalize_path(PathBuf::from(path_sym.as_str())));
+        fn hash_iter_files<P: AsRef<Path>>(
+            it: impl Iterator<Item = P>,
+            checksum_hash_algo: Option<SourceFileHashAlgorithm>,
+        ) -> impl Iterator<Item = (P, u64, Option<SourceFileHash>)> {
+            it.map(move |path| {
+                match checksum_hash_algo.and_then(|algo| {
+                    fs::File::open(path.as_ref())
+                        .and_then(|mut file| {
+                            SourceFileHash::new(algo, &mut file).map(|h| (file, h))
+                        })
+                        .and_then(|(file, h)| file.metadata().map(|m| (m.len(), h)))
+                        .map_err(|e| {
+                            tracing::error!(
+                                "failed to compute checksum, omitting it from dep-info {} {e}",
+                                path.as_ref().display()
+                            )
+                        })
+                        .ok()
+                }) {
+                    Some((file_len, checksum)) => (path, file_len, Some(checksum)),
+                    None => (path, 0, None),
+                }
+            })
+        }
+
+        let extra_tracked_files = hash_iter_files(
+            file_depinfo.iter().map(|path_sym| normalize_path(PathBuf::from(path_sym.as_str()))),
+            checksum_hash_algo,
+        );
         files.extend(extra_tracked_files);
 
         // We also need to track used PGO profile files
         if let Some(ref profile_instr) = sess.opts.cg.profile_use {
-            files.push(normalize_path(profile_instr.as_path().to_path_buf()));
+            files.extend(hash_iter_files(
+                iter::once(normalize_path(profile_instr.as_path().to_path_buf())),
+                checksum_hash_algo,
+            ));
         }
         if let Some(ref profile_sample) = sess.opts.unstable_opts.profile_sample_use {
-            files.push(normalize_path(profile_sample.as_path().to_path_buf()));
+            files.extend(hash_iter_files(
+                iter::once(normalize_path(profile_sample.as_path().to_path_buf())),
+                checksum_hash_algo,
+            ));
         }
 
         // Debugger visualizer files
         for debugger_visualizer in tcx.debugger_visualizers(LOCAL_CRATE) {
-            files.push(normalize_path(debugger_visualizer.path.clone().unwrap()));
+            files.extend(hash_iter_files(
+                iter::once(normalize_path(debugger_visualizer.path.clone().unwrap())),
+                checksum_hash_algo,
+            ));
         }
 
         if sess.binary_dep_depinfo() {
@@ -460,33 +503,54 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
                 if backend.contains('.') {
                     // If the backend name contain a `.`, it is the path to an external dynamic
                     // library. If not, it is not a path.
-                    files.push(backend.to_string());
+                    files.extend(hash_iter_files(
+                        iter::once(backend.to_string()),
+                        checksum_hash_algo,
+                    ));
                 }
             }
 
             for &cnum in tcx.crates(()) {
                 let source = tcx.used_crate_source(cnum);
                 if let Some((path, _)) = &source.dylib {
-                    files.push(escape_dep_filename(&path.display().to_string()));
+                    files.extend(hash_iter_files(
+                        iter::once(escape_dep_filename(&path.display().to_string())),
+                        checksum_hash_algo,
+                    ));
                 }
                 if let Some((path, _)) = &source.rlib {
-                    files.push(escape_dep_filename(&path.display().to_string()));
+                    files.extend(hash_iter_files(
+                        iter::once(escape_dep_filename(&path.display().to_string())),
+                        checksum_hash_algo,
+                    ));
                 }
                 if let Some((path, _)) = &source.rmeta {
-                    files.push(escape_dep_filename(&path.display().to_string()));
+                    files.extend(hash_iter_files(
+                        iter::once(escape_dep_filename(&path.display().to_string())),
+                        checksum_hash_algo,
+                    ));
                 }
             }
         }
 
         let write_deps_to_file = |file: &mut dyn Write| -> io::Result<()> {
             for path in out_filenames {
-                writeln!(file, "{}: {}\n", path.display(), files.join(" "))?;
+                writeln!(
+                    file,
+                    "{}: {}\n",
+                    path.display(),
+                    files
+                        .iter()
+                        .map(|(path, _file_len, _checksum_hash_algo)| path.as_str())
+                        .intersperse(" ")
+                        .collect::<String>()
+                )?;
             }
 
             // Emit a fake target for each input file to the compilation. This
             // prevents `make` from spitting out an error if a file is later
             // deleted. For more info see #28735
-            for path in files {
+            for (path, _file_len, _checksum_hash_algo) in &files {
                 writeln!(file, "{path}:")?;
             }
 
@@ -510,6 +574,19 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
                 }
             }
 
+            // If caller requested this information, add special comments about source file checksums.
+            // These are not necessarily the same checksums as was used in the debug files.
+            if sess.opts.unstable_opts.checksum_hash_algorithm().is_some() {
+                files
+                    .iter()
+                    .filter_map(|(path, file_len, hash_algo)| {
+                        hash_algo.map(|hash_algo| (path, file_len, hash_algo))
+                    })
+                    .try_for_each(|(path, file_len, checksum_hash)| {
+                        writeln!(file, "# checksum:{checksum_hash} file_len:{file_len} {path}")
+                    })?;
+            }
+
             Ok(())
         };
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 57aa3deae80..536ce154cd0 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -44,10 +44,12 @@ where
     let sysroot = filesearch::materialize_sysroot(sessopts.maybe_sysroot.clone());
     let target = rustc_session::config::build_target_config(&early_dcx, &sessopts, &sysroot);
     let hash_kind = sessopts.unstable_opts.src_hash_algorithm(&target);
+    let checksum_hash_kind = sessopts.unstable_opts.checksum_hash_algorithm();
     let sm_inputs = Some(SourceMapInputs {
         file_loader: Box::new(RealFileLoader) as _,
         path_mapping: sessopts.file_path_mapping(),
         hash_kind,
+        checksum_hash_kind,
     });
 
     rustc_span::create_session_globals_then(DEFAULT_EDITION, sm_inputs, || {
@@ -770,7 +772,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(crate_attr, vec!["abc".to_string()]);
     tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
     tracked!(debug_info_for_profiling, true);
-    tracked!(default_hidden_visibility, Some(true));
+    tracked!(default_visibility, Some(rustc_target::spec::SymbolVisibility::Hidden));
     tracked!(dep_info_omit_d_target, true);
     tracked!(direct_access_external_data, Some(true));
     tracked!(dual_proc_macros, true);
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 8acb986bfc9..d3799594871 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -203,12 +203,6 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i
     .current_use = this identifier can be confused with `{$existing_sym}`
     .other_use = other identifier used here
 
-lint_crate_name_in_cfg_attr_deprecated =
-    `crate_name` within an `#![cfg_attr]` attribute is deprecated
-
-lint_crate_type_in_cfg_attr_deprecated =
-    `crate_type` within an `#![cfg_attr]` attribute is deprecated
-
 lint_cstring_ptr = getting the inner pointer of a temporary `CString`
     .as_ptr_label = this pointer will be invalid
     .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs
index d9040207300..63a8a949e96 100644
--- a/compiler/rustc_lint/src/async_fn_in_trait.rs
+++ b/compiler/rustc_lint/src/async_fn_in_trait.rs
@@ -104,8 +104,9 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait {
                 return;
             }
 
-            let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) =
-                sig.decl.output
+            let hir::FnRetTy::Return(hir::Ty {
+                kind: hir::TyKind::OpaqueDef(opaq_def, ..), ..
+            }) = sig.decl.output
             else {
                 // This should never happen, but let's not ICE.
                 return;
@@ -114,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait {
                 cx.tcx,
                 sig,
                 body,
-                def.owner_id.def_id,
+                opaq_def.def_id,
                 " + Send",
             );
             cx.tcx.emit_node_span_lint(
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index 168e3a8e92c..b5ab56912cb 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -400,12 +400,6 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
         BuiltinLintDiag::CfgAttrNoAttributes => {
             lints::CfgAttrNoAttributes.decorate_lint(diag);
         }
-        BuiltinLintDiag::CrateTypeInCfgAttr => {
-            lints::CrateTypeInCfgAttr.decorate_lint(diag);
-        }
-        BuiltinLintDiag::CrateNameInCfgAttr => {
-            lints::CrateNameInCfgAttr.decorate_lint(diag);
-        }
         BuiltinLintDiag::MissingFragmentSpecifier => {
             lints::MissingFragmentSpecifier.decorate_lint(diag);
         }
diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs
index 229d0c36421..cdd0e80c458 100644
--- a/compiler/rustc_lint/src/if_let_rescope.rs
+++ b/compiler/rustc_lint/src/if_let_rescope.rs
@@ -122,7 +122,11 @@ impl IfLetRescope {
         }
         let tcx = cx.tcx;
         let source_map = tcx.sess.source_map();
-        let expr_end = expr.span.shrink_to_hi();
+        let expr_end = match expr.kind {
+            hir::ExprKind::If(_cond, conseq, None) => conseq.span.shrink_to_hi(),
+            hir::ExprKind::If(_cond, _conseq, Some(alt)) => alt.span.shrink_to_hi(),
+            _ => return,
+        };
         let mut add_bracket_to_match_head = match_head_needs_bracket(tcx, expr);
         let mut significant_droppers = vec![];
         let mut lifetime_ends = vec![];
@@ -145,7 +149,10 @@ impl IfLetRescope {
                 recovered: Recovered::No,
             }) = cond.kind
             {
-                let if_let_pat = expr.span.shrink_to_lo().between(init.span);
+                // Peel off round braces
+                let if_let_pat = source_map
+                    .span_take_while(expr.span, |&ch| ch == '(' || ch.is_whitespace())
+                    .between(init.span);
                 // The consequent fragment is always a block.
                 let before_conseq = conseq.span.shrink_to_lo();
                 let lifetime_end = source_map.end_point(conseq.span);
@@ -159,6 +166,8 @@ impl IfLetRescope {
                     if ty_ascription.is_some()
                         || !expr.span.can_be_used_for_suggestions()
                         || !pat.span.can_be_used_for_suggestions()
+                        || !if_let_pat.can_be_used_for_suggestions()
+                        || !before_conseq.can_be_used_for_suggestions()
                     {
                         // Our `match` rewrites does not support type ascription,
                         // so we just bail.
@@ -240,6 +249,23 @@ impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
         if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) {
             return;
         }
+        if let hir::ExprKind::Loop(block, _label, hir::LoopSource::While, _span) = expr.kind
+            && let Some(value) = block.expr
+            && let hir::ExprKind::If(cond, _conseq, _alt) = value.kind
+            && let hir::ExprKind::Let(..) = cond.kind
+        {
+            // Recall that `while let` is lowered into this:
+            // ```
+            // loop {
+            //     if let .. { body } else { break; }
+            // }
+            // ```
+            // There is no observable change in drop order on the overall `if let` expression
+            // given that the `{ break; }` block is trivial so the edition change
+            // means nothing substantial to this `while` statement.
+            self.skip.insert(value.hir_id);
+            return;
+        }
         if expr_parent_is_stmt(cx.tcx, expr.hir_id)
             && matches!(expr.kind, hir::ExprKind::If(_cond, _conseq, None))
         {
@@ -304,7 +330,7 @@ impl Subdiagnostic for IfLetRescopeRewrite {
                 .chain(repeat('}').take(closing_brackets.count))
                 .collect(),
         ));
-        let msg = f(diag, crate::fluent_generated::lint_suggestion.into());
+        let msg = f(diag, crate::fluent_generated::lint_suggestion);
         diag.multipart_suggestion_with_style(
             msg,
             suggestions,
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
index a073d16f634..d029ad93407 100644
--- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -258,9 +258,9 @@ where
             && self.seen.insert(opaque_def_id)
             // If it's owned by this function
             && let opaque =
-                self.tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty()
-            && let hir::OpaqueTyOrigin::FnReturn(parent_def_id) = opaque.origin
-            && parent_def_id == self.parent_def_id
+                self.tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty()
+            && let hir::OpaqueTyOrigin::FnReturn { parent, .. } = opaque.origin
+            && parent == self.parent_def_id
         {
             let opaque_span = self.tcx.def_span(opaque_def_id);
             let new_capture_rules =
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index de401397150..6d5903ac467 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -18,7 +18,7 @@ use std::any::Any;
 use std::cell::Cell;
 
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_data_structures::sync::{Lrc, join};
+use rustc_data_structures::sync::join;
 use rustc_hir as hir;
 use rustc_hir::def_id::{LocalDefId, LocalModDefId};
 use rustc_hir::{HirId, intravisit as hir_visit};
@@ -36,8 +36,7 @@ use crate::{LateContext, LateLintPass, LintStore};
 ///
 /// This function exists because [`Session::lint_store`] is type-erased.
 pub fn unerased_lint_store(sess: &Session) -> &LintStore {
-    let store: &Lrc<_> = sess.lint_store.as_ref().unwrap();
-    let store: &dyn Any = &**store;
+    let store: &dyn Any = sess.lint_store.as_deref().unwrap();
     store.downcast_ref().unwrap()
 }
 
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index c74cb866f21..81352af3d48 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -32,7 +32,6 @@
 #![feature(array_windows)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
-#![feature(control_flow_enum)]
 #![feature(extract_if)]
 #![feature(if_let_guard)]
 #![feature(iter_order_by)]
@@ -571,6 +570,11 @@ fn register_builtins(store: &mut LintStore) {
          <https://rust-lang.github.io/rfcs/3535-constants-in-patterns.html> for more information",
     );
     store.register_removed(
+        "deprecated_cfg_attr_crate_type_name",
+        "converted into hard error, see issue #91632 \
+         <https://github.com/rust-lang/rust/issues/91632> for more information",
+    );
+    store.register_removed(
         "pointer_structural_match",
         "converted into hard error, see RFC #3535 \
          <https://rust-lang.github.io/rfcs/3535-constants-in-patterns.html> for more information",
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 0045cfcaa56..a861894a444 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1703,7 +1703,7 @@ pub(crate) enum InvalidNanComparisons {
     #[diag(lint_invalid_nan_comparisons_eq_ne)]
     EqNe {
         #[subdiagnostic]
-        suggestion: Option<InvalidNanComparisonsSuggestion>,
+        suggestion: InvalidNanComparisonsSuggestion,
     },
     #[diag(lint_invalid_nan_comparisons_lt_le_gt_ge)]
     LtLeGtGe,
@@ -2442,14 +2442,6 @@ pub(crate) struct DuplicateMacroAttribute;
 pub(crate) struct CfgAttrNoAttributes;
 
 #[derive(LintDiagnostic)]
-#[diag(lint_crate_type_in_cfg_attr_deprecated)]
-pub(crate) struct CrateTypeInCfgAttr;
-
-#[derive(LintDiagnostic)]
-#[diag(lint_crate_name_in_cfg_attr_deprecated)]
-pub(crate) struct CrateNameInCfgAttr;
-
-#[derive(LintDiagnostic)]
 #[diag(lint_missing_fragment_specifier)]
 pub(crate) struct MissingFragmentSpecifier;
 
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 83652bbf546..ffbcf7f808e 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -68,8 +68,8 @@ declare_lint! {
 declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]);
 
 impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
-        let hir::ItemKind::OpaqueTy(opaque) = &item.kind else {
+    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx>) {
+        let hir::TyKind::OpaqueDef(opaque, _) = &ty.kind else {
             return;
         };
 
@@ -77,14 +77,14 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
         // That's because although we may have an opaque type on the function,
         // it won't have a hidden type, so proving predicates about it is
         // not really meaningful.
-        if let hir::OpaqueTyOrigin::FnReturn(method_def_id) = opaque.origin
+        if let hir::OpaqueTyOrigin::FnReturn { parent: method_def_id, .. } = opaque.origin
             && let hir::Node::TraitItem(trait_item) = cx.tcx.hir_node_by_def_id(method_def_id)
             && !trait_item.defaultness.has_value()
         {
             return;
         }
 
-        let def_id = item.owner_id.def_id.to_def_id();
+        let def_id = opaque.def_id.to_def_id();
         let infcx = &cx.tcx.infer_ctxt().build();
         // For every projection predicate in the opaque type's explicit bounds,
         // check that the type that we're assigning actually satisfies the bounds
@@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
                     && cx.tcx.parent(opaque_ty.def_id) == def_id
                     && matches!(
                         opaque.origin,
-                        hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_)
+                        hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. }
                     )
                 {
                     return;
@@ -114,8 +114,10 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
                 // return type is well-formed in traits even when `Self` isn't sized.
                 if let ty::Param(param_ty) = *proj_term.kind()
                     && param_ty.name == kw::SelfUpper
-                    && matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(_))
-                    && opaque.in_trait
+                    && matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn {
+                        in_trait_or_impl: Some(hir::RpitContext::Trait),
+                        ..
+                    })
                 {
                     return;
                 }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 15fe18adbfb..db4413149a4 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -209,36 +209,32 @@ fn lint_nan<'tcx>(
     }
 
     fn eq_ne(
-        cx: &LateContext<'_>,
         e: &hir::Expr<'_>,
         l: &hir::Expr<'_>,
         r: &hir::Expr<'_>,
         f: impl FnOnce(Span, Span) -> InvalidNanComparisonsSuggestion,
     ) -> InvalidNanComparisons {
-        // FIXME(#72505): This suggestion can be restored if `f{32,64}::is_nan` is made const.
-        let suggestion = (!cx.tcx.hir().is_inside_const_context(e.hir_id)).then(|| {
-            if let Some(l_span) = l.span.find_ancestor_inside(e.span)
-                && let Some(r_span) = r.span.find_ancestor_inside(e.span)
-            {
-                f(l_span, r_span)
-            } else {
-                InvalidNanComparisonsSuggestion::Spanless
-            }
-        });
+        let suggestion = if let Some(l_span) = l.span.find_ancestor_inside(e.span)
+            && let Some(r_span) = r.span.find_ancestor_inside(e.span)
+        {
+            f(l_span, r_span)
+        } else {
+            InvalidNanComparisonsSuggestion::Spanless
+        };
 
         InvalidNanComparisons::EqNe { suggestion }
     }
 
     let lint = match binop.node {
         hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, l) => {
-            eq_ne(cx, e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
+            eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
                 nan_plus_binop: l_span.until(r_span),
                 float: r_span.shrink_to_hi(),
                 neg: (binop.node == hir::BinOpKind::Ne).then(|| r_span.shrink_to_lo()),
             })
         }
         hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, r) => {
-            eq_ne(cx, e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
+            eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
                 nan_plus_binop: l_span.shrink_to_hi().to(r_span),
                 float: l_span.shrink_to_hi(),
                 neg: (binop.node == hir::BinOpKind::Ne).then(|| l_span.shrink_to_lo()),
@@ -1423,7 +1419,6 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
             hir::ItemKind::Impl(..)
             | hir::ItemKind::TraitAlias(..)
             | hir::ItemKind::Trait(..)
-            | hir::ItemKind::OpaqueTy(..)
             | hir::ItemKind::GlobalAsm(..)
             | hir::ItemKind::ForeignMod { .. }
             | hir::ItemKind::Mod(..)
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 549dc64a562..a123059df8f 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -34,7 +34,6 @@ declare_lint_pass! {
         DEAD_CODE,
         DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK,
         DEPRECATED,
-        DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
         DEPRECATED_IN_FUTURE,
         DEPRECATED_SAFE_2024,
         DEPRECATED_WHERE_CLAUSE_LOCATION,
@@ -81,6 +80,7 @@ declare_lint_pass! {
         PRIVATE_INTERFACES,
         PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
         PTR_CAST_ADD_AUTO_TO_OBJECT,
+        PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS,
         PUB_USE_OF_PRIVATE_EXTERN_CRATE,
         REDUNDANT_IMPORTS,
         REDUNDANT_LIFETIMES,
@@ -2925,16 +2925,16 @@ declare_lint! {
     /// ```rust
     /// #![feature(asm_experimental_arch, naked_functions)]
     ///
-    /// use std::arch::asm;
+    /// use std::arch::naked_asm;
     ///
     /// #[naked]
     /// pub fn default_abi() -> u32 {
-    ///     unsafe { asm!("", options(noreturn)); }
+    ///     unsafe { naked_asm!(""); }
     /// }
     ///
     /// #[naked]
     /// pub extern "Rust" fn rust_abi() -> u32 {
-    ///     unsafe { asm!("", options(noreturn)); }
+    ///     unsafe { naked_asm!(""); }
     /// }
     /// ```
     ///
@@ -3144,42 +3144,6 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `deprecated_cfg_attr_crate_type_name` lint detects uses of the
-    /// `#![cfg_attr(..., crate_type = "...")]` and
-    /// `#![cfg_attr(..., crate_name = "...")]` attributes to conditionally
-    /// specify the crate type and name in the source code.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,compile_fail
-    /// #![cfg_attr(debug_assertions, crate_type = "lib")]
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    ///
-    /// ### Explanation
-    ///
-    /// The `#![crate_type]` and `#![crate_name]` attributes require a hack in
-    /// the compiler to be able to change the used crate type and crate name
-    /// after macros have been expanded. Neither attribute works in combination
-    /// with Cargo as it explicitly passes `--crate-type` and `--crate-name` on
-    /// the commandline. These values must match the value used in the source
-    /// code to prevent an error.
-    ///
-    /// To fix the warning use `--crate-type` on the commandline when running
-    /// rustc instead of `#![cfg_attr(..., crate_type = "...")]` and
-    /// `--crate-name` instead of `#![cfg_attr(..., crate_name = "...")]`.
-    pub DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
-    Deny,
-    "detects usage of `#![cfg_attr(..., crate_type/crate_name = \"...\")]`",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
-        reference: "issue #91632 <https://github.com/rust-lang/rust/issues/91632>",
-    };
-}
-
-declare_lint! {
     /// The `unexpected_cfgs` lint detects unexpected conditional compilation conditions.
     ///
     /// ### Example
@@ -4998,3 +4962,37 @@ declare_lint! {
         reference: "issue #124535 <https://github.com/rust-lang/rust/issues/124535>",
     };
 }
+
+declare_lint! {
+    /// The `ptr_to_integer_transmute_in_consts` lint detects pointer to integer
+    /// transmute in const functions and associated constants.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// const fn foo(ptr: *const u8) -> usize {
+    ///    unsafe {
+    ///        std::mem::transmute::<*const u8, usize>(ptr)
+    ///    }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Transmuting pointers to integers in a `const` context is undefined behavior.
+    /// Any attempt to use the resulting integer will abort const-evaluation.
+    ///
+    /// But sometimes the compiler might not emit an error for pointer to integer transmutes
+    /// inside const functions and associated consts because they are evaluated only when referenced.
+    /// Therefore, this lint serves as an extra layer of defense to prevent any undefined behavior
+    /// from compiling without any warnings or errors.
+    ///
+    /// See [std::mem::transmute] in the reference for more details.
+    ///
+    /// [std::mem::transmute]: https://doc.rust-lang.org/std/mem/fn.transmute.html
+    pub PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS,
+    Warn,
+    "detects pointer to integer transmutes in const functions and associated constants",
+}
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 734e7069c90..386918a5c41 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -720,8 +720,6 @@ pub enum BuiltinLintDiag {
     UnnameableTestItems,
     DuplicateMacroAttribute,
     CfgAttrNoAttributes,
-    CrateTypeInCfgAttr,
-    CrateNameInCfgAttr,
     MissingFragmentSpecifier,
     MetaVariableStillRepeating(MacroRulesNormalizedIdent),
     MetaVariableWrongOperator,
diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml
index 1f74aaf9965..b29d6b79250 100644
--- a/compiler/rustc_llvm/Cargo.toml
+++ b/compiler/rustc_llvm/Cargo.toml
@@ -10,5 +10,5 @@ libc = "0.2.73"
 
 [build-dependencies]
 # tidy-alphabetical-start
-cc = "=1.0.105" # FIXME(cc): pinned to keep support for VS2013
+cc = "1.1.23"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 10f2087d1e6..b817b4cb7b8 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -1,9 +1,7 @@
 // tidy-alphabetical-start
 #![allow(internal_features)]
-#![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
-#![feature(control_flow_enum)]
 #![feature(coroutines)]
 #![feature(decl_macro)]
 #![feature(error_iter)]
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 089ac060ba8..99c673b021a 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -218,7 +218,7 @@ use std::ops::Deref;
 use std::path::{Path, PathBuf};
 use std::{cmp, fmt};
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::owned_slice::slice_owned;
 use rustc_data_structures::svh::Svh;
@@ -385,7 +385,7 @@ impl<'a> CrateLocator<'a> {
         let dylib_suffix = &self.target.dll_suffix;
         let staticlib_suffix = &self.target.staticlib_suffix;
 
-        let mut candidates: FxHashMap<_, (FxHashMap<_, _>, FxHashMap<_, _>, FxHashMap<_, _>)> =
+        let mut candidates: FxIndexMap<_, (FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>)> =
             Default::default();
 
         // First, find all possible candidate rlibs and dylibs purely based on
@@ -460,7 +460,7 @@ impl<'a> CrateLocator<'a> {
         // A Library candidate is created if the metadata for the set of
         // libraries corresponds to the crate id and hash criteria that this
         // search is being performed for.
-        let mut libraries = FxHashMap::default();
+        let mut libraries = FxIndexMap::default();
         for (_hash, (rlibs, rmetas, dylibs)) in candidates {
             if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs)? {
                 libraries.insert(svh, lib);
@@ -494,9 +494,9 @@ impl<'a> CrateLocator<'a> {
 
     fn extract_lib(
         &mut self,
-        rlibs: FxHashMap<PathBuf, PathKind>,
-        rmetas: FxHashMap<PathBuf, PathKind>,
-        dylibs: FxHashMap<PathBuf, PathKind>,
+        rlibs: FxIndexMap<PathBuf, PathKind>,
+        rmetas: FxIndexMap<PathBuf, PathKind>,
+        dylibs: FxIndexMap<PathBuf, PathKind>,
     ) -> Result<Option<(Svh, Library)>, CrateError> {
         let mut slot = None;
         // Order here matters, rmeta should come first. See comment in
@@ -534,7 +534,7 @@ impl<'a> CrateLocator<'a> {
     // The `PathBuf` in `slot` will only be used for diagnostic purposes.
     fn extract_one(
         &mut self,
-        m: FxHashMap<PathBuf, PathKind>,
+        m: FxIndexMap<PathBuf, PathKind>,
         flavor: CrateFlavor,
         slot: &mut Option<(Svh, MetadataBlob, PathBuf)>,
     ) -> Result<Option<(PathBuf, PathKind)>, CrateError> {
@@ -702,9 +702,9 @@ impl<'a> CrateLocator<'a> {
         // First, filter out all libraries that look suspicious. We only accept
         // files which actually exist that have the correct naming scheme for
         // rlibs/dylibs.
-        let mut rlibs = FxHashMap::default();
-        let mut rmetas = FxHashMap::default();
-        let mut dylibs = FxHashMap::default();
+        let mut rlibs = FxIndexMap::default();
+        let mut rmetas = FxIndexMap::default();
+        let mut dylibs = FxIndexMap::default();
         for loc in &self.exact_paths {
             if !loc.canonicalized().exists() {
                 return Err(CrateError::ExternLocationNotExist(
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 82b907d2501..c7953d50406 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -1,7 +1,7 @@
 use std::ops::ControlFlow;
 use std::path::{Path, PathBuf};
 
-use rustc_ast::{CRATE_NODE_ID, NestedMetaItem};
+use rustc_ast::CRATE_NODE_ID;
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::query::LocalCrate;
@@ -304,7 +304,12 @@ impl<'tcx> Collector<'tcx> {
                             sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() });
                             continue;
                         };
-                        let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else {
+                        let [link_cfg] = link_cfg else {
+                            sess.dcx()
+                                .emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
+                            continue;
+                        };
+                        let Some(link_cfg) = link_cfg.meta_item_or_bool() else {
                             sess.dcx()
                                 .emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
                             continue;
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 4425c93211a..f02fd2ab6fe 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1622,56 +1622,63 @@ impl<'a> CrateMetadataRef<'a> {
             );
 
             for virtual_dir in virtual_rust_source_base_dir.iter().flatten() {
-                if let Some(real_dir) = &sess.opts.real_rust_source_base_dir {
-                    if let rustc_span::FileName::Real(old_name) = name {
-                        if let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } =
-                            old_name
-                        {
-                            if let Ok(rest) = virtual_name.strip_prefix(virtual_dir) {
-                                let virtual_name = virtual_name.clone();
-
-                                // The std library crates are in
-                                // `$sysroot/lib/rustlib/src/rust/library`, whereas other crates
-                                // may be in `$sysroot/lib/rustlib/src/rust/` directly. So we
-                                // detect crates from the std libs and handle them specially.
-                                const STD_LIBS: &[&str] = &[
-                                    "core",
-                                    "alloc",
-                                    "std",
-                                    "test",
-                                    "term",
-                                    "unwind",
-                                    "proc_macro",
-                                    "panic_abort",
-                                    "panic_unwind",
-                                    "profiler_builtins",
-                                    "rtstartup",
-                                    "rustc-std-workspace-core",
-                                    "rustc-std-workspace-alloc",
-                                    "rustc-std-workspace-std",
-                                    "backtrace",
-                                ];
-                                let is_std_lib = STD_LIBS.iter().any(|l| rest.starts_with(l));
-
-                                let new_path = if is_std_lib {
-                                    real_dir.join("library").join(rest)
-                                } else {
-                                    real_dir.join(rest)
-                                };
-
-                                debug!(
-                                    "try_to_translate_virtual_to_real: `{}` -> `{}`",
-                                    virtual_name.display(),
-                                    new_path.display(),
-                                );
-                                let new_name = rustc_span::RealFileName::Remapped {
-                                    local_path: Some(new_path),
-                                    virtual_name,
-                                };
-                                *old_name = new_name;
-                            }
+                if let Some(real_dir) = &sess.opts.real_rust_source_base_dir
+                    && let rustc_span::FileName::Real(old_name) = name
+                    && let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } =
+                        old_name
+                    && let Ok(rest) = virtual_name.strip_prefix(virtual_dir)
+                {
+                    // The std library crates are in
+                    // `$sysroot/lib/rustlib/src/rust/library`, whereas other crates
+                    // may be in `$sysroot/lib/rustlib/src/rust/` directly. So we
+                    // detect crates from the std libs and handle them specially.
+                    const STD_LIBS: &[&str] = &[
+                        "core",
+                        "alloc",
+                        "std",
+                        "test",
+                        "term",
+                        "unwind",
+                        "proc_macro",
+                        "panic_abort",
+                        "panic_unwind",
+                        "profiler_builtins",
+                        "rtstartup",
+                        "rustc-std-workspace-core",
+                        "rustc-std-workspace-alloc",
+                        "rustc-std-workspace-std",
+                        "backtrace",
+                    ];
+                    let is_std_lib = STD_LIBS.iter().any(|l| rest.starts_with(l));
+
+                    let new_path = if is_std_lib {
+                        real_dir.join("library").join(rest)
+                    } else {
+                        real_dir.join(rest)
+                    };
+
+                    debug!(
+                        "try_to_translate_virtual_to_real: `{}` -> `{}`",
+                        virtual_name.display(),
+                        new_path.display(),
+                    );
+
+                    // Check if the translated real path is affected by any user-requested
+                    // remaps via --remap-path-prefix. Apply them if so.
+                    // Note that this is a special case for imported rust-src paths specified by
+                    // https://rust-lang.github.io/rfcs/3127-trim-paths.html#handling-sysroot-paths.
+                    // Other imported paths are not currently remapped (see #66251).
+                    let (user_remapped, applied) =
+                        sess.source_map().path_mapping().map_prefix(&new_path);
+                    let new_name = if applied {
+                        rustc_span::RealFileName::Remapped {
+                            local_path: Some(new_path.clone()),
+                            virtual_name: user_remapped.to_path_buf(),
                         }
-                    }
+                    } else {
+                        rustc_span::RealFileName::LocalPath(new_path)
+                    };
+                    *old_name = new_name;
                 }
             }
         };
@@ -1695,6 +1702,7 @@ impl<'a> CrateMetadataRef<'a> {
                 let rustc_span::SourceFile {
                     mut name,
                     src_hash,
+                    checksum_hash,
                     start_pos: original_start_pos,
                     source_len,
                     lines,
@@ -1745,6 +1753,7 @@ impl<'a> CrateMetadataRef<'a> {
                 let local_version = sess.source_map().new_imported_source_file(
                     name,
                     src_hash,
+                    checksum_hash,
                     stable_id,
                     source_len.to_u32(),
                     self.cnum,
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 5f756672b04..610c682d3a4 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1186,9 +1186,9 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
 
         DefKind::OpaqueTy => {
             let origin = tcx.opaque_type_origin(def_id);
-            if let hir::OpaqueTyOrigin::FnReturn(fn_def_id)
-            | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin
-                && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id)
+            if let hir::OpaqueTyOrigin::FnReturn { parent, .. }
+            | hir::OpaqueTyOrigin::AsyncFn { parent, .. } = origin
+                && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(parent)
                 && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
             {
                 false
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index e11361a615f..8fd5ff1f369 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -732,6 +732,19 @@ impl<'hir> Map<'hir> {
         }
     }
 
+    #[track_caller]
+    pub fn expect_opaque_ty(self, id: LocalDefId) -> &'hir OpaqueTy<'hir> {
+        match self.tcx.hir_node_by_def_id(id) {
+            Node::OpaqueTy(opaq) => opaq,
+            _ => {
+                bug!(
+                    "expected opaque type definition, found {}",
+                    self.node_to_string(self.tcx.local_def_id_to_hir_id(id))
+                )
+            }
+        }
+    }
+
     pub fn expect_expr(self, id: HirId) -> &'hir Expr<'hir> {
         match self.tcx.hir_node(id) {
             Node::Expr(expr) => expr,
@@ -923,6 +936,7 @@ impl<'hir> Map<'hir> {
             Node::Ty(ty) => ty.span,
             Node::AssocItemConstraint(constraint) => constraint.span,
             Node::TraitRef(tr) => tr.path.span,
+            Node::OpaqueTy(op) => op.span,
             Node::Pat(pat) => pat.span,
             Node::PatField(field) => field.span,
             Node::Arm(arm) => arm.span,
@@ -1006,6 +1020,10 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> {
         self.tcx.hir_node(hir_id)
     }
 
+    fn hir_node_by_def_id(&self, def_id: LocalDefId) -> Node<'hir> {
+        self.tcx.hir_node_by_def_id(def_id)
+    }
+
     fn body(&self, id: BodyId) -> &'hir Body<'hir> {
         (*self).body(id)
     }
@@ -1139,13 +1157,6 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
                 ItemKind::ForeignMod { .. } => "foreign mod",
                 ItemKind::GlobalAsm(..) => "global asm",
                 ItemKind::TyAlias(..) => "ty",
-                ItemKind::OpaqueTy(opaque) => {
-                    if opaque.in_trait {
-                        "opaque type in trait"
-                    } else {
-                        "opaque type"
-                    }
-                }
                 ItemKind::Enum(..) => "enum",
                 ItemKind::Struct(..) => "struct",
                 ItemKind::Union(..) => "union",
@@ -1197,6 +1208,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
         Node::Ty(_) => node_str("type"),
         Node::AssocItemConstraint(_) => node_str("assoc item constraint"),
         Node::TraitRef(_) => node_str("trait ref"),
+        Node::OpaqueTy(_) => node_str("opaque type"),
         Node::Pat(_) => node_str("pat"),
         Node::PatField(_) => node_str("pattern field"),
         Node::Param(_) => node_str("param"),
@@ -1234,6 +1246,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
         impl_items,
         foreign_items,
         body_owners,
+        opaques,
         ..
     } = collector;
     ModuleItems {
@@ -1243,6 +1256,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
         impl_items: impl_items.into_boxed_slice(),
         foreign_items: foreign_items.into_boxed_slice(),
         body_owners: body_owners.into_boxed_slice(),
+        opaques: opaques.into_boxed_slice(),
     }
 }
 
@@ -1262,6 +1276,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
         impl_items,
         foreign_items,
         body_owners,
+        opaques,
         ..
     } = collector;
 
@@ -1272,6 +1287,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
         impl_items: impl_items.into_boxed_slice(),
         foreign_items: foreign_items.into_boxed_slice(),
         body_owners: body_owners.into_boxed_slice(),
+        opaques: opaques.into_boxed_slice(),
     }
 }
 
@@ -1286,6 +1302,7 @@ struct ItemCollector<'tcx> {
     impl_items: Vec<ImplItemId>,
     foreign_items: Vec<ForeignItemId>,
     body_owners: Vec<LocalDefId>,
+    opaques: Vec<LocalDefId>,
 }
 
 impl<'tcx> ItemCollector<'tcx> {
@@ -1299,6 +1316,7 @@ impl<'tcx> ItemCollector<'tcx> {
             impl_items: Vec::default(),
             foreign_items: Vec::default(),
             body_owners: Vec::default(),
+            opaques: Vec::default(),
         }
     }
 }
@@ -1344,6 +1362,11 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
         intravisit::walk_inline_const(self, c)
     }
 
+    fn visit_opaque_ty(&mut self, o: &'hir OpaqueTy<'hir>) {
+        self.opaques.push(o.def_id);
+        intravisit::walk_opaque_ty(self, o)
+    }
+
     fn visit_expr(&mut self, ex: &'hir Expr<'hir>) {
         if let ExprKind::Closure(closure) = ex.kind {
             self.body_owners.push(closure.def_id);
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 7a07ef80ded..ad0d70152e1 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -28,6 +28,7 @@ pub struct ModuleItems {
     trait_items: Box<[TraitItemId]>,
     impl_items: Box<[ImplItemId]>,
     foreign_items: Box<[ForeignItemId]>,
+    opaques: Box<[LocalDefId]>,
     body_owners: Box<[LocalDefId]>,
 }
 
@@ -65,6 +66,10 @@ impl ModuleItems {
             .chain(self.foreign_items.iter().map(|id| id.owner_id))
     }
 
+    pub fn opaques(&self) -> impl Iterator<Item = LocalDefId> + '_ {
+        self.opaques.iter().copied()
+    }
+
     pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ {
         self.owners().map(|id| id.def_id)
     }
@@ -96,6 +101,13 @@ impl ModuleItems {
     ) -> Result<(), ErrorGuaranteed> {
         try_par_for_each_in(&self.foreign_items[..], |&id| f(id))
     }
+
+    pub fn par_opaques(
+        &self,
+        f: impl Fn(LocalDefId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
+    ) -> Result<(), ErrorGuaranteed> {
+        try_par_for_each_in(&self.opaques[..], |&id| f(id))
+    }
 }
 
 impl<'tcx> TyCtxt<'tcx> {
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index a32b19b067a..70e61df1ab4 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -61,6 +61,8 @@
 #![feature(trait_upcasting)]
 #![feature(trusted_len)]
 #![feature(try_blocks)]
+#![feature(try_trait_v2)]
+#![feature(try_trait_v2_yeet)]
 #![feature(type_alias_impl_trait)]
 #![feature(yeet_expr)]
 #![warn(unreachable_pub)]
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index d385be007d3..39816c17b98 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -67,7 +67,7 @@ macro_rules! TrivialLiftImpls {
     };
 }
 
-/// Used for types that are `Copy` and which **do not care arena
+/// Used for types that are `Copy` and which **do not care about arena
 /// allocated data** (i.e., don't need to be folded).
 #[macro_export]
 macro_rules! TrivialTypeTraversalImpls {
diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
index 32e2f3b4b16..13e35cd0909 100644
--- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
+++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
@@ -1,9 +1,9 @@
 //! Name resolution for lifetimes and late-bound type and const variables: type declarations.
 
-use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::sorted_map::SortedMap;
 use rustc_errors::ErrorGuaranteed;
+use rustc_hir::ItemLocalId;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::{ItemLocalId, OwnerId};
 use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable};
 
 use crate::ty;
@@ -47,11 +47,11 @@ pub enum ObjectLifetimeDefault {
 
 /// Maps the id of each lifetime reference to the lifetime decl
 /// that it corresponds to.
-#[derive(Default, HashStable, Debug)]
+#[derive(HashStable, Debug)]
 pub struct ResolveBoundVars {
     /// Maps from every use of a named (not anonymous) lifetime to a
     /// `Region` describing how that region is bound
-    pub defs: FxIndexMap<OwnerId, FxIndexMap<ItemLocalId, ResolvedArg>>,
+    pub defs: SortedMap<ItemLocalId, ResolvedArg>,
 
-    pub late_bound_vars: FxIndexMap<OwnerId, FxIndexMap<ItemLocalId, Vec<ty::BoundVariableKind>>>,
+    pub late_bound_vars: SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>>,
 }
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 54cfd995832..ee34ccd889f 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -217,7 +217,7 @@ pub fn early_report_macro_deprecation(
         suggestion_span: span,
         note: depr.note,
         path,
-        since_kind: deprecated_since_kind(is_in_effect, depr.since.clone()),
+        since_kind: deprecated_since_kind(is_in_effect, depr.since),
     };
     lint_buffer.buffer_lint(deprecation_lint(is_in_effect), node_id, span, diag);
 }
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index 89d4c460160..4262460d928 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -148,7 +148,7 @@ impl<'tcx> ConstValue<'tcx> {
                         /* read_provenance */ true,
                     )
                     .ok()?;
-                let ptr = ptr.to_pointer(&tcx).ok()?;
+                let ptr = ptr.to_pointer(&tcx).discard_err()?;
                 let len = a
                     .read_scalar(
                         &tcx,
@@ -156,7 +156,7 @@ impl<'tcx> ConstValue<'tcx> {
                         /* read_provenance */ false,
                     )
                     .ok()?;
-                let len = len.to_target_usize(&tcx).ok()?;
+                let len = len.to_target_usize(&tcx).discard_err()?;
                 if len == 0 {
                     return Some(&[]);
                 }
@@ -221,7 +221,9 @@ pub enum Const<'tcx> {
 }
 
 impl<'tcx> Const<'tcx> {
-    pub fn identity_unevaluated(
+    /// Creates an unevaluated const from a `DefId` for a const item.
+    /// The binders of the const item still need to be instantiated.
+    pub fn from_unevaluated(
         tcx: TyCtxt<'tcx>,
         def_id: DefId,
     ) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
@@ -329,18 +331,6 @@ impl<'tcx> Const<'tcx> {
         }
     }
 
-    /// Normalizes the constant to a value or an error if possible.
-    #[inline]
-    pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
-        match self.eval(tcx, param_env, DUMMY_SP) {
-            Ok(val) => Self::Val(val, self.ty()),
-            Err(ErrorHandled::Reported(guar, _span)) => {
-                Self::Ty(Ty::new_error(tcx, guar.into()), ty::Const::new_error(tcx, guar.into()))
-            }
-            Err(ErrorHandled::TooGeneric(_span)) => self,
-        }
-    }
-
     #[inline]
     pub fn try_eval_scalar(
         self,
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index b8ecfa3c3f9..04d035e27ba 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -20,7 +20,7 @@ use rustc_target::abi::{Align, HasDataLayout, Size};
 use super::{
     AllocId, BadBytesAccess, CtfeProvenance, InterpError, InterpResult, Pointer, PointerArithmetic,
     Provenance, ResourceExhaustionInfo, Scalar, ScalarSizeMismatch, UndefinedBehaviorInfo,
-    UnsupportedOpInfo, read_target_uint, write_target_uint,
+    UnsupportedOpInfo, interp_ok, read_target_uint, write_target_uint,
 };
 use crate::ty;
 
@@ -318,8 +318,9 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
     pub fn try_uninit<'tcx>(size: Size, align: Align) -> InterpResult<'tcx, Self> {
         Self::uninit_inner(size, align, || {
             ty::tls::with(|tcx| tcx.dcx().delayed_bug("exhausted memory during interpretation"));
-            InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted).into()
+            InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted)
         })
+        .into()
     }
 
     /// Try to create an Allocation of `size` bytes, panics if there is not enough memory
@@ -355,12 +356,12 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
 impl Allocation {
     /// Adjust allocation from the ones in `tcx` to a custom Machine instance
     /// with a different `Provenance` and `Byte` type.
-    pub fn adjust_from_tcx<Prov: Provenance, Bytes: AllocBytes, Err>(
+    pub fn adjust_from_tcx<'tcx, Prov: Provenance, Bytes: AllocBytes>(
         &self,
         cx: &impl HasDataLayout,
-        mut alloc_bytes: impl FnMut(&[u8], Align) -> Result<Bytes, Err>,
-        mut adjust_ptr: impl FnMut(Pointer<CtfeProvenance>) -> Result<Pointer<Prov>, Err>,
-    ) -> Result<Allocation<Prov, (), Bytes>, Err> {
+        mut alloc_bytes: impl FnMut(&[u8], Align) -> InterpResult<'tcx, Bytes>,
+        mut adjust_ptr: impl FnMut(Pointer<CtfeProvenance>) -> InterpResult<'tcx, Pointer<Prov>>,
+    ) -> InterpResult<'tcx, Allocation<Prov, (), Bytes>> {
         // Copy the data.
         let mut bytes = alloc_bytes(&*self.bytes, self.align)?;
         // Adjust provenance of pointers stored in this allocation.
@@ -377,7 +378,7 @@ impl Allocation {
             new_provenance.push((offset, ptr_prov));
         }
         // Create allocation.
-        Ok(Allocation {
+        interp_ok(Allocation {
             bytes,
             provenance: ProvenanceMap::from_presorted_ptrs(new_provenance),
             init_mask: self.init_mask.clone(),
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 46646e759d5..431043b0431 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -1,7 +1,7 @@
 use std::any::Any;
 use std::backtrace::Backtrace;
 use std::borrow::Cow;
-use std::fmt;
+use std::{convert, fmt, mem, ops};
 
 use either::Either;
 use rustc_ast_ir::Mutability;
@@ -104,6 +104,10 @@ rustc_data_structures::static_assert_size!(InterpErrorInfo<'_>, 8);
 /// These should always be constructed by calling `.into()` on
 /// an `InterpError`. In `rustc_mir::interpret`, we have `throw_err_*`
 /// macros for this.
+///
+/// Interpreter errors must *not* be silently discarded (that will lead to a panic). Instead,
+/// explicitly call `discard_err` if this is really the right thing to do. Note that if
+/// this happens during const-eval or in Miri, it could lead to a UB error being lost!
 #[derive(Debug)]
 pub struct InterpErrorInfo<'tcx>(Box<InterpErrorInfoInner<'tcx>>);
 
@@ -156,8 +160,11 @@ impl<'tcx> InterpErrorInfo<'tcx> {
     }
 
     pub fn into_kind(self) -> InterpError<'tcx> {
-        let InterpErrorInfo(box InterpErrorInfoInner { kind, .. }) = self;
-        kind
+        self.0.kind
+    }
+
+    pub fn from_parts(kind: InterpError<'tcx>, backtrace: InterpErrorBacktrace) -> Self {
+        Self(Box::new(InterpErrorInfoInner { kind, backtrace }))
     }
 
     #[inline]
@@ -599,8 +606,6 @@ pub enum InterpError<'tcx> {
     MachineStop(Box<dyn MachineStopType>),
 }
 
-pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
-
 impl InterpError<'_> {
     /// Some errors do string formatting even if the error is never printed.
     /// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors,
@@ -728,3 +733,182 @@ macro_rules! throw_exhaust {
 macro_rules! throw_machine_stop {
     ($($tt:tt)*) => { do yeet $crate::err_machine_stop!($($tt)*) };
 }
+
+/// Guard type that panics on drop.
+#[derive(Debug)]
+struct Guard;
+
+impl Drop for Guard {
+    fn drop(&mut self) {
+        // We silence the guard if we are already panicking, to avoid double-panics.
+        if !std::thread::panicking() {
+            panic!(
+                "an interpreter error got improperly discarded; use `discard_err()` if this is intentional"
+            );
+        }
+    }
+}
+
+/// The result type used by the interpreter. This is a newtype around `Result`
+/// to block access to operations like `ok()` that discard UB errors.
+///
+/// We also make things panic if this type is ever implicitly dropped.
+#[derive(Debug)]
+pub struct InterpResult_<'tcx, T> {
+    res: Result<T, InterpErrorInfo<'tcx>>,
+    guard: Guard,
+}
+
+// Type alias to be able to set a default type argument.
+pub type InterpResult<'tcx, T = ()> = InterpResult_<'tcx, T>;
+
+impl<'tcx, T> ops::Try for InterpResult_<'tcx, T> {
+    type Output = T;
+    type Residual = InterpResult_<'tcx, convert::Infallible>;
+
+    #[inline]
+    fn from_output(output: Self::Output) -> Self {
+        InterpResult_::new(Ok(output))
+    }
+
+    #[inline]
+    fn branch(self) -> ops::ControlFlow<Self::Residual, Self::Output> {
+        match self.disarm() {
+            Ok(v) => ops::ControlFlow::Continue(v),
+            Err(e) => ops::ControlFlow::Break(InterpResult_::new(Err(e))),
+        }
+    }
+}
+
+impl<'tcx, T> ops::FromResidual for InterpResult_<'tcx, T> {
+    #[inline]
+    #[track_caller]
+    fn from_residual(residual: InterpResult_<'tcx, convert::Infallible>) -> Self {
+        match residual.disarm() {
+            Err(e) => Self::new(Err(e)),
+        }
+    }
+}
+
+// Allow `yeet`ing `InterpError` in functions returning `InterpResult_`.
+impl<'tcx, T> ops::FromResidual<ops::Yeet<InterpError<'tcx>>> for InterpResult_<'tcx, T> {
+    #[inline]
+    fn from_residual(ops::Yeet(e): ops::Yeet<InterpError<'tcx>>) -> Self {
+        Self::new(Err(e.into()))
+    }
+}
+
+// Allow `?` on `Result<_, InterpError>` in functions returning `InterpResult_`.
+// This is useful e.g. for `option.ok_or_else(|| err_ub!(...))`.
+impl<'tcx, T, E: Into<InterpErrorInfo<'tcx>>> ops::FromResidual<Result<convert::Infallible, E>>
+    for InterpResult_<'tcx, T>
+{
+    #[inline]
+    fn from_residual(residual: Result<convert::Infallible, E>) -> Self {
+        match residual {
+            Err(e) => Self::new(Err(e.into())),
+        }
+    }
+}
+
+impl<'tcx, T, E: Into<InterpErrorInfo<'tcx>>> From<Result<T, E>> for InterpResult<'tcx, T> {
+    #[inline]
+    fn from(value: Result<T, E>) -> Self {
+        Self::new(value.map_err(|e| e.into()))
+    }
+}
+
+impl<'tcx, T, V: FromIterator<T>> FromIterator<InterpResult<'tcx, T>> for InterpResult<'tcx, V> {
+    fn from_iter<I: IntoIterator<Item = InterpResult<'tcx, T>>>(iter: I) -> Self {
+        Self::new(iter.into_iter().map(|x| x.disarm()).collect())
+    }
+}
+
+impl<'tcx, T> InterpResult_<'tcx, T> {
+    #[inline(always)]
+    fn new(res: Result<T, InterpErrorInfo<'tcx>>) -> Self {
+        Self { res, guard: Guard }
+    }
+
+    #[inline(always)]
+    fn disarm(self) -> Result<T, InterpErrorInfo<'tcx>> {
+        mem::forget(self.guard);
+        self.res
+    }
+
+    /// Discard the error information in this result. Only use this if ignoring Undefined Behavior is okay!
+    #[inline]
+    pub fn discard_err(self) -> Option<T> {
+        self.disarm().ok()
+    }
+
+    /// Look at the `Result` wrapped inside of this.
+    /// Must only be used to report the error!
+    #[inline]
+    pub fn report_err(self) -> Result<T, InterpErrorInfo<'tcx>> {
+        self.disarm()
+    }
+
+    #[inline]
+    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> InterpResult<'tcx, U> {
+        InterpResult_::new(self.disarm().map(f))
+    }
+
+    #[inline]
+    pub fn map_err(
+        self,
+        f: impl FnOnce(InterpErrorInfo<'tcx>) -> InterpErrorInfo<'tcx>,
+    ) -> InterpResult<'tcx, T> {
+        InterpResult_::new(self.disarm().map_err(f))
+    }
+
+    #[inline]
+    pub fn inspect_err(self, f: impl FnOnce(&InterpErrorInfo<'tcx>)) -> InterpResult<'tcx, T> {
+        InterpResult_::new(self.disarm().inspect_err(f))
+    }
+
+    #[inline]
+    #[track_caller]
+    pub fn unwrap(self) -> T {
+        self.disarm().unwrap()
+    }
+
+    #[inline]
+    #[track_caller]
+    pub fn unwrap_or_else(self, f: impl FnOnce(InterpErrorInfo<'tcx>) -> T) -> T {
+        self.disarm().unwrap_or_else(f)
+    }
+
+    #[inline]
+    #[track_caller]
+    pub fn expect(self, msg: &str) -> T {
+        self.disarm().expect(msg)
+    }
+
+    #[inline]
+    pub fn and_then<U>(self, f: impl FnOnce(T) -> InterpResult<'tcx, U>) -> InterpResult<'tcx, U> {
+        InterpResult_::new(self.disarm().and_then(|t| f(t).disarm()))
+    }
+
+    /// Returns success if both `self` and `other` succeed, while ensuring we don't
+    /// accidentally drop an error.
+    ///
+    /// If both are an error, `self` will be reported.
+    #[inline]
+    pub fn and<U>(self, other: InterpResult<'tcx, U>) -> InterpResult<'tcx, (T, U)> {
+        match self.disarm() {
+            Ok(t) => interp_ok((t, other?)),
+            Err(e) => {
+                // Discard the other error.
+                drop(other.disarm());
+                // Return `self`.
+                InterpResult_::new(Err(e))
+            }
+        }
+    }
+}
+
+#[inline(always)]
+pub fn interp_ok<'tcx, T>(x: T) -> InterpResult<'tcx, T> {
+    InterpResult_::new(Ok(x))
+}
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index d7809cc4343..115bcdbc589 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -39,7 +39,7 @@ pub use self::error::{
     InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo,
     MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo,
     ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo,
-    ValidationErrorKind,
+    ValidationErrorKind, interp_ok,
 };
 pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance};
 pub use self::value::Scalar;
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index c6c2ab414ed..061a55bfda8 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -8,7 +8,7 @@ use rustc_target::abi::{HasDataLayout, Size};
 
 use super::{
     AllocId, CtfeProvenance, InterpResult, Pointer, PointerArithmetic, Provenance,
-    ScalarSizeMismatch,
+    ScalarSizeMismatch, interp_ok,
 };
 use crate::ty::ScalarInt;
 
@@ -273,10 +273,10 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
             .to_bits_or_ptr_internal(cx.pointer_size())
             .map_err(|s| err_ub!(ScalarSizeMismatch(s)))?
         {
-            Right(ptr) => Ok(ptr.into()),
+            Right(ptr) => interp_ok(ptr.into()),
             Left(bits) => {
                 let addr = u64::try_from(bits).unwrap();
-                Ok(Pointer::from_addr_invalid(addr))
+                interp_ok(Pointer::from_addr_invalid(addr))
             }
         }
     }
@@ -311,12 +311,12 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
         if matches!(self, Scalar::Ptr(..)) {
             *self = self.to_scalar_int()?.into();
         }
-        Ok(())
+        interp_ok(())
     }
 
     #[inline(always)]
     pub fn to_scalar_int(self) -> InterpResult<'tcx, ScalarInt> {
-        self.try_to_scalar_int().map_err(|_| err_unsup!(ReadPointerAsInt(None)).into())
+        self.try_to_scalar_int().map_err(|_| err_unsup!(ReadPointerAsInt(None))).into()
     }
 
     #[inline(always)]
@@ -330,20 +330,22 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
     #[inline]
     pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> {
         assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
-        self.to_scalar_int()?.try_to_bits(target_size).map_err(|size| {
-            err_ub!(ScalarSizeMismatch(ScalarSizeMismatch {
-                target_size: target_size.bytes(),
-                data_size: size.bytes(),
-            }))
+        self.to_scalar_int()?
+            .try_to_bits(target_size)
+            .map_err(|size| {
+                err_ub!(ScalarSizeMismatch(ScalarSizeMismatch {
+                    target_size: target_size.bytes(),
+                    data_size: size.bytes(),
+                }))
+            })
             .into()
-        })
     }
 
     pub fn to_bool(self) -> InterpResult<'tcx, bool> {
         let val = self.to_u8()?;
         match val {
-            0 => Ok(false),
-            1 => Ok(true),
+            0 => interp_ok(false),
+            1 => interp_ok(true),
             _ => throw_ub!(InvalidBool(val)),
         }
     }
@@ -351,7 +353,7 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
     pub fn to_char(self) -> InterpResult<'tcx, char> {
         let val = self.to_u32()?;
         match std::char::from_u32(val) {
-            Some(c) => Ok(c),
+            Some(c) => interp_ok(c),
             None => throw_ub!(InvalidChar(val)),
         }
     }
@@ -392,7 +394,7 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
     /// Fails if the scalar is a pointer.
     pub fn to_target_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
         let b = self.to_uint(cx.data_layout().pointer_size)?;
-        Ok(u64::try_from(b).unwrap())
+        interp_ok(u64::try_from(b).unwrap())
     }
 
     /// Converts the scalar to produce a signed integer of the given size.
@@ -400,7 +402,7 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
     #[inline]
     pub fn to_int(self, size: Size) -> InterpResult<'tcx, i128> {
         let b = self.to_bits(size)?;
-        Ok(size.sign_extend(b))
+        interp_ok(size.sign_extend(b))
     }
 
     /// Converts the scalar to produce an `i8`. Fails if the scalar is a pointer.
@@ -432,13 +434,13 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
     /// Fails if the scalar is a pointer.
     pub fn to_target_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> {
         let b = self.to_int(cx.data_layout().pointer_size)?;
-        Ok(i64::try_from(b).unwrap())
+        interp_ok(i64::try_from(b).unwrap())
     }
 
     #[inline]
     pub fn to_float<F: Float>(self) -> InterpResult<'tcx, F> {
         // Going through `to_bits` to check size and truncation.
-        Ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?))
+        interp_ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?))
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 954f746ce5b..56ca9167d4d 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -15,6 +15,7 @@ use rustc_query_system::ich::StableHashingContext;
 use rustc_session::config::OptLevel;
 use rustc_span::Span;
 use rustc_span::symbol::Symbol;
+use rustc_target::spec::SymbolVisibility;
 use tracing::debug;
 
 use crate::dep_graph::{DepNode, WorkProduct, WorkProductId};
@@ -305,6 +306,16 @@ pub enum Visibility {
     Protected,
 }
 
+impl From<SymbolVisibility> for Visibility {
+    fn from(value: SymbolVisibility) -> Self {
+        match value {
+            SymbolVisibility::Hidden => Visibility::Hidden,
+            SymbolVisibility::Protected => Visibility::Protected,
+            SymbolVisibility::Interposable => Visibility::Default,
+        }
+    }
+}
+
 impl<'tcx> CodegenUnit<'tcx> {
     #[inline]
     pub fn new(name: Symbol) -> CodegenUnit<'tcx> {
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 48789565218..9cafe804a8e 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -4,7 +4,7 @@ use std::fs;
 use std::io::{self, Write as _};
 use std::path::{Path, PathBuf};
 
-use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_ast::InlineAsmTemplatePiece;
 use rustc_middle::mir::interpret::{
     AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer, Provenance, alloc_range,
     read_target_uint,
@@ -1024,9 +1024,9 @@ impl<'tcx> TerminatorKind<'tcx> {
                 vec!["real".into(), "unwind".into()]
             }
             FalseUnwind { unwind: _, .. } => vec!["real".into()],
-            InlineAsm { options, ref targets, unwind, .. } => {
+            InlineAsm { asm_macro, options, ref targets, unwind, .. } => {
                 let mut vec = Vec::with_capacity(targets.len() + 1);
-                if !options.contains(InlineAsmOptions::NORETURN) {
+                if !asm_macro.diverges(options) {
                     vec.push("return".into());
                 }
                 vec.resize(targets.len(), "label".into());
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index ae75f2d4187..c610fac80f6 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -605,6 +605,25 @@ impl CallSource {
     }
 }
 
+#[derive(Clone, Copy, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
+#[derive(TypeFoldable, TypeVisitable)]
+/// The macro that an inline assembly block was created by
+pub enum InlineAsmMacro {
+    /// The `asm!` macro
+    Asm,
+    /// The `naked_asm!` macro
+    NakedAsm,
+}
+
+impl InlineAsmMacro {
+    pub const fn diverges(self, options: InlineAsmOptions) -> bool {
+        match self {
+            InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN),
+            InlineAsmMacro::NakedAsm => true,
+        }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // Terminators
 
@@ -859,6 +878,9 @@ pub enum TerminatorKind<'tcx> {
     /// Block ends with an inline assembly block. This is a terminator since
     /// inline assembly is allowed to diverge.
     InlineAsm {
+        /// Macro used to create this inline asm: one of `asm!` or `naked_asm!`
+        asm_macro: InlineAsmMacro,
+
         /// The template for the inline assembly, with placeholders.
         template: &'tcx [InlineAsmTemplatePiece],
 
@@ -874,7 +896,7 @@ pub enum TerminatorKind<'tcx> {
 
         /// Valid targets for the inline assembly.
         /// The first element is the fallthrough destination, unless
-        /// InlineAsmOptions::NORETURN is set.
+        /// asm_macro == InlineAsmMacro::NakedAsm or InlineAsmOptions::NORETURN is set.
         targets: Box<[BasicBlock]>,
 
         /// Action to be taken if the inline assembly unwinds. This is present
@@ -1135,8 +1157,10 @@ pub enum ProjectionElem<V, T> {
     ConstantIndex {
         /// index or -index (in Python terms), depending on from_end
         offset: u64,
-        /// The thing being indexed must be at least this long. For arrays this
-        /// is always the exact length.
+        /// The thing being indexed must be at least this long -- otherwise, the
+        /// projection is UB.
+        ///
+        /// For arrays this is always the exact length.
         min_length: u64,
         /// Counting backwards from end? This is always false when indexing an
         /// array.
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 783952fb9cb..b919f5726db 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -666,6 +666,7 @@ impl<'tcx> TerminatorKind<'tcx> {
             },
 
             InlineAsm {
+                asm_macro: _,
                 template: _,
                 ref operands,
                 options: _,
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 64898a8495e..9f9ee8497b6 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -576,6 +576,7 @@ macro_rules! make_mir_visitor {
                     }
 
                     TerminatorKind::InlineAsm {
+                        asm_macro: _,
                         template: _,
                         operands,
                         options: _,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 989fbd711c3..f0be70e00df 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -16,6 +16,7 @@ use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
+use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
@@ -1552,7 +1553,7 @@ rustc_queries! {
         feedable
     }
 
-    query check_well_formed(key: hir::OwnerId) -> Result<(), ErrorGuaranteed> {
+    query check_well_formed(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
         desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key) }
         ensure_forwards_result_if_red
     }
@@ -1738,29 +1739,28 @@ rustc_queries! {
     /// Does lifetime resolution on items. Importantly, we can't resolve
     /// lifetimes directly on things like trait methods, because of trait params.
     /// See `rustc_resolve::late::lifetimes` for details.
-    query resolve_bound_vars(_: hir::OwnerId) -> &'tcx ResolveBoundVars {
+    query resolve_bound_vars(owner_id: hir::OwnerId) -> &'tcx ResolveBoundVars {
         arena_cache
-        desc { "resolving lifetimes" }
+        desc { |tcx| "resolving lifetimes for `{}`", tcx.def_path_str(owner_id) }
     }
-    query named_variable_map(_: hir::OwnerId) ->
-        Option<&'tcx FxIndexMap<ItemLocalId, ResolvedArg>> {
-        desc { "looking up a named region" }
+    query named_variable_map(owner_id: hir::OwnerId) -> &'tcx SortedMap<ItemLocalId, ResolvedArg> {
+        desc { |tcx| "looking up a named region inside `{}`", tcx.def_path_str(owner_id) }
     }
-    query is_late_bound_map(_: hir::OwnerId) -> Option<&'tcx FxIndexSet<ItemLocalId>> {
-        desc { "testing if a region is late bound" }
+    query is_late_bound_map(owner_id: hir::OwnerId) -> Option<&'tcx FxIndexSet<ItemLocalId>> {
+        desc { |tcx| "testing if a region is late bound inside `{}`", tcx.def_path_str(owner_id) }
     }
     /// For a given item's generic parameter, gets the default lifetimes to be used
     /// for each parameter if a trait object were to be passed for that parameter.
     /// For example, for `T` in `struct Foo<'a, T>`, this would be `'static`.
     /// For `T` in `struct Foo<'a, T: 'a>`, this would instead be `'a`.
     /// This query will panic if passed something that is not a type parameter.
-    query object_lifetime_default(key: DefId) -> ObjectLifetimeDefault {
-        desc { "looking up lifetime defaults for generic parameter `{}`", tcx.def_path_str(key) }
+    query object_lifetime_default(def_id: DefId) -> ObjectLifetimeDefault {
+        desc { "looking up lifetime defaults for generic parameter `{}`", tcx.def_path_str(def_id) }
         separate_provide_extern
     }
-    query late_bound_vars_map(_: hir::OwnerId)
-        -> Option<&'tcx FxIndexMap<ItemLocalId, Vec<ty::BoundVariableKind>>> {
-        desc { "looking up late bound vars" }
+    query late_bound_vars_map(owner_id: hir::OwnerId)
+        -> &'tcx SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>> {
+        desc { |tcx| "looking up late bound vars inside `{}`", tcx.def_path_str(owner_id) }
     }
 
     /// Computes the visibility of the provided `def_id`.
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index e614d41899a..fe865b8a515 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -12,7 +12,7 @@ use std::cmp::Ordering;
 use std::fmt;
 use std::ops::Index;
 
-use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_ast::{AsmMacro, InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd};
@@ -173,6 +173,7 @@ pub struct ClosureExpr<'tcx> {
 
 #[derive(Clone, Debug, HashStable)]
 pub struct InlineAsmExpr<'tcx> {
+    pub asm_macro: AsmMacro,
     pub template: &'tcx [InlineAsmTemplatePiece],
     pub operands: Box<[InlineAsmOperand<'tcx>]>,
     pub options: InlineAsmOptions,
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 58e2ebaeaf8..36f0e3d890c 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -148,7 +148,13 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
         NamedConst { def_id: _, args: _, user_ty: _ } => {}
         ConstParam { param: _, def_id: _ } => {}
         StaticRef { alloc_id: _, ty: _, def_id: _ } => {}
-        InlineAsm(box InlineAsmExpr { ref operands, template: _, options: _, line_spans: _ }) => {
+        InlineAsm(box InlineAsmExpr {
+            asm_macro: _,
+            ref operands,
+            template: _,
+            options: _,
+            line_spans: _,
+        }) => {
             for op in &**operands {
                 use InlineAsmOperand::*;
                 match op {
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index 41a20e89cbf..71833eea5c0 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -25,10 +25,10 @@ pub enum PointerCoercion {
     ArrayToPointer,
 
     /// Unsize a pointer/reference value, e.g., `&[T; n]` to
-    /// `&[T]`. Note that the source could be a thin or fat pointer.
-    /// This will do things like convert thin pointers to fat
+    /// `&[T]`. Note that the source could be a thin or wide pointer.
+    /// This will do things like convert thin pointers to wide
     /// pointers, or convert structs containing thin pointers to
-    /// structs containing fat pointers, or convert between fat
+    /// structs containing wide pointers, or convert between wide
     /// pointers. We don't store the details of how the transform is
     /// done (in fact, we don't know that, because it might depend on
     /// the precise type parameters). We just store the target
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 73d0acf95f4..389d20f315f 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -519,7 +519,7 @@ impl<'tcx> Const<'tcx> {
     }
 
     pub fn try_to_bool(self) -> Option<bool> {
-        self.try_to_scalar()?.to_bool().ok()
+        self.try_to_valtree()?.try_to_scalar_int()?.try_to_bool().ok()
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index df60950a6b2..27c1b88f93f 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -56,7 +56,7 @@ use rustc_type_ir::lang_items::TraitSolverLangItem;
 pub use rustc_type_ir::lift::Lift;
 use rustc_type_ir::solve::SolverMode;
 use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph};
-use tracing::{debug, instrument};
+use tracing::{debug, trace};
 
 use crate::arena::Arena;
 use crate::dep_graph::{DepGraph, DepKindStruct};
@@ -622,11 +622,13 @@ bidirectional_lang_item_map! {
     Destruct,
     DiscriminantKind,
     DynMetadata,
+    EffectsCompat,
     EffectsIntersection,
     EffectsIntersectionOutput,
     EffectsMaybe,
     EffectsNoRuntime,
     EffectsRuntime,
+    EffectsTyCompat,
     Fn,
     FnMut,
     FnOnce,
@@ -2071,9 +2073,11 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     /// Returns the origin of the opaque type `def_id`.
-    #[instrument(skip(self), level = "trace", ret)]
+    #[track_caller]
     pub fn opaque_type_origin(self, def_id: LocalDefId) -> hir::OpaqueTyOrigin {
-        self.hir().expect_item(def_id).expect_opaque_ty().origin
+        let origin = self.hir().expect_opaque_ty(def_id).origin;
+        trace!("opaque_type_origin({def_id:?}) => {origin:?}");
+        origin
     }
 }
 
@@ -2992,7 +2996,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
     pub fn named_bound_var(self, id: HirId) -> Option<resolve_bound_vars::ResolvedArg> {
         debug!(?id, "named_region");
-        self.named_variable_map(id.owner).and_then(|map| map.get(&id.local_id).cloned())
+        self.named_variable_map(id.owner).get(&id.local_id).cloned()
     }
 
     pub fn is_late_bound(self, id: HirId) -> bool {
@@ -3001,12 +3005,9 @@ impl<'tcx> TyCtxt<'tcx> {
 
     pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> {
         self.mk_bound_variable_kinds(
-            &self
-                .late_bound_vars_map(id.owner)
-                .and_then(|map| map.get(&id.local_id).cloned())
-                .unwrap_or_else(|| {
-                    bug!("No bound vars found for {}", self.hir().node_to_string(id))
-                }),
+            &self.late_bound_vars_map(id.owner).get(&id.local_id).cloned().unwrap_or_else(|| {
+                bug!("No bound vars found for {}", self.hir().node_to_string(id))
+            }),
         )
     }
 
@@ -3029,8 +3030,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
         loop {
             let parent = self.local_parent(opaque_lifetime_param_def_id);
-            let hir::OpaqueTy { lifetime_mapping, .. } =
-                self.hir_node_by_def_id(parent).expect_item().expect_opaque_ty();
+            let hir::OpaqueTy { lifetime_mapping, .. } = self.hir().expect_opaque_ty(parent);
 
             let Some((lifetime, _)) = lifetime_mapping
                 .iter()
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 992eb264163..751f0c71eb4 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -507,14 +507,8 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
                     ..
                 },
                 _,
-            ) => {
-                self.0.push(ty);
-            }
-            hir::TyKind::OpaqueDef(item_id, _, _) => {
-                self.0.push(ty);
-                let item = self.1.item(item_id);
-                hir::intravisit::walk_item(self, item);
-            }
+            )
+            | hir::TyKind::OpaqueDef(..) => self.0.push(ty),
             _ => {}
         }
         hir::intravisit::walk_ty(self, ty);
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 2ee7497497a..b5a77b3c942 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -1,5 +1,6 @@
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::def_id::DefId;
+use rustc_type_ir::data_structures::DelayedMap;
 pub use rustc_type_ir::fold::{
     FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, shift_region, shift_vars,
 };
@@ -131,12 +132,20 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Bound vars replacer
 
+/// A delegate used when instantiating bound vars.
+///
+/// Any implementation must make sure that each bound variable always
+/// gets mapped to the same result. `BoundVarReplacer` caches by using
+/// a `DelayedMap` which does not cache the first few types it encounters.
 pub trait BoundVarReplacerDelegate<'tcx> {
     fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx>;
     fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx>;
     fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx>;
 }
 
+/// A simple delegate taking 3 mutable functions. The used functions must
+/// always return the same result for each bound variable, no matter how
+/// frequently they are called.
 pub struct FnMutDelegate<'a, 'tcx> {
     pub regions: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
     pub types: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a),
@@ -164,11 +173,15 @@ struct BoundVarReplacer<'tcx, D> {
     current_index: ty::DebruijnIndex,
 
     delegate: D,
+
+    /// This cache only tracks the `DebruijnIndex` and assumes that it does not matter
+    /// for the delegate how often its methods get used.
+    cache: DelayedMap<(ty::DebruijnIndex, Ty<'tcx>), Ty<'tcx>>,
 }
 
 impl<'tcx, D: BoundVarReplacerDelegate<'tcx>> BoundVarReplacer<'tcx, D> {
     fn new(tcx: TyCtxt<'tcx>, delegate: D) -> Self {
-        BoundVarReplacer { tcx, current_index: ty::INNERMOST, delegate }
+        BoundVarReplacer { tcx, current_index: ty::INNERMOST, delegate, cache: Default::default() }
     }
 }
 
@@ -197,8 +210,17 @@ where
                 debug_assert!(!ty.has_vars_bound_above(ty::INNERMOST));
                 ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32())
             }
-            _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
-            _ => t,
+            _ => {
+                if !t.has_vars_bound_at_or_above(self.current_index) {
+                    t
+                } else if let Some(&t) = self.cache.get(&(self.current_index, t)) {
+                    t
+                } else {
+                    let res = t.super_fold_with(self);
+                    assert!(self.cache.insert((self.current_index, t), res));
+                    res
+                }
+            }
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index cf0c29e0c8c..4ba2a9b1d73 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -164,17 +164,17 @@ impl Primitive {
     }
 }
 
-/// The first half of a fat pointer.
+/// The first half of a wide pointer.
 ///
 /// - For a trait object, this is the address of the box.
 /// - For a slice, this is the base address.
-pub const FAT_PTR_ADDR: usize = 0;
+pub const WIDE_PTR_ADDR: usize = 0;
 
-/// The second half of a fat pointer.
+/// The second half of a wide pointer.
 ///
 /// - For a trait object, this is the address of the vtable.
 /// - For a slice, this is the length.
-pub const FAT_PTR_EXTRA: usize = 1;
+pub const WIDE_PTR_EXTRA: usize = 1;
 
 /// The maximum supported number of lanes in a SIMD vector.
 ///
@@ -312,7 +312,7 @@ pub enum SizeSkeleton<'tcx> {
     /// that another SizeSkeleton is of equal size.
     Generic(ty::Const<'tcx>),
 
-    /// A potentially-fat pointer.
+    /// A potentially-wide pointer.
     Pointer {
         /// If true, this pointer is never null.
         non_zero: bool,
@@ -785,11 +785,11 @@ where
                     bug!("TyAndLayout::field({:?}): not applicable", this)
                 }
 
-                // Potentially-fat pointers.
+                // Potentially-wide pointers.
                 ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
                     assert!(i < this.fields.count());
 
-                    // Reuse the fat `*T` type as its own thin pointer data field.
+                    // Reuse the wide `*T` type as its own thin pointer data field.
                     // This provides information about, e.g., DST struct pointees
                     // (which may have no non-DST form), and will work as long
                     // as the `Abi` or `FieldsShape` is checked by users.
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 2b1212a5eb5..f32daee7c44 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -186,9 +186,9 @@ pub struct ResolverGlobalCtxt {
     pub proc_macros: Vec<LocalDefId>,
     /// Mapping from ident span to path span for paths that don't exist as written, but that
     /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`.
-    pub confused_type_with_std_module: FxHashMap<Span, Span>,
-    pub doc_link_resolutions: FxHashMap<LocalDefId, DocLinkResMap>,
-    pub doc_link_traits_in_scope: FxHashMap<LocalDefId, Vec<DefId>>,
+    pub confused_type_with_std_module: FxIndexMap<Span, Span>,
+    pub doc_link_resolutions: FxIndexMap<LocalDefId, DocLinkResMap>,
+    pub doc_link_traits_in_scope: FxIndexMap<LocalDefId, Vec<DefId>>,
     pub all_macro_rules: FxHashMap<Symbol, Res<ast::NodeId>>,
     pub stripped_cfg_items: Steal<Vec<StrippedCfgItem>>,
 }
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index fd4e8f1cd4e..d20cb368278 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -179,6 +179,10 @@ pub struct Clause<'tcx>(
 );
 
 impl<'tcx> rustc_type_ir::inherent::Clause<TyCtxt<'tcx>> for Clause<'tcx> {
+    fn as_predicate(self) -> Predicate<'tcx> {
+        self.as_predicate()
+    }
+
     fn instantiate_supertrait(self, tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> Self {
         self.instantiate_supertrait(tcx, trait_ref)
     }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 8fd4c30457f..7ada5fd93ba 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1951,19 +1951,18 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
 
     fn pretty_print_bound_constness(
         &mut self,
-        trait_ref: ty::TraitRef<'tcx>,
+        constness: ty::BoundConstness,
     ) -> Result<(), PrintError> {
         define_scoped_cx!(self);
 
-        let Some(idx) = self.tcx().generics_of(trait_ref.def_id).host_effect_index else {
-            return Ok(());
-        };
-        let arg = trait_ref.args.const_at(idx);
-
-        if arg == self.tcx().consts.false_ {
-            p!("const ");
-        } else if arg != self.tcx().consts.true_ && !arg.has_infer() {
-            p!("~const ");
+        match constness {
+            ty::BoundConstness::NotConst => {}
+            ty::BoundConstness::Const => {
+                p!("const ");
+            }
+            ty::BoundConstness::ConstIfConst => {
+                p!("~const ");
+            }
         }
         Ok(())
     }
@@ -2948,6 +2947,15 @@ impl<'tcx> ty::TraitPredicate<'tcx> {
     }
 }
 
+#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
+pub struct TraitPredPrintWithBoundConstness<'tcx>(ty::TraitPredicate<'tcx>, ty::BoundConstness);
+
+impl<'tcx> fmt::Debug for TraitPredPrintWithBoundConstness<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, f)
+    }
+}
+
 #[extension(pub trait PrintPolyTraitPredicateExt<'tcx>)]
 impl<'tcx> ty::PolyTraitPredicate<'tcx> {
     fn print_modifiers_and_trait_path(
@@ -2955,6 +2963,13 @@ impl<'tcx> ty::PolyTraitPredicate<'tcx> {
     ) -> ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>> {
         self.map_bound(TraitPredPrintModifiersAndPath)
     }
+
+    fn print_with_bound_constness(
+        self,
+        constness: ty::BoundConstness,
+    ) -> ty::Binder<'tcx, TraitPredPrintWithBoundConstness<'tcx>> {
+        self.map_bound(|trait_pred| TraitPredPrintWithBoundConstness(trait_pred, constness))
+    }
 }
 
 #[derive(Debug, Copy, Clone, Lift)]
@@ -3052,7 +3067,6 @@ define_print! {
 
     ty::TraitPredicate<'tcx> {
         p!(print(self.trait_ref.self_ty()), ": ");
-        p!(pretty_print_bound_constness(self.trait_ref));
         if let ty::PredicatePolarity::Negative = self.polarity {
             p!("!");
         }
@@ -3184,13 +3198,21 @@ define_print_and_forward_display! {
     }
 
     TraitPredPrintModifiersAndPath<'tcx> {
-        p!(pretty_print_bound_constness(self.0.trait_ref));
         if let ty::PredicatePolarity::Negative = self.0.polarity {
             p!("!")
         }
         p!(print(self.0.trait_ref.print_trait_sugared()));
     }
 
+    TraitPredPrintWithBoundConstness<'tcx> {
+        p!(print(self.0.trait_ref.self_ty()), ": ");
+        p!(pretty_print_bound_constness(self.1));
+        if let ty::PredicatePolarity::Negative = self.0.polarity {
+            p!("!");
+        }
+        p!(print(self.0.trait_ref.print_trait_sugared()))
+    }
+
     PrintClosureAsImpl<'tcx> {
         p!(pretty_closure_as_impl(self.closure))
     }
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 61c03922ac0..4c7bcb1bf2e 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -212,15 +212,7 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for ty::GenericArg<'tcx> {
             (ty::GenericArgKind::Const(a_ct), ty::GenericArgKind::Const(b_ct)) => {
                 Ok(relation.relate(a_ct, b_ct)?.into())
             }
-            (ty::GenericArgKind::Lifetime(unpacked), x) => {
-                bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
-            }
-            (ty::GenericArgKind::Type(unpacked), x) => {
-                bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
-            }
-            (ty::GenericArgKind::Const(unpacked), x) => {
-                bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
-            }
+            _ => bug!("impossible case reached: can't relate: {a:?} with {b:?}"),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index db9978a7f53..3f00458d195 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -21,6 +21,7 @@ use rustc_target::spec::abi;
 use rustc_type_ir::TyKind::*;
 use rustc_type_ir::visit::TypeVisitableExt;
 use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind};
+use tracing::instrument;
 use ty::util::{AsyncDropGlueMorphology, IntTypeExt};
 
 use super::GenericParamDefKind;
@@ -500,6 +501,7 @@ impl<'tcx> Ty<'tcx> {
     }
 
     #[inline]
+    #[instrument(level = "debug", skip(tcx))]
     pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>) -> Ty<'tcx> {
         Ty::new_alias(tcx, ty::Opaque, AliasTy::new_from_args(tcx, def_id, args))
     }
@@ -584,6 +586,16 @@ impl<'tcx> Ty<'tcx> {
         Ty::new_ref(tcx, r, ty, hir::Mutability::Not)
     }
 
+    pub fn new_pinned_ref(
+        tcx: TyCtxt<'tcx>,
+        r: Region<'tcx>,
+        ty: Ty<'tcx>,
+        mutbl: ty::Mutability,
+    ) -> Ty<'tcx> {
+        let pin = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, None));
+        Ty::new_adt(tcx, pin, tcx.mk_args(&[Ty::new_ref(tcx, r, ty, mutbl).into()]))
+    }
+
     #[inline]
     pub fn new_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mutbl: ty::Mutability) -> Ty<'tcx> {
         Ty::new(tcx, ty::RawPtr(ty, mutbl))
@@ -1589,7 +1601,7 @@ impl<'tcx> Ty<'tcx> {
             .map_bound(|fn_sig| fn_sig.output().no_bound_vars().unwrap())
     }
 
-    /// Returns the type of metadata for (potentially fat) pointers to this type,
+    /// Returns the type of metadata for (potentially wide) pointers to this type,
     /// or the struct tail if the metadata type cannot be determined.
     pub fn ptr_metadata_ty_or_tail(
         self,
@@ -1648,7 +1660,7 @@ impl<'tcx> Ty<'tcx> {
         }
     }
 
-    /// Returns the type of metadata for (potentially fat) pointers to this type.
+    /// Returns the type of metadata for (potentially wide) pointers to this type.
     /// Causes an ICE if the metadata type cannot be determined.
     pub fn ptr_metadata_ty(
         self,
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 78d83004c14..4efaccefcf7 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -1,6 +1,6 @@
 use std::ops::ControlFlow;
 
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_type_ir::fold::TypeFoldable;
 pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
 
@@ -110,7 +110,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn collect_constrained_late_bound_regions<T>(
         self,
         value: Binder<'tcx, T>,
-    ) -> FxHashSet<ty::BoundRegionKind>
+    ) -> FxIndexSet<ty::BoundRegionKind>
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
@@ -121,7 +121,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn collect_referenced_late_bound_regions<T>(
         self,
         value: Binder<'tcx, T>,
-    ) -> FxHashSet<ty::BoundRegionKind>
+    ) -> FxIndexSet<ty::BoundRegionKind>
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
@@ -132,7 +132,7 @@ impl<'tcx> TyCtxt<'tcx> {
         self,
         value: Binder<'tcx, T>,
         just_constrained: bool,
-    ) -> FxHashSet<ty::BoundRegionKind>
+    ) -> FxIndexSet<ty::BoundRegionKind>
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
@@ -148,7 +148,7 @@ impl<'tcx> TyCtxt<'tcx> {
 /// into a hash set.
 struct LateBoundRegionsCollector {
     current_index: ty::DebruijnIndex,
-    regions: FxHashSet<ty::BoundRegionKind>,
+    regions: FxIndexSet<ty::BoundRegionKind>,
 
     /// `true` if we only want regions that are known to be
     /// "constrained" when you equate this type with another type. In
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index c98d88e22d4..48ca38344cf 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -358,7 +358,7 @@ fn find_item_ty_spans(
     match ty.kind {
         hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
             if let Res::Def(kind, def_id) = path.res
-                && !matches!(kind, DefKind::TyAlias)
+                && matches!(kind, DefKind::Enum | DefKind::Struct | DefKind::Union)
             {
                 let check_params = def_id.as_local().map_or(true, |def_id| {
                     if def_id == needle {
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 86fe447f399..dc317feb20c 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -2,7 +2,7 @@
 
 use std::iter;
 
-use rustc_ast::InlineAsmOptions;
+use rustc_ast::{AsmMacro, InlineAsmOptions};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir as hir;
@@ -384,6 +384,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.unit()
             }
             ExprKind::InlineAsm(box InlineAsmExpr {
+                asm_macro,
                 template,
                 ref operands,
                 options,
@@ -392,11 +393,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 use rustc_middle::{mir, thir};
 
                 let destination_block = this.cfg.start_new_block();
-                let mut targets = if options.contains(InlineAsmOptions::NORETURN) {
-                    vec![]
-                } else {
-                    vec![destination_block]
-                };
+                let mut targets =
+                    if asm_macro.diverges(options) { vec![] } else { vec![destination_block] };
 
                 let operands = operands
                     .into_iter()
@@ -474,7 +472,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
                 }
 
+                let asm_macro = match asm_macro {
+                    AsmMacro::Asm => InlineAsmMacro::Asm,
+                    AsmMacro::GlobalAsm => {
+                        span_bug!(expr_span, "unexpected global_asm! in inline asm")
+                    }
+                    AsmMacro::NakedAsm => InlineAsmMacro::NakedAsm,
+                };
+
                 this.cfg.terminate(block, source_info, TerminatorKind::InlineAsm {
+                    asm_macro,
                     template,
                     operands,
                     options,
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index fbd45f59a4f..abf486af962 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -672,6 +672,7 @@ impl<'tcx> Cx<'tcx> {
             }
 
             hir::ExprKind::InlineAsm(asm) => ExprKind::InlineAsm(Box::new(InlineAsmExpr {
+                asm_macro: asm.asm_macro,
                 template: asm.template,
                 operands: asm
                     .operands
@@ -699,23 +700,17 @@ impl<'tcx> Cx<'tcx> {
                             }
                         }
                         hir::InlineAsmOperand::Const { ref anon_const } => {
-                            let value = mir::Const::identity_unevaluated(
-                                tcx,
-                                anon_const.def_id.to_def_id(),
-                            )
-                            .instantiate_identity()
-                            .normalize(tcx, self.param_env);
+                            let value =
+                                mir::Const::from_unevaluated(tcx, anon_const.def_id.to_def_id())
+                                    .instantiate_identity();
                             let span = tcx.def_span(anon_const.def_id);
 
                             InlineAsmOperand::Const { value, span }
                         }
                         hir::InlineAsmOperand::SymFn { ref anon_const } => {
-                            let value = mir::Const::identity_unevaluated(
-                                tcx,
-                                anon_const.def_id.to_def_id(),
-                            )
-                            .instantiate_identity()
-                            .normalize(tcx, self.param_env);
+                            let value =
+                                mir::Const::from_unevaluated(tcx, anon_const.def_id.to_def_id())
+                                    .instantiate_identity();
                             let span = tcx.def_span(anon_const.def_id);
 
                             InlineAsmOperand::SymFn { value, span }
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index 61317925d09..dae13df4054 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -818,10 +818,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
     }
 
     fn print_inline_asm_expr(&mut self, expr: &InlineAsmExpr<'tcx>, depth_lvl: usize) {
-        let InlineAsmExpr { template, operands, options, line_spans } = expr;
+        let InlineAsmExpr { asm_macro, template, operands, options, line_spans } = expr;
 
         print_indented!(self, "InlineAsmExpr {", depth_lvl);
 
+        print_indented!(self, format!("asm_macro: {:?}", asm_macro), depth_lvl + 1);
+
         print_indented!(self, "template: [", depth_lvl + 1);
         for template_piece in template.iter() {
             print_indented!(self, format!("{:?}", template_piece), depth_lvl + 2);
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index f2541c37167..a3b117a3f19 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -225,7 +225,7 @@ where
     // FIXME: I think we should just control the flags externally,
     // and then we do not need this machinery.
     #[instrument(level = "debug")]
-    pub fn elaborate_drop(&mut self, bb: BasicBlock) {
+    fn elaborate_drop(&mut self, bb: BasicBlock) {
         match self.elaborator.drop_style(self.path, DropFlagMode::Deep) {
             DropStyle::Dead => {
                 self.elaborator
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs
index da01a974094..faf5c610a0c 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs
@@ -285,7 +285,7 @@ where
             }
 
             None if dump_enabled(tcx, A::NAME, def_id) => {
-                create_dump_file(tcx, ".dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
+                create_dump_file(tcx, "dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
             }
 
             _ => return (Ok(()), results),
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 3c8be2f73e1..162245cb950 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -481,6 +481,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
                 }
             }
             TerminatorKind::InlineAsm {
+                asm_macro: _,
                 template: _,
                 ref operands,
                 options: _,
diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl
index f9b79d72b05..b81c0906734 100644
--- a/compiler/rustc_mir_transform/messages.ftl
+++ b/compiler/rustc_mir_transform/messages.ftl
@@ -27,3 +27,8 @@ mir_transform_unaligned_packed_ref = reference to packed field is unaligned
     .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
     .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
     .help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+mir_transform_undefined_transmute = pointers cannot be transmuted to integers during const eval
+    .note = at compile-time, pointers do not have an integer value
+    .note2 = avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
+    .help = for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
diff --git a/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs
new file mode 100644
index 00000000000..8ba14a1158e
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs
@@ -0,0 +1,77 @@
+use rustc_middle::mir::visit::Visitor;
+use rustc_middle::mir::{Body, Location, Operand, Terminator, TerminatorKind};
+use rustc_middle::ty::{AssocItem, AssocKind, TyCtxt};
+use rustc_session::lint::builtin::PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS;
+use rustc_span::sym;
+
+use crate::errors;
+
+/// Check for transmutes that exhibit undefined behavior.
+/// For example, transmuting pointers to integers in a const context.
+pub(super) struct CheckUndefinedTransmutes;
+
+impl<'tcx> crate::MirLint<'tcx> for CheckUndefinedTransmutes {
+    fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+        let mut checker = UndefinedTransmutesChecker { body, tcx };
+        checker.visit_body(body);
+    }
+}
+
+struct UndefinedTransmutesChecker<'a, 'tcx> {
+    body: &'a Body<'tcx>,
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'a, 'tcx> UndefinedTransmutesChecker<'a, 'tcx> {
+    // This functions checks two things:
+    // 1. `function` takes a raw pointer as input and returns an integer as output.
+    // 2. `function` is called from a const function or an associated constant.
+    //
+    // Why do we consider const functions and associated constants only?
+    //
+    // Generally, undefined behavior in const items are handled by the evaluator.
+    // But, const functions and associated constants are evaluated only when referenced.
+    // This can result in undefined behavior in a library going unnoticed until
+    // the function or constant is actually used.
+    //
+    // Therefore, we only consider const functions and associated constants here and leave
+    // other const items to be handled by the evaluator.
+    fn is_ptr_to_int_in_const(&self, function: &Operand<'tcx>) -> bool {
+        let def_id = self.body.source.def_id();
+
+        if self.tcx.is_const_fn(def_id)
+            || matches!(
+                self.tcx.opt_associated_item(def_id),
+                Some(AssocItem { kind: AssocKind::Const, .. })
+            )
+        {
+            let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder();
+            if let [input] = fn_sig.inputs() {
+                return input.is_unsafe_ptr() && fn_sig.output().is_integral();
+            }
+        }
+        false
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for UndefinedTransmutesChecker<'_, 'tcx> {
+    // Check each block's terminator for calls to pointer to integer transmutes
+    // in const functions or associated constants and emit a lint.
+    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
+        if let TerminatorKind::Call { func, .. } = &terminator.kind
+            && let Some((func_def_id, _)) = func.const_fn_def()
+            && self.tcx.is_intrinsic(func_def_id, sym::transmute)
+            && self.is_ptr_to_int_in_const(func)
+            && let Some(call_id) = self.body.source.def_id().as_local()
+        {
+            let hir_id = self.tcx.local_def_id_to_hir_id(call_id);
+            let span = self.body.source_info(location).span;
+            self.tcx.emit_node_span_lint(
+                PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS,
+                hir_id,
+                span,
+                errors::UndefinedTransmute,
+            );
+        }
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index 65442877d2d..cc4b7689d40 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -223,14 +223,14 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
 
     // Inherited from the by-ref coroutine.
     body_def.codegen_fn_attrs(tcx.codegen_fn_attrs(coroutine_def_id).clone());
-    body_def.constness(tcx.constness(coroutine_def_id).clone());
-    body_def.coroutine_kind(tcx.coroutine_kind(coroutine_def_id).clone());
+    body_def.constness(tcx.constness(coroutine_def_id));
+    body_def.coroutine_kind(tcx.coroutine_kind(coroutine_def_id));
     body_def.def_ident_span(tcx.def_ident_span(coroutine_def_id));
     body_def.def_span(tcx.def_span(coroutine_def_id));
-    body_def.explicit_predicates_of(tcx.explicit_predicates_of(coroutine_def_id).clone());
+    body_def.explicit_predicates_of(tcx.explicit_predicates_of(coroutine_def_id));
     body_def.generics_of(tcx.generics_of(coroutine_def_id).clone());
-    body_def.param_env(tcx.param_env(coroutine_def_id).clone());
-    body_def.predicates_of(tcx.predicates_of(coroutine_def_id).clone());
+    body_def.param_env(tcx.param_env(coroutine_def_id));
+    body_def.predicates_of(tcx.predicates_of(coroutine_def_id));
 
     // The type of the coroutine is the `by_move_coroutine_ty`.
     body_def.type_of(ty::EarlyBinder::bind(by_move_coroutine_ty));
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index ef4031c5c03..94088156756 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -4,6 +4,7 @@ use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::graph::DirectedGraph;
 use rustc_index::IndexVec;
+use rustc_index::bit_set::BitSet;
 use rustc_middle::bug;
 use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op};
 use tracing::{debug, debug_span, instrument};
@@ -13,13 +14,13 @@ use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, TraverseCoverage
 /// The coverage counter or counter expression associated with a particular
 /// BCB node or BCB edge.
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub(super) enum BcbCounter {
+enum BcbCounter {
     Counter { id: CounterId },
     Expression { id: ExpressionId },
 }
 
 impl BcbCounter {
-    pub(super) fn as_term(&self) -> CovTerm {
+    fn as_term(&self) -> CovTerm {
         match *self {
             BcbCounter::Counter { id, .. } => CovTerm::Counter(id),
             BcbCounter::Expression { id, .. } => CovTerm::Expression(id),
@@ -78,21 +79,22 @@ impl CoverageCounters {
     /// counters or counter expressions for nodes and edges as required.
     pub(super) fn make_bcb_counters(
         basic_coverage_blocks: &CoverageGraph,
-        bcb_needs_counter: impl Fn(BasicCoverageBlock) -> bool,
+        bcb_needs_counter: &BitSet<BasicCoverageBlock>,
     ) -> Self {
-        let num_bcbs = basic_coverage_blocks.num_nodes();
+        let mut counters = MakeBcbCounters::new(basic_coverage_blocks, bcb_needs_counter);
+        counters.make_bcb_counters();
 
-        let mut this = Self {
+        counters.coverage_counters
+    }
+
+    fn with_num_bcbs(num_bcbs: usize) -> Self {
+        Self {
             counter_increment_sites: IndexVec::new(),
             bcb_counters: IndexVec::from_elem_n(None, num_bcbs),
             bcb_edge_counters: FxHashMap::default(),
             expressions: IndexVec::new(),
             expressions_memo: FxHashMap::default(),
-        };
-
-        MakeBcbCounters::new(&mut this, basic_coverage_blocks).make_bcb_counters(bcb_needs_counter);
-
-        this
+        }
     }
 
     /// Shared helper used by [`Self::make_phys_node_counter`] and
@@ -218,8 +220,8 @@ impl CoverageCounters {
         }
     }
 
-    pub(super) fn bcb_counter(&self, bcb: BasicCoverageBlock) -> Option<BcbCounter> {
-        self.bcb_counters[bcb]
+    pub(super) fn term_for_bcb(&self, bcb: BasicCoverageBlock) -> Option<CovTerm> {
+        self.bcb_counters[bcb].map(|counter| counter.as_term())
     }
 
     /// Returns an iterator over all the nodes/edges in the coverage graph that
@@ -265,19 +267,25 @@ impl CoverageCounters {
 
 /// Helper struct that allows counter creation to inspect the BCB graph.
 struct MakeBcbCounters<'a> {
-    coverage_counters: &'a mut CoverageCounters,
+    coverage_counters: CoverageCounters,
     basic_coverage_blocks: &'a CoverageGraph,
+    bcb_needs_counter: &'a BitSet<BasicCoverageBlock>,
 }
 
 impl<'a> MakeBcbCounters<'a> {
     fn new(
-        coverage_counters: &'a mut CoverageCounters,
         basic_coverage_blocks: &'a CoverageGraph,
+        bcb_needs_counter: &'a BitSet<BasicCoverageBlock>,
     ) -> Self {
-        Self { coverage_counters, basic_coverage_blocks }
+        assert_eq!(basic_coverage_blocks.num_nodes(), bcb_needs_counter.domain_size());
+        Self {
+            coverage_counters: CoverageCounters::with_num_bcbs(basic_coverage_blocks.num_nodes()),
+            basic_coverage_blocks,
+            bcb_needs_counter,
+        }
     }
 
-    fn make_bcb_counters(&mut self, bcb_needs_counter: impl Fn(BasicCoverageBlock) -> bool) {
+    fn make_bcb_counters(&mut self) {
         debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock");
 
         // Traverse the coverage graph, ensuring that every node that needs a
@@ -290,7 +298,7 @@ impl<'a> MakeBcbCounters<'a> {
         let mut traversal = TraverseCoverageGraphWithLoops::new(self.basic_coverage_blocks);
         while let Some(bcb) = traversal.next() {
             let _span = debug_span!("traversal", ?bcb).entered();
-            if bcb_needs_counter(bcb) {
+            if self.bcb_needs_counter.contains(bcb) {
                 self.make_node_counter_and_out_edge_counters(&traversal, bcb);
             }
         }
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 104f340c8d6..79482ba3919 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -94,9 +94,8 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
         return;
     }
 
-    let bcb_has_counter_mappings = |bcb| bcbs_with_counter_mappings.contains(bcb);
     let coverage_counters =
-        CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_counter_mappings);
+        CoverageCounters::make_bcb_counters(&basic_coverage_blocks, &bcbs_with_counter_mappings);
 
     let mappings = create_mappings(tcx, &hir_info, &extracted_mappings, &coverage_counters);
     if mappings.is_empty() {
@@ -153,12 +152,8 @@ fn create_mappings<'tcx>(
         &source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(),
     );
 
-    let term_for_bcb = |bcb| {
-        coverage_counters
-            .bcb_counter(bcb)
-            .expect("all BCBs with spans were given counters")
-            .as_term()
-    };
+    let term_for_bcb =
+        |bcb| coverage_counters.term_for_bcb(bcb).expect("all BCBs with spans were given counters");
     let region_for_span = |span: Span| make_source_region(source_map, file_name, span, body_span);
 
     // Fully destructure the mappings struct to make sure we don't miss any kinds.
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index e65a5fdd5e7..df151f8cca3 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -63,7 +63,8 @@ fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
             Some([item]) if item.has_name(sym::on) => return true,
             Some(_) | None => {
                 // Other possibilities should have been rejected by `rustc_parse::validate_attr`.
-                tcx.dcx().span_bug(attr.span, "unexpected value of coverage attribute");
+                // Use `span_delayed_bug` to avoid an ICE in failing builds (#127880).
+                tcx.dcx().span_delayed_bug(attr.span, "unexpected value of coverage attribute");
             }
         }
     }
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 88dc8e74a8c..002216f50f2 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -3,7 +3,9 @@
 //! Currently, this pass only propagates scalar values.
 
 use rustc_const_eval::const_eval::{DummyMachine, throw_machine_stop_str};
-use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable};
+use rustc_const_eval::interpret::{
+    ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable, interp_ok,
+};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
 use rustc_middle::bug;
@@ -236,6 +238,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                     FlatSet::Elem(op) => self
                         .ecx
                         .int_to_int_or_float(&op, layout)
+                        .discard_err()
                         .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)),
                     FlatSet::Bottom => FlatSet::Bottom,
                     FlatSet::Top => FlatSet::Top,
@@ -249,6 +252,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                     FlatSet::Elem(op) => self
                         .ecx
                         .float_to_float_or_int(&op, layout)
+                        .discard_err()
                         .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)),
                     FlatSet::Bottom => FlatSet::Bottom,
                     FlatSet::Top => FlatSet::Top,
@@ -271,6 +275,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                 FlatSet::Elem(value) => self
                     .ecx
                     .unary_op(*op, &value)
+                    .discard_err()
                     .map_or(FlatSet::Top, |val| self.wrap_immediate(*val)),
                 FlatSet::Bottom => FlatSet::Bottom,
                 FlatSet::Top => FlatSet::Top,
@@ -364,8 +369,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
                 }
             }
             Operand::Constant(box constant) => {
-                if let Ok(constant) =
-                    self.ecx.eval_mir_constant(&constant.const_, constant.span, None)
+                if let Some(constant) =
+                    self.ecx.eval_mir_constant(&constant.const_, constant.span, None).discard_err()
                 {
                     self.assign_constant(state, place, constant, &[]);
                 }
@@ -387,7 +392,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
         for &(mut proj_elem) in projection {
             if let PlaceElem::Index(index) = proj_elem {
                 if let FlatSet::Elem(index) = state.get(index.into(), &self.map)
-                    && let Ok(offset) = index.to_target_usize(&self.tcx)
+                    && let Some(offset) = index.to_target_usize(&self.tcx).discard_err()
                     && let Some(min_length) = offset.checked_add(1)
                 {
                     proj_elem = PlaceElem::ConstantIndex { offset, min_length, from_end: false };
@@ -395,7 +400,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
                     return;
                 }
             }
-            operand = if let Ok(operand) = self.ecx.project(&operand, proj_elem) {
+            operand = if let Some(operand) = self.ecx.project(&operand, proj_elem).discard_err() {
                 operand
             } else {
                 return;
@@ -406,24 +411,24 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
             place,
             operand,
             &mut |elem, op| match elem {
-                TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).ok(),
-                TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).ok(),
+                TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).discard_err(),
+                TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(),
                 TrackElem::Discriminant => {
-                    let variant = self.ecx.read_discriminant(op).ok()?;
+                    let variant = self.ecx.read_discriminant(op).discard_err()?;
                     let discr_value =
-                        self.ecx.discriminant_for_variant(op.layout.ty, variant).ok()?;
+                        self.ecx.discriminant_for_variant(op.layout.ty, variant).discard_err()?;
                     Some(discr_value.into())
                 }
                 TrackElem::DerefLen => {
-                    let op: OpTy<'_> = self.ecx.deref_pointer(op).ok()?.into();
-                    let len_usize = op.len(&self.ecx).ok()?;
+                    let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_err()?.into();
+                    let len_usize = op.len(&self.ecx).discard_err()?;
                     let layout =
                         self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).unwrap();
                     Some(ImmTy::from_uint(len_usize, layout).into())
                 }
             },
             &mut |place, op| {
-                if let Ok(imm) = self.ecx.read_immediate_raw(op)
+                if let Some(imm) = self.ecx.read_immediate_raw(op).discard_err()
                     && let Some(imm) = imm.right()
                 {
                     let elem = self.wrap_immediate(*imm);
@@ -447,11 +452,11 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
             (FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom),
             // Both sides are known, do the actual computation.
             (FlatSet::Elem(left), FlatSet::Elem(right)) => {
-                match self.ecx.binary_op(op, &left, &right) {
+                match self.ecx.binary_op(op, &left, &right).discard_err() {
                     // Ideally this would return an Immediate, since it's sometimes
                     // a pair and sometimes not. But as a hack we always return a pair
                     // and just make the 2nd component `Bottom` when it does not exist.
-                    Ok(val) => {
+                    Some(val) => {
                         if matches!(val.layout.abi, Abi::ScalarPair(..)) {
                             let (val, overflow) = val.to_scalar_pair();
                             (FlatSet::Elem(val), FlatSet::Elem(overflow))
@@ -470,7 +475,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
                 }
 
                 let arg_scalar = const_arg.to_scalar();
-                let Ok(arg_value) = arg_scalar.to_bits(layout.size) else {
+                let Some(arg_value) = arg_scalar.to_bits(layout.size).discard_err() else {
                     return (FlatSet::Top, FlatSet::Top);
                 };
 
@@ -519,7 +524,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
         }
         let enum_ty_layout = self.tcx.layout_of(self.param_env.and(enum_ty)).ok()?;
         let discr_value =
-            self.ecx.discriminant_for_variant(enum_ty_layout.ty, variant_index).ok()?;
+            self.ecx.discriminant_for_variant(enum_ty_layout.ty, variant_index).discard_err()?;
         Some(discr_value.to_scalar())
     }
 
@@ -595,7 +600,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
                 .intern_with_temp_alloc(layout, |ecx, dest| {
                     try_write_constant(ecx, dest, place, ty, state, map)
                 })
-                .ok()?;
+                .discard_err()?;
             return Some(Const::Val(ConstValue::Indirect { alloc_id, offset: Size::ZERO }, ty));
         }
 
@@ -632,7 +637,7 @@ fn try_write_constant<'tcx>(
 
     // Fast path for ZSTs.
     if layout.is_zst() {
-        return Ok(());
+        return interp_ok(());
     }
 
     // Fast path for scalars.
@@ -717,7 +722,7 @@ fn try_write_constant<'tcx>(
         ty::Error(_) | ty::Infer(..) | ty::CoroutineWitness(..) => bug!(),
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 impl<'mir, 'tcx>
@@ -830,7 +835,7 @@ impl<'tcx> MutVisitor<'tcx> for Patch<'tcx> {
         if let PlaceElem::Index(local) = elem {
             let offset = self.before_effect.get(&(location, local.into()))?;
             let offset = offset.try_to_scalar()?;
-            let offset = offset.to_target_usize(&self.tcx).ok()?;
+            let offset = offset.to_target_usize(&self.tcx).discard_err()?;
             let min_length = offset.checked_add(1)?;
             Some(PlaceElem::ConstantIndex { offset, min_length, from_end: false })
         } else {
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index 84d44c2ab4c..fa279ace431 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -121,3 +121,10 @@ pub(crate) struct MustNotSuspendReason {
     pub span: Span,
     pub reason: String,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(mir_transform_undefined_transmute)]
+#[note]
+#[note(mir_transform_note2)]
+#[help]
+pub(crate) struct UndefinedTransmute;
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index f735d08fca5..daf868559bc 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -103,7 +103,7 @@ use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::DUMMY_SP;
 use rustc_span::def_id::DefId;
-use rustc_target::abi::{self, Abi, FIRST_VARIANT, FieldIdx, Size, VariantIdx};
+use rustc_target::abi::{self, Abi, FIRST_VARIANT, FieldIdx, Primitive, Size, VariantIdx};
 use smallvec::SmallVec;
 use tracing::{debug, instrument, trace};
 
@@ -393,7 +393,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             Repeat(..) => return None,
 
             Constant { ref value, disambiguator: _ } => {
-                self.ecx.eval_mir_constant(value, DUMMY_SP, None).ok()?
+                self.ecx.eval_mir_constant(value, DUMMY_SP, None).discard_err()?
             }
             Aggregate(kind, variant, ref fields) => {
                 let fields = fields
@@ -419,29 +419,32 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     ImmTy::uninit(ty).into()
                 } else if matches!(kind, AggregateTy::RawPtr { .. }) {
                     // Pointers don't have fields, so don't `project_field` them.
-                    let data = self.ecx.read_pointer(fields[0]).ok()?;
+                    let data = self.ecx.read_pointer(fields[0]).discard_err()?;
                     let meta = if fields[1].layout.is_zst() {
                         MemPlaceMeta::None
                     } else {
-                        MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).ok()?)
+                        MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).discard_err()?)
                     };
                     let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx);
                     ImmTy::from_immediate(ptr_imm, ty).into()
                 } else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) {
-                    let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?;
+                    let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?;
                     let variant_dest = if let Some(variant) = variant {
-                        self.ecx.project_downcast(&dest, variant).ok()?
+                        self.ecx.project_downcast(&dest, variant).discard_err()?
                     } else {
                         dest.clone()
                     };
                     for (field_index, op) in fields.into_iter().enumerate() {
-                        let field_dest = self.ecx.project_field(&variant_dest, field_index).ok()?;
-                        self.ecx.copy_op(op, &field_dest).ok()?;
+                        let field_dest =
+                            self.ecx.project_field(&variant_dest, field_index).discard_err()?;
+                        self.ecx.copy_op(op, &field_dest).discard_err()?;
                     }
-                    self.ecx.write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest).ok()?;
+                    self.ecx
+                        .write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest)
+                        .discard_err()?;
                     self.ecx
                         .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
-                        .ok()?;
+                        .discard_err()?;
                     dest.into()
                 } else {
                     return None;
@@ -467,7 +470,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     // This should have been replaced by a `ConstantIndex` earlier.
                     ProjectionElem::Index(_) => return None,
                 };
-                self.ecx.project(value, elem).ok()?
+                self.ecx.project(value, elem).discard_err()?
             }
             Address { place, kind, provenance: _ } => {
                 if !place.is_indirect_first_projection() {
@@ -475,14 +478,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 }
                 let local = self.locals[place.local]?;
                 let pointer = self.evaluated[local].as_ref()?;
-                let mut mplace = self.ecx.deref_pointer(pointer).ok()?;
+                let mut mplace = self.ecx.deref_pointer(pointer).discard_err()?;
                 for proj in place.projection.iter().skip(1) {
                     // We have no call stack to associate a local with a value, so we cannot
                     // interpret indexing.
                     if matches!(proj, ProjectionElem::Index(_)) {
                         return None;
                     }
-                    mplace = self.ecx.project(&mplace, proj).ok()?;
+                    mplace = self.ecx.project(&mplace, proj).discard_err()?;
                 }
                 let pointer = mplace.to_ref(&self.ecx);
                 let ty = match kind {
@@ -500,15 +503,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
             Discriminant(base) => {
                 let base = self.evaluated[base].as_ref()?;
-                let variant = self.ecx.read_discriminant(base).ok()?;
+                let variant = self.ecx.read_discriminant(base).discard_err()?;
                 let discr_value =
-                    self.ecx.discriminant_for_variant(base.layout.ty, variant).ok()?;
+                    self.ecx.discriminant_for_variant(base.layout.ty, variant).discard_err()?;
                 discr_value.into()
             }
             Len(slice) => {
                 let slice = self.evaluated[slice].as_ref()?;
                 let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap();
-                let len = slice.len(&self.ecx).ok()?;
+                let len = slice.len(&self.ecx).discard_err()?;
                 let imm = ImmTy::from_uint(len, usize_layout);
                 imm.into()
             }
@@ -535,67 +538,83 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
             UnaryOp(un_op, operand) => {
                 let operand = self.evaluated[operand].as_ref()?;
-                let operand = self.ecx.read_immediate(operand).ok()?;
-                let val = self.ecx.unary_op(un_op, &operand).ok()?;
+                let operand = self.ecx.read_immediate(operand).discard_err()?;
+                let val = self.ecx.unary_op(un_op, &operand).discard_err()?;
                 val.into()
             }
             BinaryOp(bin_op, lhs, rhs) => {
                 let lhs = self.evaluated[lhs].as_ref()?;
-                let lhs = self.ecx.read_immediate(lhs).ok()?;
+                let lhs = self.ecx.read_immediate(lhs).discard_err()?;
                 let rhs = self.evaluated[rhs].as_ref()?;
-                let rhs = self.ecx.read_immediate(rhs).ok()?;
-                let val = self.ecx.binary_op(bin_op, &lhs, &rhs).ok()?;
+                let rhs = self.ecx.read_immediate(rhs).discard_err()?;
+                let val = self.ecx.binary_op(bin_op, &lhs, &rhs).discard_err()?;
                 val.into()
             }
             Cast { kind, value, from: _, to } => match kind {
                 CastKind::IntToInt | CastKind::IntToFloat => {
                     let value = self.evaluated[value].as_ref()?;
-                    let value = self.ecx.read_immediate(value).ok()?;
+                    let value = self.ecx.read_immediate(value).discard_err()?;
                     let to = self.ecx.layout_of(to).ok()?;
-                    let res = self.ecx.int_to_int_or_float(&value, to).ok()?;
+                    let res = self.ecx.int_to_int_or_float(&value, to).discard_err()?;
                     res.into()
                 }
                 CastKind::FloatToFloat | CastKind::FloatToInt => {
                     let value = self.evaluated[value].as_ref()?;
-                    let value = self.ecx.read_immediate(value).ok()?;
+                    let value = self.ecx.read_immediate(value).discard_err()?;
                     let to = self.ecx.layout_of(to).ok()?;
-                    let res = self.ecx.float_to_float_or_int(&value, to).ok()?;
+                    let res = self.ecx.float_to_float_or_int(&value, to).discard_err()?;
                     res.into()
                 }
                 CastKind::Transmute => {
                     let value = self.evaluated[value].as_ref()?;
                     let to = self.ecx.layout_of(to).ok()?;
-                    // `offset` for immediates only supports scalar/scalar-pair ABIs,
-                    // so bail out if the target is not one.
+                    // `offset` for immediates generally only supports projections that match the
+                    // type of the immediate. However, as a HACK, we exploit that it can also do
+                    // limited transmutes: it only works between types with the same layout, and
+                    // cannot transmute pointers to integers.
                     if value.as_mplace_or_imm().is_right() {
-                        match (value.layout.abi, to.abi) {
-                            (Abi::Scalar(..), Abi::Scalar(..)) => {}
-                            (Abi::ScalarPair(..), Abi::ScalarPair(..)) => {}
-                            _ => return None,
+                        let can_transmute = match (value.layout.abi, to.abi) {
+                            (Abi::Scalar(s1), Abi::Scalar(s2)) => {
+                                s1.size(&self.ecx) == s2.size(&self.ecx)
+                                    && !matches!(s1.primitive(), Primitive::Pointer(..))
+                            }
+                            (Abi::ScalarPair(a1, b1), Abi::ScalarPair(a2, b2)) => {
+                                a1.size(&self.ecx) == a2.size(&self.ecx) &&
+                                b1.size(&self.ecx) == b2.size(&self.ecx) &&
+                                // The alignment of the second component determines its offset, so that also needs to match.
+                                b1.align(&self.ecx) == b2.align(&self.ecx) &&
+                                // None of the inputs may be a pointer.
+                                !matches!(a1.primitive(), Primitive::Pointer(..))
+                                    && !matches!(b1.primitive(), Primitive::Pointer(..))
+                            }
+                            _ => false,
+                        };
+                        if !can_transmute {
+                            return None;
                         }
                     }
-                    value.offset(Size::ZERO, to, &self.ecx).ok()?
+                    value.offset(Size::ZERO, to, &self.ecx).discard_err()?
                 }
                 CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) => {
                     let src = self.evaluated[value].as_ref()?;
                     let to = self.ecx.layout_of(to).ok()?;
-                    let dest = self.ecx.allocate(to, MemoryKind::Stack).ok()?;
-                    self.ecx.unsize_into(src, to, &dest.clone().into()).ok()?;
+                    let dest = self.ecx.allocate(to, MemoryKind::Stack).discard_err()?;
+                    self.ecx.unsize_into(src, to, &dest.clone().into()).discard_err()?;
                     self.ecx
                         .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
-                        .ok()?;
+                        .discard_err()?;
                     dest.into()
                 }
                 CastKind::FnPtrToPtr | CastKind::PtrToPtr => {
                     let src = self.evaluated[value].as_ref()?;
-                    let src = self.ecx.read_immediate(src).ok()?;
+                    let src = self.ecx.read_immediate(src).discard_err()?;
                     let to = self.ecx.layout_of(to).ok()?;
-                    let ret = self.ecx.ptr_to_ptr(&src, to).ok()?;
+                    let ret = self.ecx.ptr_to_ptr(&src, to).discard_err()?;
                     ret.into()
                 }
                 CastKind::PointerCoercion(ty::adjustment::PointerCoercion::UnsafeFnPointer, _) => {
                     let src = self.evaluated[value].as_ref()?;
-                    let src = self.ecx.read_immediate(src).ok()?;
+                    let src = self.ecx.read_immediate(src).discard_err()?;
                     let to = self.ecx.layout_of(to).ok()?;
                     ImmTy::from_immediate(*src, to).into()
                 }
@@ -708,7 +727,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 && let Some(idx) = self.locals[idx_local]
             {
                 if let Some(offset) = self.evaluated[idx].as_ref()
-                    && let Ok(offset) = self.ecx.read_target_usize(offset)
+                    && let Some(offset) = self.ecx.read_target_usize(offset).discard_err()
                     && let Some(min_length) = offset.checked_add(1)
                 {
                     projection.to_mut()[i] =
@@ -868,7 +887,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             && let DefKind::Enum = self.tcx.def_kind(enum_did)
         {
             let enum_ty = self.tcx.type_of(enum_did).instantiate(self.tcx, enum_args);
-            let discr = self.ecx.discriminant_for_variant(enum_ty, variant).ok()?;
+            let discr = self.ecx.discriminant_for_variant(enum_ty, variant).discard_err()?;
             return Some(self.insert_scalar(discr.to_scalar(), discr.layout.ty));
         }
 
@@ -1134,7 +1153,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             (UnOp::PtrMetadata, Value::Aggregate(AggregateTy::RawPtr { .. }, _, fields)) => {
                 return Some(fields[1]);
             }
-            // We have an unsizing cast, which assigns the length to fat pointer metadata.
+            // We have an unsizing cast, which assigns the length to wide pointer metadata.
             (
                 UnOp::PtrMetadata,
                 Value::Cast {
@@ -1223,8 +1242,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         let as_bits = |value| {
             let constant = self.evaluated[value].as_ref()?;
             if layout.abi.is_scalar() {
-                let scalar = self.ecx.read_scalar(constant).ok()?;
-                scalar.to_bits(constant.layout.size).ok()
+                let scalar = self.ecx.read_scalar(constant).discard_err()?;
+                scalar.to_bits(constant.layout.size).discard_err()
             } else {
                 // `constant` is a wide pointer. Do not evaluate to bits.
                 None
@@ -1418,7 +1437,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
         let mut inner = self.simplify_place_value(place, location)?;
 
-        // The length information is stored in the fat pointer.
+        // The length information is stored in the wide pointer.
         // Reborrowing copies length information from one pointer to the other.
         while let Value::Address { place: borrowed, .. } = self.get(inner)
             && let [PlaceElem::Deref] = borrowed.projection[..]
@@ -1427,7 +1446,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             inner = borrowed;
         }
 
-        // We have an unsizing cast, which assigns the length to fat pointer metadata.
+        // We have an unsizing cast, which assigns the length to wide pointer metadata.
         if let Value::Cast { kind, from, to, .. } = self.get(inner)
             && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind
             && let Some(from) = from.builtin_deref(true)
@@ -1484,7 +1503,7 @@ fn op_to_prop_const<'tcx>(
 
     // If this constant has scalar ABI, return it as a `ConstValue::Scalar`.
     if let Abi::Scalar(abi::Scalar::Initialized { .. }) = op.layout.abi
-        && let Ok(scalar) = ecx.read_scalar(op)
+        && let Some(scalar) = ecx.read_scalar(op).discard_err()
     {
         if !scalar.try_to_scalar_int().is_ok() {
             // Check that we do not leak a pointer.
@@ -1498,12 +1517,12 @@ fn op_to_prop_const<'tcx>(
     // If this constant is already represented as an `Allocation`,
     // try putting it into global memory to return it.
     if let Either::Left(mplace) = op.as_mplace_or_imm() {
-        let (size, _align) = ecx.size_and_align_of_mplace(&mplace).ok()??;
+        let (size, _align) = ecx.size_and_align_of_mplace(&mplace).discard_err()??;
 
         // Do not try interning a value that contains provenance.
         // Due to https://github.com/rust-lang/rust/issues/79738, doing so could lead to bugs.
         // FIXME: remove this hack once that issue is fixed.
-        let alloc_ref = ecx.get_ptr_alloc(mplace.ptr(), size).ok()??;
+        let alloc_ref = ecx.get_ptr_alloc(mplace.ptr(), size).discard_err()??;
         if alloc_ref.has_provenance() {
             return None;
         }
@@ -1511,7 +1530,7 @@ fn op_to_prop_const<'tcx>(
         let pointer = mplace.ptr().into_pointer_or_addr().ok()?;
         let (prov, offset) = pointer.into_parts();
         let alloc_id = prov.alloc_id();
-        intern_const_alloc_for_constprop(ecx, alloc_id).ok()?;
+        intern_const_alloc_for_constprop(ecx, alloc_id).discard_err()?;
 
         // `alloc_id` may point to a static. Codegen will choke on an `Indirect` with anything
         // by `GlobalAlloc::Memory`, so do fall through to copying if needed.
@@ -1526,7 +1545,8 @@ fn op_to_prop_const<'tcx>(
     }
 
     // Everything failed: create a new allocation to hold the data.
-    let alloc_id = ecx.intern_with_temp_alloc(op.layout, |ecx, dest| ecx.copy_op(op, dest)).ok()?;
+    let alloc_id =
+        ecx.intern_with_temp_alloc(op.layout, |ecx, dest| ecx.copy_op(op, dest)).discard_err()?;
     let value = ConstValue::Indirect { alloc_id, offset: Size::ZERO };
 
     // Check that we do not leak a pointer.
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index 9d85b5ba5a7..9b9b0b705bf 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -200,7 +200,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
         debug!(?discr, ?bb);
 
         let discr_ty = discr.ty(self.body, self.tcx).ty;
-        let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return };
+        let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else {
+            return;
+        };
 
         let Some(discr) = self.map.find(discr.as_ref()) else { return };
         debug!(?discr);
@@ -388,24 +390,24 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
             lhs,
             constant,
             &mut |elem, op| match elem {
-                TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).ok(),
-                TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).ok(),
+                TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).discard_err(),
+                TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(),
                 TrackElem::Discriminant => {
-                    let variant = self.ecx.read_discriminant(op).ok()?;
+                    let variant = self.ecx.read_discriminant(op).discard_err()?;
                     let discr_value =
-                        self.ecx.discriminant_for_variant(op.layout.ty, variant).ok()?;
+                        self.ecx.discriminant_for_variant(op.layout.ty, variant).discard_err()?;
                     Some(discr_value.into())
                 }
                 TrackElem::DerefLen => {
-                    let op: OpTy<'_> = self.ecx.deref_pointer(op).ok()?.into();
-                    let len_usize = op.len(&self.ecx).ok()?;
+                    let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_err()?.into();
+                    let len_usize = op.len(&self.ecx).discard_err()?;
                     let layout = self.ecx.layout_of(self.tcx.types.usize).unwrap();
                     Some(ImmTy::from_uint(len_usize, layout).into())
                 }
             },
             &mut |place, op| {
                 if let Some(conditions) = state.try_get_idx(place, &self.map)
-                    && let Ok(imm) = self.ecx.read_immediate_raw(op)
+                    && let Some(imm) = self.ecx.read_immediate_raw(op).discard_err()
                     && let Some(imm) = imm.right()
                     && let Immediate::Scalar(Scalar::Int(int)) = *imm
                 {
@@ -429,8 +431,8 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
         match rhs {
             // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`.
             Operand::Constant(constant) => {
-                let Ok(constant) =
-                    self.ecx.eval_mir_constant(&constant.const_, constant.span, None)
+                let Some(constant) =
+                    self.ecx.eval_mir_constant(&constant.const_, constant.span, None).discard_err()
                 else {
                     return;
                 };
@@ -469,8 +471,10 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
                     AggregateKind::Adt(.., Some(_)) => return,
                     AggregateKind::Adt(_, variant_index, ..) if agg_ty.is_enum() => {
                         if let Some(discr_target) = self.map.apply(lhs, TrackElem::Discriminant)
-                            && let Ok(discr_value) =
-                                self.ecx.discriminant_for_variant(agg_ty, *variant_index)
+                            && let Some(discr_value) = self
+                                .ecx
+                                .discriminant_for_variant(agg_ty, *variant_index)
+                                .discard_err()
                         {
                             self.process_immediate(bb, discr_target, discr_value, state);
                         }
@@ -490,8 +494,16 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
             }
             // Transfer the conditions on the copy rhs, after inversing polarity.
             Rvalue::UnaryOp(UnOp::Not, Operand::Move(place) | Operand::Copy(place)) => {
+                if !place.ty(self.body, self.tcx).ty.is_bool() {
+                    // Constructing the conditions by inverting the polarity
+                    // of equality is only correct for bools. That is to say,
+                    // `!a == b` is not `a != b` for integers greater than 1 bit.
+                    return;
+                }
                 let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return };
                 let Some(place) = self.map.find(place.as_ref()) else { return };
+                // FIXME: I think This could be generalized to not bool if we
+                // actually perform a logical not on the condition's value.
                 let conds = conditions.map(self.arena, Condition::inv);
                 state.insert_value_idx(place, conds, &self.map);
             }
@@ -516,9 +528,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
                     // Avoid handling them, though this could be extended in the future.
                     return;
                 }
-                let Some(value) =
-                    value.const_.normalize(self.tcx, self.param_env).try_to_scalar_int()
-                else {
+                let Some(value) = value.const_.try_eval_scalar_int(self.tcx, self.param_env) else {
                     return;
                 };
                 let conds = conditions.map(self.arena, |c| Condition {
@@ -557,7 +567,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
                 // `SetDiscriminant` may be a no-op if the assigned variant is the untagged variant
                 // of a niche encoding. If we cannot ensure that we write to the discriminant, do
                 // nothing.
-                let Ok(enum_layout) = self.ecx.layout_of(enum_ty) else { return };
+                let Ok(enum_layout) = self.ecx.layout_of(enum_ty) else {
+                    return;
+                };
                 let writes_discriminant = match enum_layout.variants {
                     Variants::Single { index } => {
                         assert_eq!(index, *variant_index);
@@ -570,7 +582,8 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
                     } => *variant_index != untagged_variant,
                 };
                 if writes_discriminant {
-                    let Ok(discr) = self.ecx.discriminant_for_variant(enum_ty, *variant_index)
+                    let Some(discr) =
+                        self.ecx.discriminant_for_variant(enum_ty, *variant_index).discard_err()
                     else {
                         return;
                     };
@@ -647,7 +660,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
 
         let Some(discr) = discr.place() else { return };
         let discr_ty = discr.ty(self.body, self.tcx).ty;
-        let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return };
+        let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else {
+            return;
+        };
         let Some(conditions) = state.try_get(discr.as_ref(), &self.map) else { return };
 
         if let Some((value, _)) = targets.iter().find(|&(_, target)| target == target_bb) {
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index 783e7aabe85..8f490094d60 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -6,7 +6,7 @@ use std::fmt::Debug;
 
 use rustc_const_eval::const_eval::DummyMachine;
 use rustc_const_eval::interpret::{
-    ImmTy, InterpCx, InterpResult, Projectable, Scalar, format_interp_error,
+    ImmTy, InterpCx, InterpResult, Projectable, Scalar, format_interp_error, interp_ok,
 };
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::HirId;
@@ -101,7 +101,7 @@ impl<'tcx> Value<'tcx> {
                 }
                 (PlaceElem::Index(idx), Value::Aggregate { fields, .. }) => {
                     let idx = prop.get_const(idx.into())?.immediate()?;
-                    let idx = prop.ecx.read_target_usize(idx).ok()?.try_into().ok()?;
+                    let idx = prop.ecx.read_target_usize(idx).discard_err()?.try_into().ok()?;
                     if idx <= FieldIdx::MAX_AS_U32 {
                         fields.get(FieldIdx::from_u32(idx)).unwrap_or(&Value::Uninit)
                     } else {
@@ -231,21 +231,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
     where
         F: FnOnce(&mut Self) -> InterpResult<'tcx, T>,
     {
-        match f(self) {
-            Ok(val) => Some(val),
-            Err(error) => {
-                trace!("InterpCx operation failed: {:?}", error);
+        f(self)
+            .map_err(|err| {
+                trace!("InterpCx operation failed: {:?}", err);
                 // Some errors shouldn't come up because creating them causes
                 // an allocation, which we should avoid. When that happens,
                 // dedicated error variants should be introduced instead.
                 assert!(
-                    !error.kind().formatted_string(),
+                    !err.kind().formatted_string(),
                     "known panics lint encountered formatting error: {}",
-                    format_interp_error(self.ecx.tcx.dcx(), error),
+                    format_interp_error(self.ecx.tcx.dcx(), err),
                 );
-                None
-            }
-        }
+                err
+            })
+            .discard_err()
     }
 
     /// Returns the value, if any, of evaluating `c`.
@@ -315,7 +314,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     .ecx
                     .binary_op(BinOp::SubWithOverflow, &ImmTy::from_int(0, arg.layout), &arg)?
                     .to_scalar_pair();
-                Ok((arg, overflow.to_bool()?))
+                interp_ok((arg, overflow.to_bool()?))
             })?;
             if overflow {
                 self.report_assert_as_lint(
@@ -349,7 +348,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             let left_ty = left.ty(self.local_decls(), self.tcx);
             let left_size = self.ecx.layout_of(left_ty).ok()?.size;
             let right_size = r.layout.size;
-            let r_bits = r.to_scalar().to_bits(right_size).ok();
+            let r_bits = r.to_scalar().to_bits(right_size).discard_err();
             if r_bits.is_some_and(|b| b >= left_size.bits() as u128) {
                 debug!("check_binary_op: reporting assert for {:?}", location);
                 let panic = AssertKind::Overflow(
@@ -496,7 +495,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                 // This can be `None` if the lhs wasn't const propagated and we just
                 // triggered the assert on the value of the rhs.
                 self.eval_operand(op)
-                    .and_then(|op| self.ecx.read_immediate(&op).ok())
+                    .and_then(|op| self.ecx.read_immediate(&op).discard_err())
                     .map_or(DbgVal::Underscore, |op| DbgVal::Val(op.to_const_int()))
             };
             let msg = match msg {
@@ -601,13 +600,15 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             }
 
             Len(place) => {
-                let len = match self.get_const(place)? {
-                    Value::Immediate(src) => src.len(&self.ecx).ok()?,
-                    Value::Aggregate { fields, .. } => fields.len() as u64,
-                    Value::Uninit => match place.ty(self.local_decls(), self.tcx).ty.kind() {
-                        ty::Array(_, n) => n.try_eval_target_usize(self.tcx, self.param_env)?,
-                        _ => return None,
-                    },
+                let len = if let ty::Array(_, n) = place.ty(self.local_decls(), self.tcx).ty.kind()
+                {
+                    n.try_eval_target_usize(self.tcx, self.param_env)?
+                } else {
+                    match self.get_const(place)? {
+                        Value::Immediate(src) => src.len(&self.ecx).discard_err()?,
+                        Value::Aggregate { fields, .. } => fields.len() as u64,
+                        Value::Uninit => return None,
+                    }
                 };
                 ImmTy::from_scalar(Scalar::from_target_usize(len, self), layout).into()
             }
@@ -615,7 +616,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             Ref(..) | RawPtr(..) => return None,
 
             NullaryOp(ref null_op, ty) => {
-                let op_layout = self.use_ecx(|this| this.ecx.layout_of(ty))?;
+                let op_layout = self.ecx.layout_of(ty).ok()?;
                 let val = match null_op {
                     NullOp::SizeOf => op_layout.size.bytes(),
                     NullOp::AlignOf => op_layout.align.abi.bytes(),
@@ -633,16 +634,16 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             Cast(ref kind, ref value, to) => match kind {
                 CastKind::IntToInt | CastKind::IntToFloat => {
                     let value = self.eval_operand(value)?;
-                    let value = self.ecx.read_immediate(&value).ok()?;
+                    let value = self.ecx.read_immediate(&value).discard_err()?;
                     let to = self.ecx.layout_of(to).ok()?;
-                    let res = self.ecx.int_to_int_or_float(&value, to).ok()?;
+                    let res = self.ecx.int_to_int_or_float(&value, to).discard_err()?;
                     res.into()
                 }
                 CastKind::FloatToFloat | CastKind::FloatToInt => {
                     let value = self.eval_operand(value)?;
-                    let value = self.ecx.read_immediate(&value).ok()?;
+                    let value = self.ecx.read_immediate(&value).discard_err()?;
                     let to = self.ecx.layout_of(to).ok()?;
-                    let res = self.ecx.float_to_float_or_int(&value, to).ok()?;
+                    let res = self.ecx.float_to_float_or_int(&value, to).discard_err()?;
                     res.into()
                 }
                 CastKind::Transmute => {
@@ -656,7 +657,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                         _ => return None,
                     }
 
-                    value.offset(Size::ZERO, to, &self.ecx).ok()?.into()
+                    value.offset(Size::ZERO, to, &self.ecx).discard_err()?.into()
                 }
                 _ => return None,
             },
@@ -781,7 +782,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
             TerminatorKind::SwitchInt { ref discr, ref targets } => {
                 if let Some(ref value) = self.eval_operand(discr)
                     && let Some(value_const) = self.use_ecx(|this| this.ecx.read_scalar(value))
-                    && let Ok(constant) = value_const.to_bits(value_const.size())
+                    && let Some(constant) = value_const.to_bits(value_const.size()).discard_err()
                 {
                     // We managed to evaluate the discriminant, so we know we only need to visit
                     // one target.
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 4c090665992..d184328748f 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -51,6 +51,7 @@ mod add_subtyping_projections;
 mod check_alignment;
 mod check_const_item_mutation;
 mod check_packed_ref;
+mod check_undefined_transmutes;
 // This pass is public to allow external drivers to perform MIR cleanup
 pub mod cleanup_post_borrowck;
 mod copy_prop;
@@ -298,6 +299,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
             &Lint(check_packed_ref::CheckPackedRef),
             &Lint(check_const_item_mutation::CheckConstItemMutation),
             &Lint(function_item_references::FunctionItemReferences),
+            &Lint(check_undefined_transmutes::CheckUndefinedTransmutes),
             // What we need to do constant evaluation.
             &simplify::SimplifyCfg::Initial,
             &Lint(sanity_check::SanityCheck),
diff --git a/compiler/rustc_mir_transform/src/single_use_consts.rs b/compiler/rustc_mir_transform/src/single_use_consts.rs
index 9884b6dd1c3..277a33c0311 100644
--- a/compiler/rustc_mir_transform/src/single_use_consts.rs
+++ b/compiler/rustc_mir_transform/src/single_use_consts.rs
@@ -185,15 +185,14 @@ impl<'tcx> MutVisitor<'tcx> for LocalReplacer<'tcx> {
             && let Some(local) = place.as_local()
             && local == self.local
         {
-            let const_op = self
+            let const_op = *self
                 .operand
                 .as_ref()
                 .unwrap_or_else(|| {
                     bug!("the operand was already stolen");
                 })
                 .constant()
-                .unwrap()
-                .clone();
+                .unwrap();
             var_debug_info.value = VarDebugInfoContents::Const(const_op);
         }
     }
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 05b3859e554..b4d084d4dff 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -119,7 +119,7 @@
 //!
 //! #### Unsizing Casts
 //! A subtle way of introducing use edges is by casting to a trait object.
-//! Since the resulting fat-pointer contains a reference to a vtable, we need to
+//! Since the resulting wide-pointer contains a reference to a vtable, we need to
 //! instantiate all dyn-compatible methods of the trait, as we need to store
 //! pointers to these functions even if they never get called anywhere. This can
 //! be seen as a special case of taking a function reference.
@@ -661,7 +661,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
         let span = self.body.source_info(location).span;
 
         match *rvalue {
-            // When doing an cast from a regular pointer to a fat pointer, we
+            // When doing an cast from a regular pointer to a wide pointer, we
             // have to instantiate all methods of the trait being cast to, so we
             // can build the appropriate vtable.
             mir::Rvalue::Cast(
@@ -985,7 +985,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -
 /// ```
 ///
 /// Then the output of this function would be (SomeStruct, SomeTrait) since for
-/// constructing the `target` fat-pointer we need the vtable for that pair.
+/// constructing the `target` wide-pointer we need the vtable for that pair.
 ///
 /// Things can get more complicated though because there's also the case where
 /// the unsized type occurs as a field:
@@ -999,7 +999,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -
 /// ```
 ///
 /// In this case, if `T` is sized, `&ComplexStruct<T>` is a thin pointer. If `T`
-/// is unsized, `&SomeStruct` is a fat pointer, and the vtable it points to is
+/// is unsized, `&SomeStruct` is a wide pointer, and the vtable it points to is
 /// for the pair of `T` (which is a trait) and the concrete type that `T` was
 /// originally coerced from:
 ///
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index ad05cca66ca..5bd484d7bb0 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -904,26 +904,22 @@ fn mono_item_visibility<'tcx>(
 }
 
 fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility {
-    if !tcx.sess.default_hidden_visibility() {
-        return Visibility::Default;
-    }
-
-    // Generic functions never have export-level C.
-    if is_generic {
-        return Visibility::Hidden;
-    }
-
-    // Things with export level C don't get instantiated in
-    // downstream crates.
-    if !id.is_local() {
-        return Visibility::Hidden;
-    }
+    let export_level = if is_generic {
+        // Generic functions never have export-level C.
+        SymbolExportLevel::Rust
+    } else {
+        match tcx.reachable_non_generics(id.krate).get(&id) {
+            Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => SymbolExportLevel::C,
+            _ => SymbolExportLevel::Rust,
+        }
+    };
+    match export_level {
+        // C-export level items remain at `Default` to allow C code to
+        // access and interpose them.
+        SymbolExportLevel::C => Visibility::Default,
 
-    // C-export level items remain at `Default`, all other internal
-    // items become `Hidden`.
-    match tcx.reachable_non_generics(id.krate).get(&id) {
-        Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => Visibility::Default,
-        _ => Visibility::Hidden,
+        // For all other symbols, `default_visibility` determines which visibility to use.
+        SymbolExportLevel::Rust => tcx.sess.default_visibility().into(),
     }
 }
 
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index 196ddeb2443..0bf9d7b9249 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -1,5 +1,6 @@
 use std::cmp::Ordering;
 
+use rustc_type_ir::data_structures::HashMap;
 use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::visit::TypeVisitableExt;
@@ -41,11 +42,20 @@ pub enum CanonicalizeMode {
 
 pub struct Canonicalizer<'a, D: SolverDelegate<Interner = I>, I: Interner> {
     delegate: &'a D,
+
+    // Immutable field.
     canonicalize_mode: CanonicalizeMode,
 
+    // Mutable fields.
     variables: &'a mut Vec<I::GenericArg>,
     primitive_var_infos: Vec<CanonicalVarInfo<I>>,
+    variable_lookup_table: HashMap<I::GenericArg, usize>,
     binder_index: ty::DebruijnIndex,
+
+    /// We only use the debruijn index during lookup. We don't need to
+    /// track the `variables` as each generic arg only results in a single
+    /// bound variable regardless of how many times it is encountered.
+    cache: HashMap<(ty::DebruijnIndex, I::Ty), I::Ty>,
 }
 
 impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
@@ -60,12 +70,14 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
             canonicalize_mode,
 
             variables,
+            variable_lookup_table: Default::default(),
             primitive_var_infos: Vec::new(),
             binder_index: ty::INNERMOST,
+
+            cache: Default::default(),
         };
 
         let value = value.fold_with(&mut canonicalizer);
-        // FIXME: Restore these assertions. Should we uplift type flags?
         assert!(!value.has_infer(), "unexpected infer in {value:?}");
         assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}");
 
@@ -75,6 +87,37 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
         Canonical { defining_opaque_types, max_universe, variables, value }
     }
 
+    fn get_or_insert_bound_var(
+        &mut self,
+        arg: impl Into<I::GenericArg>,
+        canonical_var_info: CanonicalVarInfo<I>,
+    ) -> ty::BoundVar {
+        // FIXME: 16 is made up and arbitrary. We should look at some
+        // perf data here.
+        let arg = arg.into();
+        let idx = if self.variables.len() > 16 {
+            if self.variable_lookup_table.is_empty() {
+                self.variable_lookup_table.extend(self.variables.iter().copied().zip(0..));
+            }
+
+            *self.variable_lookup_table.entry(arg).or_insert_with(|| {
+                let var = self.variables.len();
+                self.variables.push(arg);
+                self.primitive_var_infos.push(canonical_var_info);
+                var
+            })
+        } else {
+            self.variables.iter().position(|&v| v == arg).unwrap_or_else(|| {
+                let var = self.variables.len();
+                self.variables.push(arg);
+                self.primitive_var_infos.push(canonical_var_info);
+                var
+            })
+        };
+
+        ty::BoundVar::from(idx)
+    }
+
     fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVars) {
         let mut var_infos = self.primitive_var_infos;
         // See the rustc-dev-guide section about how we deal with universes
@@ -124,8 +167,8 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
         // - var_infos: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6
         // - var_infos: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: -
         //
-        // This algorithm runs in `O(n²)` where `n` is the number of different universe
-        // indices in the input. This should be fine as `n` is expected to be small.
+        // This algorithm runs in `O(mn)` where `n` is the number of different universes and
+        // `m` the number of variables. This should be fine as both are expected to be small.
         let mut curr_compressed_uv = ty::UniverseIndex::ROOT;
         let mut existential_in_new_uv = None;
         let mut next_orig_uv = Some(ty::UniverseIndex::ROOT);
@@ -185,14 +228,16 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
                 for var in var_infos.iter_mut() {
                     // We simply put all regions from the input into the highest
                     // compressed universe, so we only deal with them at the end.
-                    if !var.is_region() && is_existential == var.is_existential() {
-                        update_uv(var, orig_uv, is_existential)
+                    if !var.is_region() {
+                        if is_existential == var.is_existential() {
+                            update_uv(var, orig_uv, is_existential)
+                        }
                     }
                 }
             }
         }
 
-        // We uniquify regions and always put them into their own universe
+        // We put all regions into a separate universe.
         let mut first_region = true;
         for var in var_infos.iter_mut() {
             if var.is_region() {
@@ -208,93 +253,8 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
         let var_infos = self.delegate.cx().mk_canonical_var_infos(&var_infos);
         (curr_compressed_uv, var_infos)
     }
-}
-
-impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicalizer<'_, D, I> {
-    fn cx(&self) -> I {
-        self.delegate.cx()
-    }
-
-    fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
-    where
-        T: TypeFoldable<I>,
-    {
-        self.binder_index.shift_in(1);
-        let t = t.super_fold_with(self);
-        self.binder_index.shift_out(1);
-        t
-    }
-
-    fn fold_region(&mut self, r: I::Region) -> I::Region {
-        let kind = match r.kind() {
-            ty::ReBound(..) => return r,
-
-            // We may encounter `ReStatic` in item signatures or the hidden type
-            // of an opaque. `ReErased` should only be encountered in the hidden
-            // type of an opaque for regions that are ignored for the purposes of
-            // captures.
-            //
-            // FIXME: We should investigate the perf implications of not uniquifying
-            // `ReErased`. We may be able to short-circuit registering region
-            // obligations if we encounter a `ReErased` on one side, for example.
-            ty::ReStatic | ty::ReErased | ty::ReError(_) => match self.canonicalize_mode {
-                CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
-                CanonicalizeMode::Response { .. } => return r,
-            },
-
-            ty::ReEarlyParam(_) | ty::ReLateParam(_) => match self.canonicalize_mode {
-                CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
-                CanonicalizeMode::Response { .. } => {
-                    panic!("unexpected region in response: {r:?}")
-                }
-            },
-
-            ty::RePlaceholder(placeholder) => match self.canonicalize_mode {
-                // We canonicalize placeholder regions as existentials in query inputs.
-                CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
-                CanonicalizeMode::Response { max_input_universe } => {
-                    // If we have a placeholder region inside of a query, it must be from
-                    // a new universe.
-                    if max_input_universe.can_name(placeholder.universe()) {
-                        panic!("new placeholder in universe {max_input_universe:?}: {r:?}");
-                    }
-                    CanonicalVarKind::PlaceholderRegion(placeholder)
-                }
-            },
-
-            ty::ReVar(vid) => {
-                assert_eq!(
-                    self.delegate.opportunistic_resolve_lt_var(vid),
-                    r,
-                    "region vid should have been resolved fully before canonicalization"
-                );
-                match self.canonicalize_mode {
-                    CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
-                    CanonicalizeMode::Response { .. } => {
-                        CanonicalVarKind::Region(self.delegate.universe_of_lt(vid).unwrap())
-                    }
-                }
-            }
-        };
-
-        let existing_bound_var = match self.canonicalize_mode {
-            CanonicalizeMode::Input => None,
-            CanonicalizeMode::Response { .. } => {
-                self.variables.iter().position(|&v| v == r.into()).map(ty::BoundVar::from)
-            }
-        };
-
-        let var = existing_bound_var.unwrap_or_else(|| {
-            let var = ty::BoundVar::from(self.variables.len());
-            self.variables.push(r.into());
-            self.primitive_var_infos.push(CanonicalVarInfo { kind });
-            var
-        });
 
-        Region::new_anon_bound(self.cx(), self.binder_index, var)
-    }
-
-    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
+    fn cached_fold_ty(&mut self, t: I::Ty) -> I::Ty {
         let kind = match t.kind() {
             ty::Infer(i) => match i {
                 ty::TyVar(vid) => {
@@ -368,20 +328,98 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
             | ty::Tuple(_)
             | ty::Alias(_, _)
             | ty::Bound(_, _)
-            | ty::Error(_) => return t.super_fold_with(self),
+            | ty::Error(_) => {
+                return t.super_fold_with(self);
+            }
         };
 
-        let var = ty::BoundVar::from(
-            self.variables.iter().position(|&v| v == t.into()).unwrap_or_else(|| {
-                let var = self.variables.len();
-                self.variables.push(t.into());
-                self.primitive_var_infos.push(CanonicalVarInfo { kind });
-                var
-            }),
-        );
+        let var = self.get_or_insert_bound_var(t, CanonicalVarInfo { kind });
 
         Ty::new_anon_bound(self.cx(), self.binder_index, var)
     }
+}
+
+impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicalizer<'_, D, I> {
+    fn cx(&self) -> I {
+        self.delegate.cx()
+    }
+
+    fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
+    where
+        T: TypeFoldable<I>,
+    {
+        self.binder_index.shift_in(1);
+        let t = t.super_fold_with(self);
+        self.binder_index.shift_out(1);
+        t
+    }
+
+    fn fold_region(&mut self, r: I::Region) -> I::Region {
+        let kind = match r.kind() {
+            ty::ReBound(..) => return r,
+
+            // We may encounter `ReStatic` in item signatures or the hidden type
+            // of an opaque. `ReErased` should only be encountered in the hidden
+            // type of an opaque for regions that are ignored for the purposes of
+            // captures.
+            //
+            // FIXME: We should investigate the perf implications of not uniquifying
+            // `ReErased`. We may be able to short-circuit registering region
+            // obligations if we encounter a `ReErased` on one side, for example.
+            ty::ReStatic | ty::ReErased | ty::ReError(_) => match self.canonicalize_mode {
+                CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
+                CanonicalizeMode::Response { .. } => return r,
+            },
+
+            ty::ReEarlyParam(_) | ty::ReLateParam(_) => match self.canonicalize_mode {
+                CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
+                CanonicalizeMode::Response { .. } => {
+                    panic!("unexpected region in response: {r:?}")
+                }
+            },
+
+            ty::RePlaceholder(placeholder) => match self.canonicalize_mode {
+                // We canonicalize placeholder regions as existentials in query inputs.
+                CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
+                CanonicalizeMode::Response { max_input_universe } => {
+                    // If we have a placeholder region inside of a query, it must be from
+                    // a new universe.
+                    if max_input_universe.can_name(placeholder.universe()) {
+                        panic!("new placeholder in universe {max_input_universe:?}: {r:?}");
+                    }
+                    CanonicalVarKind::PlaceholderRegion(placeholder)
+                }
+            },
+
+            ty::ReVar(vid) => {
+                assert_eq!(
+                    self.delegate.opportunistic_resolve_lt_var(vid),
+                    r,
+                    "region vid should have been resolved fully before canonicalization"
+                );
+                match self.canonicalize_mode {
+                    CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
+                    CanonicalizeMode::Response { .. } => {
+                        CanonicalVarKind::Region(self.delegate.universe_of_lt(vid).unwrap())
+                    }
+                }
+            }
+        };
+
+        let var = self.get_or_insert_bound_var(r, CanonicalVarInfo { kind });
+
+        Region::new_anon_bound(self.cx(), self.binder_index, var)
+    }
+
+    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
+        if let Some(&ty) = self.cache.get(&(self.binder_index, t)) {
+            ty
+        } else {
+            let res = self.cached_fold_ty(t);
+            assert!(self.cache.insert((self.binder_index, t), res).is_none());
+            res
+        }
+    }
 
     fn fold_const(&mut self, c: I::Const) -> I::Const {
         let kind = match c.kind() {
@@ -419,14 +457,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
             | ty::ConstKind::Expr(_) => return c.super_fold_with(self),
         };
 
-        let var = ty::BoundVar::from(
-            self.variables.iter().position(|&v| v == c.into()).unwrap_or_else(|| {
-                let var = self.variables.len();
-                self.variables.push(c.into());
-                self.primitive_var_infos.push(CanonicalVarInfo { kind });
-                var
-            }),
-        );
+        let var = self.get_or_insert_bound_var(c, CanonicalVarInfo { kind });
 
         Const::new_anon_bound(self.cx(), self.binder_index, var)
     }
diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs
index 132b7400300..f2654f7534e 100644
--- a/compiler/rustc_next_trait_solver/src/resolve.rs
+++ b/compiler/rustc_next_trait_solver/src/resolve.rs
@@ -1,3 +1,4 @@
+use rustc_type_ir::data_structures::DelayedMap;
 use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::visit::TypeVisitableExt;
@@ -15,11 +16,14 @@ where
     I: Interner,
 {
     delegate: &'a D,
+    /// We're able to use a cache here as the folder does not have any
+    /// mutable state.
+    cache: DelayedMap<I::Ty, I::Ty>,
 }
 
 impl<'a, D: SolverDelegate> EagerResolver<'a, D> {
     pub fn new(delegate: &'a D) -> Self {
-        EagerResolver { delegate }
+        EagerResolver { delegate, cache: Default::default() }
     }
 }
 
@@ -42,7 +46,12 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for EagerResolv
             ty::Infer(ty::FloatVar(vid)) => self.delegate.opportunistic_resolve_float_var(vid),
             _ => {
                 if t.has_infer() {
-                    t.super_fold_with(self)
+                    if let Some(&ty) = self.cache.get(&t) {
+                        return ty;
+                    }
+                    let res = t.super_fold_with(self);
+                    assert!(self.cache.insert(t, res));
+                    res
                 } else {
                     t
                 }
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index ced1ca23e9b..ffa800348f2 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -3,7 +3,7 @@ use std::ops::ControlFlow;
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
-use rustc_type_ir::data_structures::ensure_sufficient_stack;
+use rustc_type_ir::data_structures::{HashMap, HashSet, ensure_sufficient_stack};
 use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::relate::Relate;
@@ -579,18 +579,16 @@ where
 
     #[instrument(level = "trace", skip(self))]
     pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<I, ty::NormalizesTo<I>>) {
-        goal.predicate = goal
-            .predicate
-            .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
+        goal.predicate =
+            goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, goal.param_env));
         self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal);
         self.nested_goals.normalizes_to_goals.push(goal);
     }
 
     #[instrument(level = "debug", skip(self))]
     pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal<I, I::Predicate>) {
-        goal.predicate = goal
-            .predicate
-            .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
+        goal.predicate =
+            goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, goal.param_env));
         self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal);
         self.nested_goals.goals.push((source, goal));
     }
@@ -654,6 +652,7 @@ where
             term: I::Term,
             universe_of_term: ty::UniverseIndex,
             delegate: &'a D,
+            cache: HashSet<I::Ty>,
         }
 
         impl<D: SolverDelegate<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, D, I> {
@@ -671,6 +670,10 @@ where
         {
             type Result = ControlFlow<()>;
             fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
+                if self.cache.contains(&t) {
+                    return ControlFlow::Continue(());
+                }
+
                 match t.kind() {
                     ty::Infer(ty::TyVar(vid)) => {
                         if let ty::TermKind::Ty(term) = self.term.kind() {
@@ -683,17 +686,18 @@ where
                             }
                         }
 
-                        self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())
+                        self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())?;
                     }
-                    ty::Placeholder(p) => self.check_nameable(p.universe()),
+                    ty::Placeholder(p) => self.check_nameable(p.universe())?,
                     _ => {
                         if t.has_non_region_infer() || t.has_placeholders() {
-                            t.super_visit_with(self)
-                        } else {
-                            ControlFlow::Continue(())
+                            t.super_visit_with(self)?
                         }
                     }
                 }
+
+                assert!(self.cache.insert(t));
+                ControlFlow::Continue(())
             }
 
             fn visit_const(&mut self, c: I::Const) -> Self::Result {
@@ -728,6 +732,7 @@ where
             delegate: self.delegate,
             universe_of_term,
             term: goal.predicate.term,
+            cache: Default::default(),
         };
         goal.predicate.alias.visit_with(&mut visitor).is_continue()
             && goal.param_env.visit_with(&mut visitor).is_continue()
@@ -1017,6 +1022,17 @@ where
 {
     ecx: &'me mut EvalCtxt<'a, D>,
     param_env: I::ParamEnv,
+    cache: HashMap<I::Ty, I::Ty>,
+}
+
+impl<'me, 'a, D, I> ReplaceAliasWithInfer<'me, 'a, D, I>
+where
+    D: SolverDelegate<Interner = I>,
+    I: Interner,
+{
+    fn new(ecx: &'me mut EvalCtxt<'a, D>, param_env: I::ParamEnv) -> Self {
+        ReplaceAliasWithInfer { ecx, param_env, cache: Default::default() }
+    }
 }
 
 impl<D, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, D, I>
@@ -1043,7 +1059,17 @@ where
                 );
                 infer_ty
             }
-            _ => ty.super_fold_with(self),
+            _ => {
+                if !ty.has_aliases() {
+                    ty
+                } else if let Some(&entry) = self.cache.get(&ty) {
+                    return entry;
+                } else {
+                    let res = ty.super_fold_with(self);
+                    assert!(self.cache.insert(ty, res).is_none());
+                    res
+                }
+            }
         }
     }
 
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 6cb851eb8df..948199fd55c 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -26,6 +26,13 @@ parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 20
 parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
     .suggestion = try switching the order
 
+parse_at_dot_dot_in_struct_pattern = `@ ..` is not supported in struct patterns
+    .suggestion = bind to each field separately or, if you don't need them, just remove `{$ident} @`
+
+parse_at_in_struct_pattern = Unexpected `@` in struct pattern
+    .note = struct patterns use `field: pattern` syntax to bind to fields
+    .help = consider replacing `new_name @ field_name` with `field_name: new_name` if that is what you intended
+
 parse_attr_after_generic = trailing attribute after generic parameter
     .label = attributes must go before parameters
 
@@ -805,7 +812,8 @@ parse_unexpected_expr_in_pat =
        *[false] a pattern
     }, found an expression
 
-    .label = arbitrary expressions are not allowed in patterns
+    .label = not a pattern
+    .note = arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 
 parse_unexpected_expr_in_pat_const_sugg = consider extracting the expression into a `const`
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 20bcefd4fe1..dade3912751 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2572,6 +2572,25 @@ pub(crate) struct EnumPatternInsteadOfIdentifier {
 }
 
 #[derive(Diagnostic)]
+#[diag(parse_at_dot_dot_in_struct_pattern)]
+pub(crate) struct AtDotDotInStructPattern {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(code = "", style = "verbose", applicability = "machine-applicable")]
+    pub remove: Span,
+    pub ident: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_at_in_struct_pattern)]
+#[note]
+#[help]
+pub(crate) struct AtInStructPattern {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(parse_dot_dot_dot_for_remaining_fields)]
 pub(crate) struct DotDotDotForRemainingFields {
     #[primary_span]
@@ -2589,6 +2608,7 @@ pub(crate) struct ExpectedCommaAfterPatternField {
 
 #[derive(Diagnostic)]
 #[diag(parse_unexpected_expr_in_pat)]
+#[note]
 pub(crate) struct UnexpectedExpressionInPattern {
     /// The unexpected expr's span.
     #[primary_span]
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index f7a8b8780ed..da02f98d0e5 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -18,7 +18,7 @@ use std::path::Path;
 
 use rustc_ast as ast;
 use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::{AttrItem, Attribute, MetaItem, token};
+use rustc_ast::{AttrItem, Attribute, NestedMetaItem, token};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Diag, FatalError, PResult};
@@ -160,7 +160,7 @@ pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> Tok
 pub fn parse_cfg_attr(
     cfg_attr: &Attribute,
     psess: &ParseSess,
-) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
+) -> Option<(NestedMetaItem, Vec<(AttrItem, Span)>)> {
     const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
     const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
         <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>";
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index c65cf3f40f6..4aa56cb7624 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -356,8 +356,10 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
-    pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
-        let cfg_predicate = self.parse_meta_item(AllowLeadingUnsafe::No)?;
+    pub fn parse_cfg_attr(
+        &mut self,
+    ) -> PResult<'a, (ast::NestedMetaItem, Vec<(ast::AttrItem, Span)>)> {
+        let cfg_predicate = self.parse_meta_item_inner()?;
         self.expect(&token::Comma)?;
 
         // Presumably, the majority of the time there will only be one attr.
@@ -452,7 +454,7 @@ impl<'a> Parser<'a> {
     /// ```ebnf
     /// MetaItemInner = UNSUFFIXED_LIT | MetaItem ;
     /// ```
-    fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
+    pub fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
         match self.parse_unsuffixed_meta_item_lit() {
             Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)),
             Err(err) => err.cancel(), // we provide a better error below
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index bd2ffaa0a89..7f114013320 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -17,15 +17,16 @@ use thin_vec::{ThinVec, thin_vec};
 
 use super::{ForceCollect, Parser, PathStyle, Restrictions, Trailing, UsePreAttrPos};
 use crate::errors::{
-    self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
-    DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
-    ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax,
-    InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
-    ParenRangeSuggestion, PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern,
-    SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
-    TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedExpressionInPatternSugg,
-    UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
-    UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens,
+    self, AmbiguousRangePattern, AtDotDotInStructPattern, AtInStructPattern,
+    DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern,
+    EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, ExpectedCommaAfterPatternField,
+    GenericArgsInPatRequireTurbofishSyntax, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow,
+    InclusiveRangeNoEnd, InvalidMutInPattern, ParenRangeSuggestion, PatternOnWrongSideOfAt,
+    RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed,
+    TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, UnexpectedExpressionInPattern,
+    UnexpectedExpressionInPatternSugg, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat,
+    UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam,
+    UnexpectedVertVertInPattern, WrapInParens,
 };
 use crate::parser::expr::{DestructuredFloat, could_be_unclosed_char_literal};
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
@@ -1433,7 +1434,7 @@ impl<'a> Parser<'a> {
 
     /// Parses the fields of a struct-like pattern.
     fn parse_pat_fields(&mut self) -> PResult<'a, (ThinVec<PatField>, PatFieldsRest)> {
-        let mut fields = ThinVec::new();
+        let mut fields: ThinVec<PatField> = ThinVec::new();
         let mut etc = PatFieldsRest::None;
         let mut ate_comma = true;
         let mut delayed_err: Option<Diag<'a>> = None;
@@ -1454,12 +1455,22 @@ impl<'a> Parser<'a> {
 
             // check that a comma comes after every field
             if !ate_comma {
-                let mut err =
-                    self.dcx().create_err(ExpectedCommaAfterPatternField { span: self.token.span });
+                let err = if self.token == token::At {
+                    let prev_field = fields
+                        .last()
+                        .expect("Unreachable on first iteration, not empty otherwise")
+                        .ident;
+                    self.report_misplaced_at_in_struct_pat(prev_field)
+                } else {
+                    let mut err = self
+                        .dcx()
+                        .create_err(ExpectedCommaAfterPatternField { span: self.token.span });
+                    self.recover_misplaced_pattern_modifiers(&fields, &mut err);
+                    err
+                };
                 if let Some(delayed) = delayed_err {
                     delayed.emit();
                 }
-                self.recover_misplaced_pattern_modifiers(&fields, &mut err);
                 return Err(err);
             }
             ate_comma = false;
@@ -1594,6 +1605,23 @@ impl<'a> Parser<'a> {
         Ok((fields, etc))
     }
 
+    #[deny(rustc::untranslatable_diagnostic)]
+    fn report_misplaced_at_in_struct_pat(&self, prev_field: Ident) -> Diag<'a> {
+        debug_assert_eq!(self.token, token::At);
+        let span = prev_field.span.to(self.token.span);
+        if let Some(dot_dot_span) =
+            self.look_ahead(1, |t| if t == &token::DotDot { Some(t.span) } else { None })
+        {
+            self.dcx().create_err(AtDotDotInStructPattern {
+                span: span.to(dot_dot_span),
+                remove: span.until(dot_dot_span),
+                ident: prev_field,
+            })
+        } else {
+            self.dcx().create_err(AtInStructPattern { span: span })
+        }
+    }
+
     /// If the user writes `S { ref field: name }` instead of `S { field: ref name }`, we suggest
     /// the correct code.
     fn recover_misplaced_pattern_modifiers(&self, fields: &ThinVec<PatField>, err: &mut Diag<'a>) {
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 5369f54afb9..be76d6cef2b 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -391,7 +391,7 @@ passes_lang_item_fn_with_target_feature =
 
 passes_lang_item_fn_with_track_caller =
     {passes_lang_item_fn} is not allowed to have `#[track_caller]`
-    .label = {passes_lang_item_fn} is not allowed to have `#[target_feature]`
+    .label = {passes_lang_item_fn} is not allowed to have `#[track_caller]`
 
 passes_lang_item_on_incorrect_target =
     `{$name}` lang item must be applied to a {$expected_target}
@@ -488,24 +488,18 @@ passes_naked_asm_outside_naked_fn =
     the `naked_asm!` macro can only be used in functions marked with `#[naked]`
 
 passes_naked_functions_asm_block =
-    naked functions must contain a single asm block
-    .label_multiple_asm = multiple asm blocks are unsupported in naked functions
-    .label_non_asm = non-asm is unsupported in naked functions
-
-passes_naked_functions_asm_options =
-    asm options unsupported in naked functions: {$unsupported_options}
+    naked functions must contain a single `naked_asm!` invocation
+    .label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions
+    .label_non_asm = not allowed in naked functions
 
 passes_naked_functions_incompatible_attribute =
     attribute incompatible with `#[naked]`
     .label = the `{$attr}` attribute is incompatible with `#[naked]`
     .naked_attribute = function marked with `#[naked]` here
 
-passes_naked_functions_must_use_noreturn =
-    asm in naked functions must use `noreturn` option
-    .suggestion = consider specifying that the asm block is responsible for returning from the function
-
-passes_naked_functions_operands =
-    only `const` and `sym` operands are supported in naked functions
+passes_naked_functions_must_naked_asm =
+    the `asm!` macro is not allowed in naked functions
+    .label = consider using the `naked_asm!` macro instead
 
 passes_no_link =
     attribute should be applied to an `extern crate` item
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index a24259a1e35..b3334bb70aa 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -814,7 +814,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             | Target::Mod
             | Target::GlobalAsm
             | Target::TyAlias
-            | Target::OpaqueTy
             | Target::Enum
             | Target::Variant
             | Target::Struct
@@ -1328,7 +1327,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         ) {
             let article = match target {
                 Target::ExternCrate
-                | Target::OpaqueTy
                 | Target::Enum
                 | Target::Impl
                 | Target::Expression
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index aa329fc546e..af17fbf7e4d 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -41,6 +41,7 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
             | Node::TraitItem(..)
             | Node::Variant(..)
             | Node::AnonConst(..)
+            | Node::OpaqueTy(..)
     )
 }
 
@@ -494,6 +495,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
             Node::ForeignItem(foreign_item) => {
                 intravisit::walk_foreign_item(self, foreign_item);
             }
+            Node::OpaqueTy(opaq) => intravisit::walk_opaque_ty(self, opaq),
             _ => {}
         }
         self.repr_has_repr_simd = had_repr_simd;
@@ -655,14 +657,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
         intravisit::walk_path(self, path);
     }
 
-    fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
-        if let TyKind::OpaqueDef(item_id, _, _) = ty.kind {
-            let item = self.tcx.hir().item(item_id);
-            intravisit::walk_item(self, item);
-        }
-        intravisit::walk_ty(self, ty);
-    }
-
     fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
         // When inline const blocks are used in pattern position, paths
         // referenced by it should be considered as used.
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 29a087bf759..4f00c90fa3b 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1187,27 +1187,11 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for NakedFunctionsAsmBlock {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_naked_functions_operands, code = E0787)]
-pub(crate) struct NakedFunctionsOperands {
-    #[primary_span]
-    pub unsupported_operands: Vec<Span>,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_naked_functions_asm_options, code = E0787)]
-pub(crate) struct NakedFunctionsAsmOptions {
-    #[primary_span]
-    pub span: Span,
-    pub unsupported_options: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_naked_functions_must_use_noreturn, code = E0787)]
-pub(crate) struct NakedFunctionsMustUseNoreturn {
+#[diag(passes_naked_functions_must_naked_asm, code = E0787)]
+pub(crate) struct NakedFunctionsMustNakedAsm {
     #[primary_span]
+    #[label]
     pub span: Span,
-    #[suggestion(code = ", options(noreturn)", applicability = "machine-applicable")]
-    pub last_span: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 903fb114744..8ad14b6eb74 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -230,7 +230,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
             ForeignMod,
             GlobalAsm,
             TyAlias,
-            OpaqueTy,
             Enum,
             Struct,
             Union,
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 8d3f7e0231f..b2f8d7dadff 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -1,13 +1,13 @@
 //! Checks validity of naked functions.
 
-use rustc_ast::InlineAsmOptions;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{LocalDefId, LocalModDefId};
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{ExprKind, HirIdSet, InlineAsmOperand, StmtKind};
+use rustc_hir::{ExprKind, HirIdSet, StmtKind};
 use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_middle::query::Providers;
+use rustc_middle::span_bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
 use rustc_span::Span;
@@ -15,9 +15,8 @@ use rustc_span::symbol::sym;
 use rustc_target::spec::abi::Abi;
 
 use crate::errors::{
-    NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions,
-    NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed,
-    UndefinedNakedFunctionAbi,
+    NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns,
+    ParamsNotAllowed, UndefinedNakedFunctionAbi,
 };
 
 pub(crate) fn provide(providers: &mut Providers) {
@@ -119,23 +118,28 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
 
 /// Checks that function body contains a single inline assembly block.
 fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) {
-    let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
+    let mut this = CheckInlineAssembly { items: Vec::new() };
     this.visit_body(body);
-    if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] {
+    if let [(ItemKind::NakedAsm | ItemKind::Err, _)] = this.items[..] {
         // Ok.
     } else {
         let mut must_show_error = false;
-        let mut has_asm = false;
+        let mut has_naked_asm = false;
         let mut has_err = false;
         let mut multiple_asms = vec![];
         let mut non_asms = vec![];
         for &(kind, span) in &this.items {
             match kind {
-                ItemKind::Asm if has_asm => {
+                ItemKind::NakedAsm if has_naked_asm => {
                     must_show_error = true;
                     multiple_asms.push(span);
                 }
-                ItemKind::Asm => has_asm = true,
+                ItemKind::NakedAsm => has_naked_asm = true,
+                ItemKind::InlineAsm => {
+                    has_err = true;
+
+                    tcx.dcx().emit_err(NakedFunctionsMustNakedAsm { span });
+                }
                 ItemKind::NonAsm => {
                     must_show_error = true;
                     non_asms.push(span);
@@ -157,20 +161,20 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<
     }
 }
 
-struct CheckInlineAssembly<'tcx> {
-    tcx: TyCtxt<'tcx>,
+struct CheckInlineAssembly {
     items: Vec<(ItemKind, Span)>,
 }
 
 #[derive(Copy, Clone)]
 enum ItemKind {
-    Asm,
+    NakedAsm,
+    InlineAsm,
     NonAsm,
     Err,
 }
 
-impl<'tcx> CheckInlineAssembly<'tcx> {
-    fn check_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) {
+impl CheckInlineAssembly {
+    fn check_expr<'tcx>(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) {
         match expr.kind {
             ExprKind::ConstBlock(..)
             | ExprKind::Array(..)
@@ -204,10 +208,17 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
                 self.items.push((ItemKind::NonAsm, span));
             }
 
-            ExprKind::InlineAsm(asm) => {
-                self.items.push((ItemKind::Asm, span));
-                self.check_inline_asm(asm, span);
-            }
+            ExprKind::InlineAsm(asm) => match asm.asm_macro {
+                rustc_ast::AsmMacro::Asm => {
+                    self.items.push((ItemKind::InlineAsm, span));
+                }
+                rustc_ast::AsmMacro::NakedAsm => {
+                    self.items.push((ItemKind::NakedAsm, span));
+                }
+                rustc_ast::AsmMacro::GlobalAsm => {
+                    span_bug!(span, "`global_asm!` is not allowed in this position")
+                }
+            },
 
             ExprKind::DropTemps(..) | ExprKind::Block(..) => {
                 hir::intravisit::walk_expr(self, expr);
@@ -218,52 +229,9 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
             }
         }
     }
-
-    fn check_inline_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) {
-        let unsupported_operands: Vec<Span> = asm
-            .operands
-            .iter()
-            .filter_map(|&(ref op, op_sp)| match op {
-                InlineAsmOperand::Const { .. }
-                | InlineAsmOperand::SymFn { .. }
-                | InlineAsmOperand::SymStatic { .. } => None,
-                InlineAsmOperand::In { .. }
-                | InlineAsmOperand::Out { .. }
-                | InlineAsmOperand::InOut { .. }
-                | InlineAsmOperand::SplitInOut { .. }
-                | InlineAsmOperand::Label { .. } => Some(op_sp),
-            })
-            .collect();
-        if !unsupported_operands.is_empty() {
-            self.tcx.dcx().emit_err(NakedFunctionsOperands { unsupported_operands });
-        }
-
-        let unsupported_options = asm.options.difference(InlineAsmOptions::NAKED_OPTIONS);
-        if !unsupported_options.is_empty() {
-            self.tcx.dcx().emit_err(NakedFunctionsAsmOptions {
-                span,
-                unsupported_options: unsupported_options
-                    .human_readable_names()
-                    .into_iter()
-                    .map(|name| format!("`{name}`"))
-                    .collect::<Vec<_>>()
-                    .join(", "),
-            });
-        }
-
-        if !asm.options.contains(InlineAsmOptions::NORETURN) {
-            let last_span = asm
-                .operands
-                .last()
-                .map_or_else(|| asm.template_strs.last().unwrap().2, |op| op.1)
-                .shrink_to_hi();
-
-            self.tcx.dcx().emit_err(NakedFunctionsMustUseNoreturn { span, last_span });
-        }
-    }
 }
 
-impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> {
+impl<'tcx> Visitor<'tcx> for CheckInlineAssembly {
     fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
         match stmt.kind {
             StmtKind::Item(..) => {}
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 925ee262022..056318fbcb7 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -236,7 +236,6 @@ impl<'tcx> ReachableContext<'tcx> {
                     // worklist, as determined by the privacy pass
                     hir::ItemKind::ExternCrate(_)
                     | hir::ItemKind::Use(..)
-                    | hir::ItemKind::OpaqueTy(..)
                     | hir::ItemKind::TyAlias(..)
                     | hir::ItemKind::Macro(..)
                     | hir::ItemKind::Mod(..)
@@ -287,7 +286,8 @@ impl<'tcx> ReachableContext<'tcx> {
             | Node::Field(_)
             | Node::Ty(_)
             | Node::Crate(_)
-            | Node::Synthetic => {}
+            | Node::Synthetic
+            | Node::OpaqueTy(..) => {}
             _ => {
                 bug!(
                     "found unexpected node kind in worklist: {} ({:?})",
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index 3cb7576154f..8fce4266345 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -735,10 +735,10 @@ impl<Cx: PatCx> Clone for Constructor<Cx> {
             Constructor::UnionField => Constructor::UnionField,
             Constructor::Bool(b) => Constructor::Bool(*b),
             Constructor::IntRange(range) => Constructor::IntRange(*range),
-            Constructor::F16Range(lo, hi, end) => Constructor::F16Range(lo.clone(), *hi, *end),
-            Constructor::F32Range(lo, hi, end) => Constructor::F32Range(lo.clone(), *hi, *end),
-            Constructor::F64Range(lo, hi, end) => Constructor::F64Range(lo.clone(), *hi, *end),
-            Constructor::F128Range(lo, hi, end) => Constructor::F128Range(lo.clone(), *hi, *end),
+            Constructor::F16Range(lo, hi, end) => Constructor::F16Range(*lo, *hi, *end),
+            Constructor::F32Range(lo, hi, end) => Constructor::F32Range(*lo, *hi, *end),
+            Constructor::F64Range(lo, hi, end) => Constructor::F64Range(*lo, *hi, *end),
+            Constructor::F128Range(lo, hi, end) => Constructor::F128Range(*lo, *hi, *end),
             Constructor::Str(value) => Constructor::Str(value.clone()),
             Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()),
             Constructor::Or => Constructor::Or,
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 72737fb98cb..70a9319d666 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -1027,7 +1027,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
                     // Point at this range.
                     first_range: thir_pat.span,
                     // That's the gap that isn't covered.
-                    max: gap_as_pat.to_string(),
+                    max: gap_as_pat,
                     // Suggest `lo..=max` instead.
                     suggestion: suggested_range,
                 },
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 9094b00fbfb..f67c4cb922c 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -402,8 +402,6 @@ struct EmbargoVisitor<'tcx> {
     ///     n::p::f()
     /// }
     macro_reachable: FxHashSet<(LocalModDefId, LocalModDefId)>,
-    /// Preliminary pass for marking all underlying types of `impl Trait`s as reachable.
-    impl_trait_pass: bool,
     /// Has something changed in the level map?
     changed: bool,
 }
@@ -635,21 +633,6 @@ impl<'tcx> EmbargoVisitor<'tcx> {
 
 impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        if self.impl_trait_pass
-            && let hir::ItemKind::OpaqueTy(opaque) = item.kind
-            && !opaque.in_trait
-        {
-            // FIXME: This is some serious pessimization intended to workaround deficiencies
-            // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
-            // reachable if they are returned via `impl Trait`, even from private functions.
-            let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public);
-            self.reach_through_impl_trait(item.owner_id.def_id, pub_ev)
-                .generics()
-                .predicates()
-                .ty();
-            return;
-        }
-
         // Update levels of nested things and mark all items
         // in interfaces of reachable items as reachable.
         let item_ev = self.get(item.owner_id.def_id);
@@ -659,7 +642,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             | hir::ItemKind::ExternCrate(..)
             | hir::ItemKind::GlobalAsm(..) => {}
             // The interface is empty, and all nested items are processed by `visit_item`.
-            hir::ItemKind::Mod(..) | hir::ItemKind::OpaqueTy(..) => {}
+            hir::ItemKind::Mod(..) => {}
             hir::ItemKind::Macro(macro_def, _) => {
                 if let Some(item_ev) = item_ev {
                     self.update_reachability_from_macro(item.owner_id.def_id, macro_def, item_ev);
@@ -1725,19 +1708,59 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
         tcx,
         effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(),
         macro_reachable: Default::default(),
-        // HACK(jynelson): trying to infer the type of `impl Trait` breaks `async-std` (and
-        // `pub async fn` in general). Since rustdoc never needs to do codegen and doesn't
-        // care about link-time reachability, keep them unreachable (issue #75100).
-        impl_trait_pass: !tcx.sess.opts.actually_rustdoc,
         changed: false,
     };
 
     visitor.effective_visibilities.check_invariants(tcx);
-    if visitor.impl_trait_pass {
+
+    // HACK(jynelson): trying to infer the type of `impl Trait` breaks `async-std` (and
+    // `pub async fn` in general). Since rustdoc never needs to do codegen and doesn't
+    // care about link-time reachability, keep them unreachable (issue #75100).
+    let impl_trait_pass = !tcx.sess.opts.actually_rustdoc;
+    if impl_trait_pass {
         // Underlying types of `impl Trait`s are marked as reachable unconditionally,
         // so this pass doesn't need to be a part of the fixed point iteration below.
-        tcx.hir().visit_all_item_likes_in_crate(&mut visitor);
-        visitor.impl_trait_pass = false;
+        let krate = tcx.hir_crate_items(());
+        for id in krate.opaques() {
+            let opaque = tcx.hir_node_by_def_id(id).expect_opaque_ty();
+            let should_visit = match opaque.origin {
+                hir::OpaqueTyOrigin::FnReturn {
+                    parent,
+                    in_trait_or_impl: Some(hir::RpitContext::Trait),
+                }
+                | hir::OpaqueTyOrigin::AsyncFn {
+                    parent,
+                    in_trait_or_impl: Some(hir::RpitContext::Trait),
+                } => match tcx.hir_node_by_def_id(parent).expect_trait_item().expect_fn().1 {
+                    hir::TraitFn::Required(_) => false,
+                    hir::TraitFn::Provided(..) => true,
+                },
+
+                // Always visit RPITs in functions that have definitions,
+                // and all TAITs.
+                hir::OpaqueTyOrigin::FnReturn {
+                    in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
+                    ..
+                }
+                | hir::OpaqueTyOrigin::AsyncFn {
+                    in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
+                    ..
+                }
+                | hir::OpaqueTyOrigin::TyAlias { .. } => true,
+            };
+            if should_visit {
+                // FIXME: This is some serious pessimization intended to workaround deficiencies
+                // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
+                // reachable if they are returned via `impl Trait`, even from private functions.
+                let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public);
+                visitor
+                    .reach_through_impl_trait(opaque.def_id, pub_ev)
+                    .generics()
+                    .predicates()
+                    .ty();
+            }
+        }
+
         visitor.changed = false;
     }
 
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 69742bb49b1..df898e0587f 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -2,7 +2,7 @@
 
 // tidy-alphabetical-start
 #![allow(internal_features)]
-#![allow(rustc::potential_query_instability, unused_parens)]
+#![allow(unused_parens)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(min_specialization)]
diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs
index 8d7a6e4fa9b..5e450979273 100644
--- a/compiler/rustc_query_system/src/ich/impls_syntax.rs
+++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs
@@ -68,6 +68,8 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
             // Do not hash the source as it is not encoded
             src: _,
             ref src_hash,
+            // Already includes src_hash, this is redundant
+            checksum_hash: _,
             external_src: _,
             start_pos: _,
             source_len: _,
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 46e30c614ab..582db97e1ce 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1469,11 +1469,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
 
         let unused_macro = self.unused_macros.iter().find_map(|(def_id, (_, unused_ident))| {
-            if unused_ident.name == ident.name {
-                Some((def_id.clone(), unused_ident.clone()))
-            } else {
-                None
-            }
+            if unused_ident.name == ident.name { Some((def_id, unused_ident)) } else { None }
         });
 
         if let Some((def_id, unused_ident)) = unused_macro {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 35d166e8b4a..fce5ec36c66 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -443,6 +443,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
 
         self.suggest_bare_struct_literal(&mut err);
         self.suggest_changing_type_to_const_param(&mut err, res, source, span);
+        self.explain_functions_in_pattern(&mut err, res, source);
 
         if self.suggest_pattern_match_with_let(&mut err, source, span) {
             // Fallback label.
@@ -1166,6 +1167,18 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         }
     }
 
+    fn explain_functions_in_pattern(
+        &mut self,
+        err: &mut Diag<'_>,
+        res: Option<Res>,
+        source: PathSource<'_>,
+    ) {
+        let PathSource::TupleStruct(_, _) = source else { return };
+        let Some(Res::Def(DefKind::Fn, _)) = res else { return };
+        err.primary_message("expected a pattern, found a function call");
+        err.note("function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>");
+    }
+
     fn suggest_changing_type_to_const_param(
         &mut self,
         err: &mut Diag<'_>,
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index b84408cd0cb..24a0c252e55 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1188,7 +1188,7 @@ pub struct Resolver<'ra, 'tcx> {
     /// A list of proc macro LocalDefIds, written out in the order in which
     /// they are declared in the static array generated by proc_macro_harness.
     proc_macros: Vec<NodeId>,
-    confused_type_with_std_module: FxHashMap<Span, Span>,
+    confused_type_with_std_module: FxIndexMap<Span, Span>,
     /// Whether lifetime elision was successful.
     lifetime_elision_allowed: FxHashSet<NodeId>,
 
@@ -1196,8 +1196,8 @@ pub struct Resolver<'ra, 'tcx> {
     stripped_cfg_items: Vec<StrippedCfgItem<NodeId>>,
 
     effective_visibilities: EffectiveVisibilities,
-    doc_link_resolutions: FxHashMap<LocalDefId, DocLinkResMap>,
-    doc_link_traits_in_scope: FxHashMap<LocalDefId, Vec<DefId>>,
+    doc_link_resolutions: FxIndexMap<LocalDefId, DocLinkResMap>,
+    doc_link_traits_in_scope: FxIndexMap<LocalDefId, Vec<DefId>>,
     all_macro_rules: FxHashMap<Symbol, Res>,
 
     /// Invocation ids of all glob delegations.
@@ -2148,7 +2148,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
         match self.maybe_resolve_path(&segments, Some(ns), &parent_scope, None) {
             PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()),
-            PathResult::NonModule(path_res) => path_res.full_res(),
+            PathResult::NonModule(path_res) => {
+                path_res.full_res().filter(|res| !matches!(res, Res::Def(DefKind::Ctor(..), _)))
+            }
             PathResult::Module(ModuleOrUniformRoot::ExternPrelude) | PathResult::Failed { .. } => {
                 None
             }
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index d1c1b6c882e..02e255d7726 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -6,7 +6,7 @@ use pulldown_cmark::{
 };
 use rustc_ast as ast;
 use rustc_ast::util::comments::beautify_doc_string;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::{Symbol, kw, sym};
@@ -235,8 +235,8 @@ fn span_for_value(attr: &ast::Attribute) -> Span {
 /// early and late doc link resolution regardless of their position.
 pub fn prepare_to_doc_link_resolution(
     doc_fragments: &[DocFragment],
-) -> FxHashMap<Option<DefId>, String> {
-    let mut res = FxHashMap::default();
+) -> FxIndexMap<Option<DefId>, String> {
+    let mut res = FxIndexMap::default();
     for fragment in doc_fragments {
         let out_str = res.entry(fragment.item_id).or_default();
         add_doc_fragment(out_str, fragment);
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
index 320d6616384..53834198f63 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
@@ -315,7 +315,7 @@ fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>,
 /// Encodes a ty:Ty using the Itanium C++ ABI with vendor extended type qualifiers and types for
 /// Rust types that are not used at the FFI boundary.
 #[instrument(level = "trace", skip(tcx, dict))]
-pub fn encode_ty<'tcx>(
+pub(crate) fn encode_ty<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     dict: &mut FxHashMap<DictKey<'tcx>, usize>,
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
index 5f7184a4240..83dcceeaa84 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
@@ -291,7 +291,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc
 ///   the Fn trait that defines the method (for being attached as a secondary type id).
 ///
 #[instrument(level = "trace", skip(tcx))]
-pub fn transform_instance<'tcx>(
+pub(crate) fn transform_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
     mut instance: Instance<'tcx>,
     options: TransformTyOptions,
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index b052d8d72c7..d2c03e588ff 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1242,6 +1242,10 @@ impl UnstableOptions {
             }
         })
     }
+
+    pub fn checksum_hash_algorithm(&self) -> Option<SourceFileHashAlgorithm> {
+        self.checksum_hash_algorithm
+    }
 }
 
 // The type of entry function, so users can have their own entry functions
@@ -3008,7 +3012,8 @@ pub(crate) mod dep_tracking {
     use rustc_span::edition::Edition;
     use rustc_target::spec::{
         CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel,
-        RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, WasmCAbi,
+        RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTriple,
+        TlsModel, WasmCAbi,
     };
 
     use super::{
@@ -3101,6 +3106,7 @@ pub(crate) mod dep_tracking {
         StackProtector,
         SwitchWithOptPath,
         SymbolManglingVersion,
+        SymbolVisibility,
         RemapPathScopeComponents,
         SourceFileHashAlgorithm,
         OutFileName,
diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs
index 44b96d92b19..ccc01728958 100644
--- a/compiler/rustc_session/src/config/cfg.rs
+++ b/compiler/rustc_session/src/config/cfg.rs
@@ -402,18 +402,18 @@ impl CheckCfg {
                 // Get all values map at once otherwise it would be costly.
                 // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
                 let [
-                    values_target_abi,
-                    values_target_arch,
-                    values_target_endian,
-                    values_target_env,
-                    values_target_family,
-                    values_target_os,
-                    values_target_pointer_width,
-                    values_target_vendor,
-                ] = self
-                    .expecteds
-                    .get_many_mut(VALUES)
-                    .expect("unable to get all the check-cfg values buckets");
+                    Some(values_target_abi),
+                    Some(values_target_arch),
+                    Some(values_target_endian),
+                    Some(values_target_env),
+                    Some(values_target_family),
+                    Some(values_target_os),
+                    Some(values_target_pointer_width),
+                    Some(values_target_vendor),
+                ] = self.expecteds.get_many_mut(VALUES)
+                else {
+                    panic!("unable to get all the check-cfg values buckets");
+                };
 
                 for target in TARGETS
                     .iter()
diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs
index 66ad70d8d18..b936a299b09 100644
--- a/compiler/rustc_session/src/cstore.rs
+++ b/compiler/rustc_session/src/cstore.rs
@@ -72,7 +72,7 @@ pub struct NativeLib {
     pub name: Symbol,
     /// If packed_bundled_libs enabled, actual filename of library is stored.
     pub filename: Option<Symbol>,
-    pub cfg: Option<ast::MetaItem>,
+    pub cfg: Option<ast::NestedMetaItem>,
     pub foreign_module: Option<DefId>,
     pub verbatim: Option<bool>,
     pub dll_imports: Vec<DllImport>,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index aac776d2919..d63276db493 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -13,8 +13,8 @@ use rustc_span::edition::Edition;
 use rustc_span::{RealFileName, SourceFileHashAlgorithm};
 use rustc_target::spec::{
     CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy,
-    RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
-    WasmCAbi,
+    RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility,
+    TargetTriple, TlsModel, WasmCAbi,
 };
 
 use crate::config::*;
@@ -416,7 +416,11 @@ mod desc {
         "one of: `disabled`, `trampolines`, or `aliases`";
     pub(crate) const parse_symbol_mangling_version: &str =
         "one of: `legacy`, `v0` (RFC 2603), or `hashed`";
-    pub(crate) const parse_src_file_hash: &str = "either `md5` or `sha1`";
+    pub(crate) const parse_opt_symbol_visibility: &str =
+        "one of: `hidden`, `protected`, or `interposable`";
+    pub(crate) const parse_cargo_src_file_hash: &str =
+        "one of `blake3`, `md5`, `sha1`, or `sha256`";
+    pub(crate) const parse_src_file_hash: &str = "one of `md5`, `sha1`, or `sha256`";
     pub(crate) const parse_relocation_model: &str =
         "one of supported relocation models (`rustc --print relocation-models`)";
     pub(crate) const parse_code_model: &str =
@@ -922,6 +926,20 @@ mod parse {
         true
     }
 
+    pub(crate) fn parse_opt_symbol_visibility(
+        slot: &mut Option<SymbolVisibility>,
+        v: Option<&str>,
+    ) -> bool {
+        if let Some(v) = v {
+            if let Ok(vis) = SymbolVisibility::from_str(v) {
+                *slot = Some(vis);
+            } else {
+                return false;
+            }
+        }
+        true
+    }
+
     pub(crate) fn parse_optimization_fuel(
         slot: &mut Option<(String, u64)>,
         v: Option<&str>,
@@ -1272,6 +1290,19 @@ mod parse {
         true
     }
 
+    pub(crate) fn parse_cargo_src_file_hash(
+        slot: &mut Option<SourceFileHashAlgorithm>,
+        v: Option<&str>,
+    ) -> bool {
+        match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) {
+            Some(hash_kind) => {
+                *slot = Some(hash_kind);
+            }
+            _ => return false,
+        }
+        true
+    }
+
     pub(crate) fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
         match v {
             Some(s) => {
@@ -1672,6 +1703,8 @@ options! {
         "instrument control-flow architecture protection"),
     check_cfg_all_expected: bool = (false, parse_bool, [UNTRACKED],
         "show all expected values in check-cfg diagnostics (default: no)"),
+    checksum_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_cargo_src_file_hash, [TRACKED],
+        "hash algorithm of source files used to check freshness in cargo (`blake3` or `sha256`)"),
     codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
         "the backend to use"),
     combine_cgu: bool = (false, parse_bool, [TRACKED],
@@ -1688,8 +1721,8 @@ options! {
         "compress debug info sections (none, zlib, zstd, default: none)"),
     deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED],
         "deduplicate identical diagnostics (default: yes)"),
-    default_hidden_visibility: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "overrides the `default_hidden_visibility` setting of the target"),
+    default_visibility: Option<SymbolVisibility> = (None, parse_opt_symbol_visibility, [TRACKED],
+        "overrides the `default_visibility` setting of the target"),
     dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
         "in dep-info output, omit targets for tracking dependencies of the dep-info files \
         themselves (default: no)"),
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index adc28e38462..d67e69fe0fb 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -31,7 +31,8 @@ use rustc_span::{FileNameDisplayPreference, RealFileName, Span, Symbol};
 use rustc_target::asm::InlineAsmArch;
 use rustc_target::spec::{
     CodeModel, DebuginfoKind, PanicStrategy, RelocModel, RelroLevel, SanitizerSet,
-    SmallDataThresholdSupport, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel,
+    SmallDataThresholdSupport, SplitDebuginfo, StackProtector, SymbolVisibility, Target,
+    TargetTriple, TlsModel,
 };
 
 use crate::code_stats::CodeStats;
@@ -617,12 +618,13 @@ impl Session {
         }
     }
 
-    /// Whether the default visibility of symbols should be "hidden" rather than "default".
-    pub fn default_hidden_visibility(&self) -> bool {
+    /// Returns the default symbol visibility.
+    pub fn default_visibility(&self) -> SymbolVisibility {
         self.opts
             .unstable_opts
-            .default_hidden_visibility
-            .unwrap_or(self.target.options.default_hidden_visibility)
+            .default_visibility
+            .or(self.target.options.default_visibility)
+            .unwrap_or(SymbolVisibility::Interposable)
     }
 }
 
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index 0dbbc338e73..dbae4b7e719 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -655,6 +655,7 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> {
                 }
             }
             mir::TerminatorKind::InlineAsm {
+                asm_macro: _,
                 template,
                 operands,
                 options,
diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml
index 3fdfe77ead9..c52d1fcc07f 100644
--- a/compiler/rustc_span/Cargo.toml
+++ b/compiler/rustc_span/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2021"
 
 [dependencies]
 # tidy-alphabetical-start
+blake3 = "1.5.2"
 derive-where = "1.2.7"
 indexmap = { version = "2.0.0" }
 itoa = "1.0"
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 9dbdab84a81..5b1be5bca05 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -75,7 +75,9 @@ pub mod profiling;
 
 use std::borrow::Cow;
 use std::cmp::{self, Ordering};
+use std::fmt::Display;
 use std::hash::Hash;
+use std::io::{self, Read};
 use std::ops::{Add, Range, Sub};
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
@@ -1378,7 +1380,7 @@ pub enum ExternalSourceKind {
 }
 
 impl ExternalSource {
-    pub fn get_source(&self) -> Option<&Lrc<String>> {
+    pub fn get_source(&self) -> Option<&str> {
         match self {
             ExternalSource::Foreign { kind: ExternalSourceKind::Present(ref src), .. } => Some(src),
             _ => None,
@@ -1395,6 +1397,18 @@ pub enum SourceFileHashAlgorithm {
     Md5,
     Sha1,
     Sha256,
+    Blake3,
+}
+
+impl Display for SourceFileHashAlgorithm {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str(match self {
+            Self::Md5 => "md5",
+            Self::Sha1 => "sha1",
+            Self::Sha256 => "sha256",
+            Self::Blake3 => "blake3",
+        })
+    }
 }
 
 impl FromStr for SourceFileHashAlgorithm {
@@ -1405,12 +1419,13 @@ impl FromStr for SourceFileHashAlgorithm {
             "md5" => Ok(SourceFileHashAlgorithm::Md5),
             "sha1" => Ok(SourceFileHashAlgorithm::Sha1),
             "sha256" => Ok(SourceFileHashAlgorithm::Sha256),
+            "blake3" => Ok(SourceFileHashAlgorithm::Blake3),
             _ => Err(()),
         }
     }
 }
 
-/// The hash of the on-disk source file used for debug info.
+/// The hash of the on-disk source file used for debug info and cargo freshness checks.
 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
 #[derive(HashStable_Generic, Encodable, Decodable)]
 pub struct SourceFileHash {
@@ -1418,12 +1433,22 @@ pub struct SourceFileHash {
     value: [u8; 32],
 }
 
+impl Display for SourceFileHash {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}=", self.kind)?;
+        for byte in self.value[0..self.hash_len()].into_iter() {
+            write!(f, "{byte:02x}")?;
+        }
+        Ok(())
+    }
+}
+
 impl SourceFileHash {
-    pub fn new(kind: SourceFileHashAlgorithm, src: &str) -> SourceFileHash {
+    pub fn new_in_memory(kind: SourceFileHashAlgorithm, src: impl AsRef<[u8]>) -> SourceFileHash {
         let mut hash = SourceFileHash { kind, value: Default::default() };
         let len = hash.hash_len();
         let value = &mut hash.value[..len];
-        let data = src.as_bytes();
+        let data = src.as_ref();
         match kind {
             SourceFileHashAlgorithm::Md5 => {
                 value.copy_from_slice(&Md5::digest(data));
@@ -1434,13 +1459,94 @@ impl SourceFileHash {
             SourceFileHashAlgorithm::Sha256 => {
                 value.copy_from_slice(&Sha256::digest(data));
             }
-        }
+            SourceFileHashAlgorithm::Blake3 => value.copy_from_slice(blake3::hash(data).as_bytes()),
+        };
         hash
     }
 
+    pub fn new(kind: SourceFileHashAlgorithm, src: impl Read) -> Result<SourceFileHash, io::Error> {
+        let mut hash = SourceFileHash { kind, value: Default::default() };
+        let len = hash.hash_len();
+        let value = &mut hash.value[..len];
+        // Buffer size is the recommended amount to fully leverage SIMD instructions on AVX-512 as per
+        // blake3 documentation.
+        let mut buf = vec![0; 16 * 1024];
+
+        fn digest<T>(
+            mut hasher: T,
+            mut update: impl FnMut(&mut T, &[u8]),
+            finish: impl FnOnce(T, &mut [u8]),
+            mut src: impl Read,
+            buf: &mut [u8],
+            value: &mut [u8],
+        ) -> Result<(), io::Error> {
+            loop {
+                let bytes_read = src.read(buf)?;
+                if bytes_read == 0 {
+                    break;
+                }
+                update(&mut hasher, &buf[0..bytes_read]);
+            }
+            finish(hasher, value);
+            Ok(())
+        }
+
+        match kind {
+            SourceFileHashAlgorithm::Sha256 => {
+                digest(
+                    Sha256::new(),
+                    |h, b| {
+                        h.update(b);
+                    },
+                    |h, out| out.copy_from_slice(&h.finalize()),
+                    src,
+                    &mut buf,
+                    value,
+                )?;
+            }
+            SourceFileHashAlgorithm::Sha1 => {
+                digest(
+                    Sha1::new(),
+                    |h, b| {
+                        h.update(b);
+                    },
+                    |h, out| out.copy_from_slice(&h.finalize()),
+                    src,
+                    &mut buf,
+                    value,
+                )?;
+            }
+            SourceFileHashAlgorithm::Md5 => {
+                digest(
+                    Md5::new(),
+                    |h, b| {
+                        h.update(b);
+                    },
+                    |h, out| out.copy_from_slice(&h.finalize()),
+                    src,
+                    &mut buf,
+                    value,
+                )?;
+            }
+            SourceFileHashAlgorithm::Blake3 => {
+                digest(
+                    blake3::Hasher::new(),
+                    |h, b| {
+                        h.update(b);
+                    },
+                    |h, out| out.copy_from_slice(h.finalize().as_bytes()),
+                    src,
+                    &mut buf,
+                    value,
+                )?;
+            }
+        }
+        Ok(hash)
+    }
+
     /// Check if the stored hash matches the hash of the string.
     pub fn matches(&self, src: &str) -> bool {
-        Self::new(self.kind, src) == *self
+        Self::new_in_memory(self.kind, src.as_bytes()) == *self
     }
 
     /// The bytes of the hash.
@@ -1453,7 +1559,7 @@ impl SourceFileHash {
         match self.kind {
             SourceFileHashAlgorithm::Md5 => 16,
             SourceFileHashAlgorithm::Sha1 => 20,
-            SourceFileHashAlgorithm::Sha256 => 32,
+            SourceFileHashAlgorithm::Sha256 | SourceFileHashAlgorithm::Blake3 => 32,
         }
     }
 }
@@ -1509,6 +1615,10 @@ pub struct SourceFile {
     pub src: Option<Lrc<String>>,
     /// The source code's hash.
     pub src_hash: SourceFileHash,
+    /// Used to enable cargo to use checksums to check if a crate is fresh rather
+    /// than mtimes. This might be the same as `src_hash`, and if the requested algorithm
+    /// is identical we won't compute it twice.
+    pub checksum_hash: Option<SourceFileHash>,
     /// The external source code (used for external crates, which will have a `None`
     /// value as `self.src`.
     pub external_src: FreezeLock<ExternalSource>,
@@ -1536,6 +1646,7 @@ impl Clone for SourceFile {
             name: self.name.clone(),
             src: self.src.clone(),
             src_hash: self.src_hash,
+            checksum_hash: self.checksum_hash,
             external_src: self.external_src.clone(),
             start_pos: self.start_pos,
             source_len: self.source_len,
@@ -1552,6 +1663,7 @@ impl<S: SpanEncoder> Encodable<S> for SourceFile {
     fn encode(&self, s: &mut S) {
         self.name.encode(s);
         self.src_hash.encode(s);
+        self.checksum_hash.encode(s);
         // Do not encode `start_pos` as it's global state for this session.
         self.source_len.encode(s);
 
@@ -1625,6 +1737,7 @@ impl<D: SpanDecoder> Decodable<D> for SourceFile {
     fn decode(d: &mut D) -> SourceFile {
         let name: FileName = Decodable::decode(d);
         let src_hash: SourceFileHash = Decodable::decode(d);
+        let checksum_hash: Option<SourceFileHash> = Decodable::decode(d);
         let source_len: RelativeBytePos = Decodable::decode(d);
         let lines = {
             let num_lines: u32 = Decodable::decode(d);
@@ -1650,6 +1763,7 @@ impl<D: SpanDecoder> Decodable<D> for SourceFile {
             source_len,
             src: None,
             src_hash,
+            checksum_hash,
             // Unused - the metadata decoder will construct
             // a new SourceFile, filling in `external_src` properly
             external_src: FreezeLock::frozen(ExternalSource::Unneeded),
@@ -1733,9 +1847,17 @@ impl SourceFile {
         name: FileName,
         mut src: String,
         hash_kind: SourceFileHashAlgorithm,
+        checksum_hash_kind: Option<SourceFileHashAlgorithm>,
     ) -> Result<Self, OffsetOverflowError> {
         // Compute the file hash before any normalization.
-        let src_hash = SourceFileHash::new(hash_kind, &src);
+        let src_hash = SourceFileHash::new_in_memory(hash_kind, src.as_bytes());
+        let checksum_hash = checksum_hash_kind.map(|checksum_hash_kind| {
+            if checksum_hash_kind == hash_kind {
+                src_hash
+            } else {
+                SourceFileHash::new_in_memory(checksum_hash_kind, src.as_bytes())
+            }
+        });
         let normalized_pos = normalize_src(&mut src);
 
         let stable_id = StableSourceFileId::from_filename_in_current_crate(&name);
@@ -1748,6 +1870,7 @@ impl SourceFile {
             name,
             src: Some(Lrc::new(src)),
             src_hash,
+            checksum_hash,
             external_src: FreezeLock::frozen(ExternalSource::Unneeded),
             start_pos: BytePos::from_u32(0),
             source_len: RelativeBytePos::from_u32(source_len),
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 98447147d3e..8a023305937 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -175,6 +175,7 @@ pub struct SourceMapInputs {
     pub file_loader: Box<dyn FileLoader + Send + Sync>,
     pub path_mapping: FilePathMapping,
     pub hash_kind: SourceFileHashAlgorithm,
+    pub checksum_hash_kind: Option<SourceFileHashAlgorithm>,
 }
 
 pub struct SourceMap {
@@ -187,6 +188,12 @@ pub struct SourceMap {
 
     /// The algorithm used for hashing the contents of each source file.
     hash_kind: SourceFileHashAlgorithm,
+
+    /// Similar to `hash_kind`, however this algorithm is used for checksums to determine if a crate is fresh.
+    /// `cargo` is the primary user of these.
+    ///
+    /// If this is equal to `hash_kind` then the checksum won't be computed twice.
+    checksum_hash_kind: Option<SourceFileHashAlgorithm>,
 }
 
 impl SourceMap {
@@ -195,17 +202,19 @@ impl SourceMap {
             file_loader: Box::new(RealFileLoader),
             path_mapping,
             hash_kind: SourceFileHashAlgorithm::Md5,
+            checksum_hash_kind: None,
         })
     }
 
     pub fn with_inputs(
-        SourceMapInputs { file_loader, path_mapping, hash_kind }: SourceMapInputs,
+        SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind }: SourceMapInputs,
     ) -> SourceMap {
         SourceMap {
             files: Default::default(),
             file_loader: IntoDynSyncSend(file_loader),
             path_mapping,
             hash_kind,
+            checksum_hash_kind,
         }
     }
 
@@ -307,7 +316,8 @@ impl SourceMap {
         match self.source_file_by_stable_id(stable_id) {
             Some(lrc_sf) => Ok(lrc_sf),
             None => {
-                let source_file = SourceFile::new(filename, src, self.hash_kind)?;
+                let source_file =
+                    SourceFile::new(filename, src, self.hash_kind, self.checksum_hash_kind)?;
 
                 // Let's make sure the file_id we generated above actually matches
                 // the ID we generate for the SourceFile we just created.
@@ -326,6 +336,7 @@ impl SourceMap {
         &self,
         filename: FileName,
         src_hash: SourceFileHash,
+        checksum_hash: Option<SourceFileHash>,
         stable_id: StableSourceFileId,
         source_len: u32,
         cnum: CrateNum,
@@ -340,6 +351,7 @@ impl SourceMap {
             name: filename,
             src: None,
             src_hash,
+            checksum_hash,
             external_src: FreezeLock::new(ExternalSource::Foreign {
                 kind: ExternalSourceKind::AbsentOk,
                 metadata_index,
diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs
index 0c818b94b85..5b39706f3ad 100644
--- a/compiler/rustc_span/src/source_map/tests.rs
+++ b/compiler/rustc_span/src/source_map/tests.rs
@@ -229,6 +229,7 @@ fn t10() {
     let SourceFile {
         name,
         src_hash,
+        checksum_hash,
         source_len,
         lines,
         multibyte_chars,
@@ -240,6 +241,7 @@ fn t10() {
     let imported_src_file = sm.new_imported_source_file(
         name,
         src_hash,
+        checksum_hash,
         stable_id,
         source_len.to_u32(),
         CrateNum::ZERO,
@@ -255,7 +257,7 @@ fn t10() {
     );
     imported_src_file.add_external_src(|| Some(unnormalized.to_string()));
     assert_eq!(
-        imported_src_file.external_src.borrow().get_source().unwrap().as_ref(),
+        imported_src_file.external_src.borrow().get_source().unwrap(),
         normalized,
         "imported source file should be normalized"
     );
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 8f226b26bef..1527600e764 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -411,6 +411,7 @@ symbols! {
         arbitrary_enum_discriminant,
         arbitrary_self_types,
         arbitrary_self_types_pointers,
+        areg,
         args,
         arith_offset,
         arm,
@@ -543,6 +544,7 @@ symbols! {
         cfg_accessible,
         cfg_attr,
         cfg_attr_multi,
+        cfg_boolean_literals,
         cfg_doctest,
         cfg_eval,
         cfg_fmt_debug,
diff --git a/compiler/rustc_span/src/tests.rs b/compiler/rustc_span/src/tests.rs
index 48fa786fb1c..ed1db344634 100644
--- a/compiler/rustc_span/src/tests.rs
+++ b/compiler/rustc_span/src/tests.rs
@@ -3,9 +3,13 @@ use super::*;
 #[test]
 fn test_lookup_line() {
     let source = "abcdefghijklm\nabcdefghij\n...".to_owned();
-    let mut sf =
-        SourceFile::new(FileName::Anon(Hash64::ZERO), source, SourceFileHashAlgorithm::Sha256)
-            .unwrap();
+    let mut sf = SourceFile::new(
+        FileName::Anon(Hash64::ZERO),
+        source,
+        SourceFileHashAlgorithm::Sha256,
+        Some(SourceFileHashAlgorithm::Sha256),
+    )
+    .unwrap();
     sf.start_pos = BytePos(3);
     assert_eq!(sf.lines(), &[RelativeBytePos(0), RelativeBytePos(14), RelativeBytePos(25)]);
 
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index f4469467249..352861c5ccb 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -637,7 +637,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
         }
     }
 
-    /// Pass this argument indirectly, by passing a (thin or fat) pointer to the argument instead.
+    /// Pass this argument indirectly, by passing a (thin or wide) pointer to the argument instead.
     /// This is valid for both sized and unsized arguments.
     pub fn make_indirect(&mut self) {
         match self.mode {
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index 3eaff652618..fc92e755fea 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -135,7 +135,7 @@ impl<'a> Layout<'a> {
 /// Note that the layout is NOT guaranteed to always be identical
 /// to that obtained from `layout_of(ty)`, as we need to produce
 /// layouts for which Rust types do not exist, such as enum variants
-/// or synthetic fields of enums (i.e., discriminants) and fat pointers.
+/// or synthetic fields of enums (i.e., discriminants) and wide pointers.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
 pub struct TyAndLayout<'a, Ty> {
     pub ty: Ty,
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 4d8c5cea8a8..df13d24cb9e 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -439,7 +439,7 @@ impl InlineAsmReg {
             Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
             Self::LoongArch(_) => cb(self),
             Self::Mips(_) => cb(self),
-            Self::S390x(_) => cb(self),
+            Self::S390x(r) => r.overlapping_regs(|r| cb(Self::S390x(r))),
             Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
             Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))),
             Self::Msp430(_) => cb(self),
@@ -892,6 +892,7 @@ pub enum InlineAsmClobberAbi {
     AArch64NoX18,
     RiscV,
     LoongArch,
+    S390x,
 }
 
 impl InlineAsmClobberAbi {
@@ -941,6 +942,10 @@ impl InlineAsmClobberAbi {
                 "C" | "system" => Ok(InlineAsmClobberAbi::LoongArch),
                 _ => Err(&["C", "system"]),
             },
+            InlineAsmArch::S390x => match name {
+                "C" | "system" => Ok(InlineAsmClobberAbi::S390x),
+                _ => Err(&["C", "system"]),
+            },
             _ => Err(&[]),
         }
     }
@@ -1098,6 +1103,28 @@ impl InlineAsmClobberAbi {
                     f16, f17, f18, f19, f20, f21, f22, f23,
                 }
             },
+            InlineAsmClobberAbi::S390x => clobbered_regs! {
+                S390x S390xInlineAsmReg {
+                    r0, r1, r2, r3, r4, r5,
+                    r14,
+
+                    // f0-f7, v0-v7
+                    f0, f1, f2, f3, f4, f5, f6, f7,
+                    v0, v1, v2, v3, v4, v5, v6, v7,
+
+                    // Technically the left halves of v8-v15 (i.e., f8-f15) are saved, but
+                    // we have no way of expressing this using clobbers.
+                    v8, v9, v10, v11, v12, v13, v14, v15,
+
+                    // Other vector registers are volatile
+                    v16, v17, v18, v19, v20, v21, v22, v23,
+                    v24, v25, v26, v27, v28, v29, v30, v31,
+
+                    // a0-a1 are reserved, other access registers are volatile
+                    a2, a3, a4, a5, a6, a7,
+                    a8, a9, a10, a11, a12, a13, a14, a15,
+                }
+            },
         }
     }
 }
diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs
index 4258b23ac57..9b31190a72b 100644
--- a/compiler/rustc_target/src/asm/s390x.rs
+++ b/compiler/rustc_target/src/asm/s390x.rs
@@ -9,6 +9,8 @@ def_reg_class! {
         reg,
         reg_addr,
         freg,
+        vreg,
+        areg,
     }
 }
 
@@ -35,11 +37,13 @@ impl S390xInlineAsmRegClass {
 
     pub fn supported_types(
         self,
-        arch: InlineAsmArch,
+        _arch: InlineAsmArch,
     ) -> &'static [(InlineAsmType, Option<Symbol>)] {
-        match (self, arch) {
-            (Self::reg | Self::reg_addr, _) => types! { _: I8, I16, I32, I64; },
-            (Self::freg, _) => types! { _: F32, F64; },
+        match self {
+            Self::reg | Self::reg_addr => types! { _: I8, I16, I32, I64; },
+            Self::freg => types! { _: F32, F64; },
+            Self::vreg => &[],
+            Self::areg => &[],
         }
     }
 }
@@ -76,6 +80,52 @@ def_regs! {
         f13: freg = ["f13"],
         f14: freg = ["f14"],
         f15: freg = ["f15"],
+        v0: vreg = ["v0"],
+        v1: vreg = ["v1"],
+        v2: vreg = ["v2"],
+        v3: vreg = ["v3"],
+        v4: vreg = ["v4"],
+        v5: vreg = ["v5"],
+        v6: vreg = ["v6"],
+        v7: vreg = ["v7"],
+        v8: vreg = ["v8"],
+        v9: vreg = ["v9"],
+        v10: vreg = ["v10"],
+        v11: vreg = ["v11"],
+        v12: vreg = ["v12"],
+        v13: vreg = ["v13"],
+        v14: vreg = ["v14"],
+        v15: vreg = ["v15"],
+        v16: vreg = ["v16"],
+        v17: vreg = ["v17"],
+        v18: vreg = ["v18"],
+        v19: vreg = ["v19"],
+        v20: vreg = ["v20"],
+        v21: vreg = ["v21"],
+        v22: vreg = ["v22"],
+        v23: vreg = ["v23"],
+        v24: vreg = ["v24"],
+        v25: vreg = ["v25"],
+        v26: vreg = ["v26"],
+        v27: vreg = ["v27"],
+        v28: vreg = ["v28"],
+        v29: vreg = ["v29"],
+        v30: vreg = ["v30"],
+        v31: vreg = ["v31"],
+        a2: areg = ["a2"],
+        a3: areg = ["a3"],
+        a4: areg = ["a4"],
+        a5: areg = ["a5"],
+        a6: areg = ["a6"],
+        a7: areg = ["a7"],
+        a8: areg = ["a8"],
+        a9: areg = ["a9"],
+        a10: areg = ["a10"],
+        a11: areg = ["a11"],
+        a12: areg = ["a12"],
+        a13: areg = ["a13"],
+        a14: areg = ["a14"],
+        a15: areg = ["a15"],
         #error = ["r11"] =>
             "The frame pointer cannot be used as an operand for inline asm",
         #error = ["r15"] =>
@@ -87,13 +137,8 @@ def_regs! {
             "c12", "c13", "c14", "c15"
         ] =>
             "control registers are reserved by the kernel and cannot be used as operands for inline asm",
-        #error = [
-            "a0", "a1", "a2", "a3",
-            "a4", "a5", "a6", "a7",
-            "a8", "a9", "a10", "a11",
-            "a12", "a13", "a14", "a15"
-        ] =>
-            "access registers are not supported and cannot be used as operands for inline asm",
+        #error = ["a0", "a1"] =>
+            "a0 and a1 are reserved for system use and cannot be used as operands for inline asm",
     }
 }
 
@@ -106,4 +151,48 @@ impl S390xInlineAsmReg {
     ) -> fmt::Result {
         write!(out, "%{}", self.name())
     }
+
+    pub fn overlapping_regs(self, mut cb: impl FnMut(S390xInlineAsmReg)) {
+        macro_rules! reg_conflicts {
+            (
+                $(
+                    $full:ident : $($field:ident)*
+                ),*;
+            ) => {
+                match self {
+                    $(
+                        Self::$full => {
+                            cb(Self::$full);
+                            $(cb(Self::$field);)*
+                        }
+                        $(Self::$field)|* => {
+                            cb(Self::$full);
+                            cb(self);
+                        }
+                    )*
+                    r => cb(r),
+                }
+            };
+        }
+
+        // The left halves of v0-v15 are aliased to f0-f15.
+        reg_conflicts! {
+            v0 : f0,
+            v1 : f1,
+            v2 : f2,
+            v3 : f3,
+            v4 : f4,
+            v5 : f5,
+            v6 : f6,
+            v7 : f7,
+            v8 : f8,
+            v9 : f9,
+            v10 : f10,
+            v11 : f11,
+            v12 : f12,
+            v13 : f13,
+            v14 : f14,
+            v15 : f15;
+        }
+    }
 }
diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs
index 81b5a936d35..73763cf034c 100644
--- a/compiler/rustc_target/src/spec/base/apple/mod.rs
+++ b/compiler/rustc_target/src/spec/base/apple/mod.rs
@@ -158,23 +158,6 @@ pub(crate) fn base(
     (opts, llvm_target(os, arch, abi), arch.target_arch())
 }
 
-pub fn sdk_version(platform: u32) -> Option<(u16, u8)> {
-    // NOTE: These values are from an arbitrary point in time but shouldn't make it into the final
-    // binary since the final link command will have the current SDK version passed to it.
-    match platform {
-        object::macho::PLATFORM_MACOS => Some((13, 1)),
-        object::macho::PLATFORM_IOS
-        | object::macho::PLATFORM_IOSSIMULATOR
-        | object::macho::PLATFORM_TVOS
-        | object::macho::PLATFORM_TVOSSIMULATOR
-        | object::macho::PLATFORM_MACCATALYST => Some((16, 2)),
-        object::macho::PLATFORM_WATCHOS | object::macho::PLATFORM_WATCHOSSIMULATOR => Some((9, 1)),
-        // FIXME: Upgrade to `object-rs` 0.33+ implementation with visionOS platform definition
-        11 | 12 => Some((1, 0)),
-        _ => None,
-    }
-}
-
 pub fn platform(target: &Target) -> Option<u32> {
     Some(match (&*target.os, &*target.abi) {
         ("macos", _) => object::macho::PLATFORM_MACOS,
diff --git a/compiler/rustc_target/src/spec/base/avr_gnu.rs b/compiler/rustc_target/src/spec/base/avr_gnu.rs
index fb97738618b..4f348af21ad 100644
--- a/compiler/rustc_target/src/spec/base/avr_gnu.rs
+++ b/compiler/rustc_target/src/spec/base/avr_gnu.rs
@@ -19,6 +19,8 @@ pub(crate) fn target(target_cpu: &'static str, mmcu: &'static str) -> Target {
         llvm_target: "avr-unknown-unknown".into(),
         pointer_width: 16,
         options: TargetOptions {
+            env: "gnu".into(),
+
             c_int_width: "16".into(),
             cpu: target_cpu.into(),
             exe_suffix: ".elf".into(),
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index f327c1fd179..82e11a3afce 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -61,7 +61,7 @@ pub mod crt_objects;
 mod base;
 pub use base::apple::{
     deployment_target_for_target as current_apple_deployment_target,
-    platform as current_apple_platform, sdk_version as current_apple_sdk_version,
+    platform as current_apple_platform,
 };
 pub use base::avr_gnu::ef_avr_arch;
 
@@ -830,6 +830,46 @@ impl RelroLevel {
     }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Hash)]
+pub enum SymbolVisibility {
+    Hidden,
+    Protected,
+    Interposable,
+}
+
+impl SymbolVisibility {
+    pub fn desc(&self) -> &str {
+        match *self {
+            SymbolVisibility::Hidden => "hidden",
+            SymbolVisibility::Protected => "protected",
+            SymbolVisibility::Interposable => "interposable",
+        }
+    }
+}
+
+impl FromStr for SymbolVisibility {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<SymbolVisibility, ()> {
+        match s {
+            "hidden" => Ok(SymbolVisibility::Hidden),
+            "protected" => Ok(SymbolVisibility::Protected),
+            "interposable" => Ok(SymbolVisibility::Interposable),
+            _ => Err(()),
+        }
+    }
+}
+
+impl ToJson for SymbolVisibility {
+    fn to_json(&self) -> Json {
+        match *self {
+            SymbolVisibility::Hidden => "hidden".to_json(),
+            SymbolVisibility::Protected => "protected".to_json(),
+            SymbolVisibility::Interposable => "interposable".to_json(),
+        }
+    }
+}
+
 impl FromStr for RelroLevel {
     type Err = ();
 
@@ -1790,6 +1830,7 @@ supported_targets! {
 
     ("armv7-unknown-trusty", armv7_unknown_trusty),
     ("aarch64-unknown-trusty", aarch64_unknown_trusty),
+    ("x86_64-unknown-trusty", x86_64_unknown_trusty),
 
     ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf),
     ("riscv32im-risc0-zkvm-elf", riscv32im_risc0_zkvm_elf),
@@ -1800,6 +1841,10 @@ supported_targets! {
     ("riscv32imac-esp-espidf", riscv32imac_esp_espidf),
     ("riscv32imafc-esp-espidf", riscv32imafc_esp_espidf),
 
+    ("riscv32e-unknown-none-elf", riscv32e_unknown_none_elf),
+    ("riscv32em-unknown-none-elf", riscv32em_unknown_none_elf),
+    ("riscv32emc-unknown-none-elf", riscv32emc_unknown_none_elf),
+
     ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf),
     ("riscv32imafc-unknown-none-elf", riscv32imafc_unknown_none_elf),
     ("riscv32imac-unknown-xous-elf", riscv32imac_unknown_xous_elf),
@@ -2326,13 +2371,12 @@ pub struct TargetOptions {
     /// for this target unconditionally.
     pub no_builtins: bool,
 
-    /// The default visibility for symbols in this target should be "hidden"
-    /// rather than "default".
+    /// The default visibility for symbols in this target.
     ///
-    /// This value typically shouldn't be accessed directly, but through
-    /// the `rustc_session::Session::default_hidden_visibility` method, which
-    /// allows `rustc` users to override this setting using cmdline flags.
-    pub default_hidden_visibility: bool,
+    /// This value typically shouldn't be accessed directly, but through the
+    /// `rustc_session::Session::default_visibility` method, which allows `rustc` users to override
+    /// this setting using cmdline flags.
+    pub default_visibility: Option<SymbolVisibility>,
 
     /// Whether a .debug_gdb_scripts section will be added to the output object file
     pub emit_debug_gdb_scripts: bool,
@@ -2623,7 +2667,7 @@ impl Default for TargetOptions {
             requires_lto: false,
             singlethread: false,
             no_builtins: false,
-            default_hidden_visibility: false,
+            default_visibility: None,
             emit_debug_gdb_scripts: true,
             requires_uwtable: false,
             default_uwtable: false,
@@ -2963,6 +3007,18 @@ impl Target {
                     Some(Ok(()))
                 })).unwrap_or(Ok(()))
             } );
+            ($key_name:ident, Option<SymbolVisibility>) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
+                    match s.parse::<SymbolVisibility>() {
+                        Ok(level) => base.$key_name = Some(level),
+                        _ => return Some(Err(format!("'{}' is not a valid value for \
+                                                      symbol-visibility. Use 'hidden', 'protected, or 'interposable'.",
+                                                      s))),
+                    }
+                    Some(Ok(()))
+                })).unwrap_or(Ok(()))
+            } );
             ($key_name:ident, DebuginfoKind) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
@@ -3353,7 +3409,7 @@ impl Target {
         key!(requires_lto, bool);
         key!(singlethread, bool);
         key!(no_builtins, bool);
-        key!(default_hidden_visibility, bool);
+        key!(default_visibility, Option<SymbolVisibility>)?;
         key!(emit_debug_gdb_scripts, bool);
         key!(requires_uwtable, bool);
         key!(default_uwtable, bool);
@@ -3633,7 +3689,7 @@ impl ToJson for Target {
         target_option_val!(requires_lto);
         target_option_val!(singlethread);
         target_option_val!(no_builtins);
-        target_option_val!(default_hidden_visibility);
+        target_option_val!(default_visibility);
         target_option_val!(emit_debug_gdb_scripts);
         target_option_val!(requires_uwtable);
         target_option_val!(default_uwtable);
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs b/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs
index d6d49a4a070..1f1cd966326 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs
@@ -23,6 +23,7 @@ pub(crate) fn target() -> Target {
             linker: Some("rust-lld".into()),
             link_script: Some(LINKER_SCRIPT.into()),
             os: "horizon".into(),
+            vendor: "nintendo".into(),
             max_atomic_width: Some(128),
             stack_probes: StackProbeType::Inline,
             panic_strategy: PanicStrategy::Abort,
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs
index 7e14c5efe71..e5ae1064d97 100644
--- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs
@@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
         arch: "arm".into(),
         options: TargetOptions {
+            abi: "eabi".into(),
             linker: Some("arm-kmc-eabi-gcc".into()),
             features: "+v7,+soft-float,+thumb2,-neon".into(),
             relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs
index 1958f4a7c30..0879fa24a1b 100644
--- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs
@@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
         arch: "arm".into(),
         options: TargetOptions {
+            abi: "eabihf".into(),
             linker: Some("arm-kmc-eabi-gcc".into()),
             features: "+v7,+vfp3,-d32,+thumb2,-neon".into(),
             relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs
new file mode 100644
index 00000000000..b1f52973c10
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs
@@ -0,0 +1,34 @@
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+
+pub(crate) fn target() -> Target {
+    Target {
+        // The below `data_layout` is explicitly specified by the ilp32e ABI in LLVM. See also
+        // `options.llvm_abiname`.
+        data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(),
+        llvm_target: "riscv32".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: Some("Bare RISC-V (RV32E ISA)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
+        },
+        pointer_width: 32,
+        arch: "riscv32".into(),
+
+        options: TargetOptions {
+            linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+            linker: Some("rust-lld".into()),
+            cpu: "generic-rv32".into(),
+            // The ilp32e ABI specifies the `data_layout`
+            llvm_abiname: "ilp32e".into(),
+            max_atomic_width: Some(32),
+            atomic_cas: false,
+            features: "+e,+forced-atomics".into(),
+            panic_strategy: PanicStrategy::Abort,
+            relocation_model: RelocModel::Static,
+            emit_debug_gdb_scripts: false,
+            eh_frame_header: false,
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs
new file mode 100644
index 00000000000..feeaa48778d
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs
@@ -0,0 +1,34 @@
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+
+pub(crate) fn target() -> Target {
+    Target {
+        // The below `data_layout` is explicitly specified by the ilp32e ABI in LLVM. See also
+        // `options.llvm_abiname`.
+        data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(),
+        llvm_target: "riscv32".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: Some("Bare RISC-V (RV32EM ISA)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
+        },
+        pointer_width: 32,
+        arch: "riscv32".into(),
+
+        options: TargetOptions {
+            linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+            linker: Some("rust-lld".into()),
+            cpu: "generic-rv32".into(),
+            // The ilp32e ABI specifies the `data_layout`
+            llvm_abiname: "ilp32e".into(),
+            max_atomic_width: Some(32),
+            atomic_cas: false,
+            features: "+e,+m,+forced-atomics".into(),
+            panic_strategy: PanicStrategy::Abort,
+            relocation_model: RelocModel::Static,
+            emit_debug_gdb_scripts: false,
+            eh_frame_header: false,
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs
new file mode 100644
index 00000000000..45d73c13233
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs
@@ -0,0 +1,34 @@
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+
+pub(crate) fn target() -> Target {
+    Target {
+        // The below `data_layout` is explicitly specified by the ilp32e ABI in LLVM. See also
+        // `options.llvm_abiname`.
+        data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(),
+        llvm_target: "riscv32".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: Some("Bare RISC-V (RV32EMC ISA)".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
+        },
+        pointer_width: 32,
+        arch: "riscv32".into(),
+
+        options: TargetOptions {
+            linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+            linker: Some("rust-lld".into()),
+            cpu: "generic-rv32".into(),
+            // The ilp32e ABI specifies the `data_layout`
+            llvm_abiname: "ilp32e".into(),
+            max_atomic_width: Some(32),
+            atomic_cas: false,
+            features: "+e,+m,+c,+forced-atomics".into(),
+            panic_strategy: PanicStrategy::Abort,
+            relocation_model: RelocModel::Static,
+            emit_debug_gdb_scripts: false,
+            eh_frame_header: false,
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs
index 0cd4faefd6b..0157d03f854 100644
--- a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs
@@ -7,7 +7,6 @@ pub(crate) fn target() -> Target {
         linker: Some("sparc-elf-gcc".into()),
         endian: Endian::Big,
         cpu: "v7".into(),
-        abi: "elf".into(),
         max_atomic_width: Some(32),
         atomic_cas: true,
         panic_strategy: PanicStrategy::Abort,
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs
new file mode 100644
index 00000000000..a6af06b03db
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs
@@ -0,0 +1,38 @@
+// Trusty OS target for X86_64.
+
+use crate::spec::{
+    LinkSelfContainedDefault, PanicStrategy, RelroLevel, StackProbeType, Target, TargetOptions,
+};
+
+pub(crate) fn target() -> Target {
+    Target {
+        llvm_target: "x86_64-unknown-unknown-musl".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: Some("x86_64 Trusty".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
+        },
+        pointer_width: 64,
+        data_layout:
+            "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(),
+        arch: "x86_64".into(),
+        options: TargetOptions {
+            executables: true,
+            max_atomic_width: Some(64),
+            panic_strategy: PanicStrategy::Abort,
+            os: "trusty".into(),
+            link_self_contained: LinkSelfContainedDefault::InferredForMusl,
+            position_independent_executables: true,
+            static_position_independent_executables: true,
+            crt_static_default: true,
+            crt_static_respected: true,
+            dynamic_linking: false,
+            plt_by_default: false,
+            relro_level: RelroLevel::Full,
+            stack_probes: StackProbeType::Inline,
+            mcount: "\u{1}_mcount".into(),
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index be14107baa9..0a98b363b1a 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -373,7 +373,7 @@ const MIPS_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
 
 const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("a", Stable, &[]),
+    ("a", Stable, &["zaamo", "zalrsc"]),
     ("c", Stable, &[]),
     ("d", Unstable(sym::riscv_target_feature), &["f"]),
     ("e", Unstable(sym::riscv_target_feature), &[]),
@@ -382,6 +382,9 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     ("relax", Unstable(sym::riscv_target_feature), &[]),
     ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]),
     ("v", Unstable(sym::riscv_target_feature), &[]),
+    ("zaamo", Unstable(sym::riscv_target_feature), &[]),
+    ("zabha", Unstable(sym::riscv_target_feature), &["zaamo"]),
+    ("zalrsc", Unstable(sym::riscv_target_feature), &[]),
     ("zba", Stable, &[]),
     ("zbb", Stable, &[]),
     ("zbc", Stable, &[]),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
index 4bde120cba9..a6ecd1cc987 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
@@ -284,14 +284,9 @@ pub fn suggest_new_region_bound(
         }
         match fn_return.kind {
             // FIXME(precise_captures): Suggest adding to `use<...>` list instead.
-            TyKind::OpaqueDef(item_id, _, _) => {
-                let item = tcx.hir().item(item_id);
-                let ItemKind::OpaqueTy(opaque) = &item.kind else {
-                    return;
-                };
-
+            TyKind::OpaqueDef(opaque, _) => {
                 // Get the identity type for this RPIT
-                let did = item_id.owner_id.to_def_id();
+                let did = opaque.def_id.to_def_id();
                 let ty = Ty::new_opaque(tcx, did, ty::GenericArgs::identity_for_item(tcx, did));
 
                 if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index 7802d5bf7a6..cf0ab630f2e 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -720,7 +720,7 @@ fn foo(&self) -> Self::T { String::new() }
         if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() {
             let opaque_local_def_id = def_id.as_local();
             let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
-                tcx.hir().expect_item(opaque_local_def_id).expect_opaque_ty()
+                tcx.hir().expect_opaque_ty(opaque_local_def_id)
             } else {
                 return false;
             };
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
index 41fe8a2bf22..94610a9e0e6 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -842,14 +842,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         lifetime: Region<'tcx>,
         add_lt_suggs: &mut Vec<(Span, String)>,
     ) -> String {
-        struct LifetimeReplaceVisitor<'a, 'tcx> {
-            tcx: TyCtxt<'tcx>,
+        struct LifetimeReplaceVisitor<'a> {
             needle: hir::LifetimeName,
             new_lt: &'a str,
             add_lt_suggs: &'a mut Vec<(Span, String)>,
         }
 
-        impl<'hir, 'tcx> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'_, 'tcx> {
+        impl<'hir> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'_> {
             fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) {
                 if lt.res == self.needle {
                     self.add_lt_suggs.push(lt.suggestion(self.new_lt));
@@ -857,10 +856,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
 
             fn visit_ty(&mut self, ty: &'hir hir::Ty<'hir>) {
-                let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind else {
+                let hir::TyKind::OpaqueDef(opaque_ty, _) = ty.kind else {
                     return hir::intravisit::walk_ty(self, ty);
                 };
-                let opaque_ty = self.tcx.hir().item(item_id).expect_opaque_ty();
                 if let Some(&(_, b)) =
                     opaque_ty.lifetime_mapping.iter().find(|&(a, _)| a.res == self.needle)
                 {
@@ -905,7 +903,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         };
 
         let mut visitor = LifetimeReplaceVisitor {
-            tcx: self.tcx,
             needle: hir::LifetimeName::Param(lifetime_def_id),
             add_lt_suggs,
             new_lt: &new_lt,
@@ -1269,9 +1266,9 @@ fn suggest_precise_capturing<'tcx>(
     diag: &mut Diag<'_>,
 ) {
     let hir::OpaqueTy { bounds, origin, .. } =
-        tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
+        tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty();
 
-    let hir::OpaqueTyOrigin::FnReturn(fn_def_id) = *origin else {
+    let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } = *origin else {
         return;
     };
 
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
index 6c3f3afce11..709b6eb18e3 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
@@ -731,12 +731,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 let exp_local_id = exp_def_id.as_local()?;
 
                 match (
-                    &self.tcx.hir().expect_item(last_local_id).kind,
-                    &self.tcx.hir().expect_item(exp_local_id).kind,
+                    &self.tcx.hir().expect_opaque_ty(last_local_id),
+                    &self.tcx.hir().expect_opaque_ty(exp_local_id),
                 ) {
                     (
-                        hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }),
-                        hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }),
+                        hir::OpaqueTy { bounds: last_bounds, .. },
+                        hir::OpaqueTy { bounds: exp_bounds, .. },
                     ) if std::iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| match (
                         left, right,
                     ) {
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 34a0f182ab4..824c25db07d 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
@@ -1,6 +1,7 @@
 use core::ops::ControlFlow;
 use std::borrow::Cow;
 
+use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::codes::*;
@@ -19,8 +20,8 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::print::{
-    FmtPrinter, Print, PrintTraitPredicateExt as _, PrintTraitRefExt as _,
-    with_forced_trimmed_paths,
+    FmtPrinter, Print, PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _,
+    PrintTraitRefExt as _, with_forced_trimmed_paths,
 };
 use rustc_middle::ty::{
     self, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast,
@@ -154,6 +155,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         } else {
                             (leaf_trait_predicate, &obligation)
                         };
+
+                        let (main_trait_predicate, leaf_trait_predicate, predicate_constness) = self.get_effects_trait_pred_override(main_trait_predicate, leaf_trait_predicate, span);
+
                         let main_trait_ref = main_trait_predicate.to_poly_trait_ref();
                         let leaf_trait_ref = leaf_trait_predicate.to_poly_trait_ref();
 
@@ -164,9 +168,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             return guar;
                         }
 
-                        // FIXME(effects)
-                        let predicate_is_const = false;
-
                         if let Err(guar) = leaf_trait_predicate.error_reported()
                         {
                             return guar;
@@ -227,7 +228,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         let err_msg = self.get_standard_error_message(
                             main_trait_predicate,
                             message,
-                            predicate_is_const,
+                            predicate_constness,
                             append_const_msg,
                             post_message,
                         );
@@ -245,6 +246,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                         span, "silent safe transmute error"
                                     );
                                 }
+                                GetSafeTransmuteErrorAndReason::Default => {
+                                    (err_msg, None)
+                                }
                                 GetSafeTransmuteErrorAndReason::Error {
                                     err_msg,
                                     safe_transmute_explanation,
@@ -286,7 +290,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         }
 
                         if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Drop)
-                            && predicate_is_const
+                            && matches!(predicate_constness, ty::BoundConstness::ConstIfConst | ty::BoundConstness::Const)
                         {
                             err.note("`~const Drop` was renamed to `~const Destruct`");
                             err.note("See <https://github.com/rust-lang/rust/pull/94901> for more details");
@@ -570,7 +574,26 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
                     ty::PredicateKind::DynCompatible(trait_def_id) => {
                         let violations = self.tcx.dyn_compatibility_violations(trait_def_id);
-                        report_dyn_incompatibility(self.tcx, span, None, trait_def_id, violations)
+                        let mut err = report_dyn_incompatibility(
+                            self.tcx,
+                            span,
+                            None,
+                            trait_def_id,
+                            violations,
+                        );
+                        if let hir::Node::Item(item) =
+                            self.tcx.hir_node_by_def_id(obligation.cause.body_id)
+                            && let hir::ItemKind::Impl(impl_) = item.kind
+                            && let None = impl_.of_trait
+                            && let hir::TyKind::TraitObject(_, _, syntax) = impl_.self_ty.kind
+                            && let TraitObjectSyntax::None = syntax
+                            && impl_.self_ty.span.edition().at_least_rust_2021()
+                        {
+                            // Silence the dyn-compatibility error in favor of the missing dyn on
+                            // self type error. #131051.
+                            err.downgrade_to_delayed_bug();
+                        }
+                        err
                     }
 
                     ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => {
@@ -2187,29 +2210,34 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         &self,
         trait_predicate: ty::PolyTraitPredicate<'tcx>,
         message: Option<String>,
-        predicate_is_const: bool,
+        predicate_constness: ty::BoundConstness,
         append_const_msg: Option<AppendConstMessage>,
         post_message: String,
     ) -> String {
         message
             .and_then(|cannot_do_this| {
-                match (predicate_is_const, append_const_msg) {
+                match (predicate_constness, append_const_msg) {
                     // do nothing if predicate is not const
-                    (false, _) => Some(cannot_do_this),
+                    (ty::BoundConstness::NotConst, _) => Some(cannot_do_this),
                     // suggested using default post message
-                    (true, Some(AppendConstMessage::Default)) => {
-                        Some(format!("{cannot_do_this} in const contexts"))
-                    }
+                    (
+                        ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst,
+                        Some(AppendConstMessage::Default),
+                    ) => Some(format!("{cannot_do_this} in const contexts")),
                     // overridden post message
-                    (true, Some(AppendConstMessage::Custom(custom_msg, _))) => {
-                        Some(format!("{cannot_do_this}{custom_msg}"))
-                    }
+                    (
+                        ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst,
+                        Some(AppendConstMessage::Custom(custom_msg, _)),
+                    ) => Some(format!("{cannot_do_this}{custom_msg}")),
                     // fallback to generic message
-                    (true, None) => None,
+                    (ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst, None) => None,
                 }
             })
             .unwrap_or_else(|| {
-                format!("the trait bound `{trait_predicate}` is not satisfied{post_message}")
+                format!(
+                    "the trait bound `{}` is not satisfied{post_message}",
+                    trait_predicate.print_with_bound_constness(predicate_constness)
+                )
             })
     }
 
@@ -2221,6 +2249,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     ) -> GetSafeTransmuteErrorAndReason {
         use rustc_transmute::Answer;
 
+        // We don't assemble a transmutability candidate for types that are generic
+        // and we should have ambiguity for types that still have non-region infer.
+        if obligation.predicate.has_non_region_param() || obligation.has_non_region_infer() {
+            return GetSafeTransmuteErrorAndReason::Default;
+        }
+
         // Erase regions because layout code doesn't particularly care about regions.
         let trait_ref =
             self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
@@ -2243,6 +2277,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         let dst = trait_ref.args.type_at(0);
         let src = trait_ref.args.type_at(1);
+
         let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
 
         match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
@@ -2333,6 +2368,51 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
+    /// For effects predicates such as `<u32 as Add>::Effects: Compat<host>`, pretend that the
+    /// predicate that failed was `u32: Add`. Return the constness of such predicate to later
+    /// print as `u32: ~const Add`.
+    fn get_effects_trait_pred_override(
+        &self,
+        p: ty::PolyTraitPredicate<'tcx>,
+        leaf: ty::PolyTraitPredicate<'tcx>,
+        span: Span,
+    ) -> (ty::PolyTraitPredicate<'tcx>, ty::PolyTraitPredicate<'tcx>, ty::BoundConstness) {
+        let trait_ref = p.to_poly_trait_ref();
+        if !self.tcx.is_lang_item(trait_ref.def_id(), LangItem::EffectsCompat) {
+            return (p, leaf, ty::BoundConstness::NotConst);
+        }
+
+        let Some(ty::Alias(ty::AliasTyKind::Projection, projection)) =
+            trait_ref.self_ty().no_bound_vars().map(Ty::kind)
+        else {
+            return (p, leaf, ty::BoundConstness::NotConst);
+        };
+
+        let constness = trait_ref.skip_binder().args.const_at(1);
+
+        let constness = if constness == self.tcx.consts.true_ || constness.is_ct_infer() {
+            ty::BoundConstness::NotConst
+        } else if constness == self.tcx.consts.false_ {
+            ty::BoundConstness::Const
+        } else if matches!(constness.kind(), ty::ConstKind::Param(_)) {
+            ty::BoundConstness::ConstIfConst
+        } else {
+            self.dcx().span_bug(span, format!("Unknown constness argument: {constness:?}"));
+        };
+
+        let new_pred = p.map_bound(|mut trait_pred| {
+            trait_pred.trait_ref = projection.trait_ref(self.tcx);
+            trait_pred
+        });
+
+        let new_leaf = leaf.map_bound(|mut trait_pred| {
+            trait_pred.trait_ref = projection.trait_ref(self.tcx);
+            trait_pred
+        });
+
+        (new_pred, new_leaf, constness)
+    }
+
     fn add_tuple_trait_message(
         &self,
         obligation_cause_code: &ObligationCauseCode<'tcx>,
@@ -2580,7 +2660,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         def_id: DefId,
     ) -> ErrorGuaranteed {
         let name = match self.tcx.opaque_type_origin(def_id.expect_local()) {
-            hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
+            hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } => {
                 "opaque type".to_string()
             }
             hir::OpaqueTyOrigin::TyAlias { .. } => {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index 109bae10b54..becc1acfb66 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -43,6 +43,7 @@ pub struct ImplCandidate<'tcx> {
 
 enum GetSafeTransmuteErrorAndReason {
     Silent,
+    Default,
     Error { err_msg: String, safe_transmute_explanation: Option<String> },
 }
 
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 2c7ca50f954..e9a2c5b8d8e 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
@@ -1,7 +1,7 @@
 use std::iter;
 use std::path::PathBuf;
 
-use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, MetaItem, NestedMetaItem};
+use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::codes::*;
 use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
@@ -282,7 +282,7 @@ pub struct OnUnimplementedFormatString {
 
 #[derive(Debug)]
 pub struct OnUnimplementedDirective {
-    pub condition: Option<MetaItem>,
+    pub condition: Option<NestedMetaItem>,
     pub subcommands: Vec<OnUnimplementedDirective>,
     pub message: Option<OnUnimplementedFormatString>,
     pub label: Option<OnUnimplementedFormatString>,
@@ -414,7 +414,7 @@ impl<'tcx> OnUnimplementedDirective {
             let cond = item_iter
                 .next()
                 .ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))?
-                .meta_item()
+                .meta_item_or_bool()
                 .ok_or_else(|| tcx.dcx().emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
             attr::eval_condition(cond, &tcx.sess, Some(tcx.features()), &mut |cfg| {
                 if let Some(value) = cfg.value
@@ -558,8 +558,8 @@ impl<'tcx> OnUnimplementedDirective {
                         IgnoredDiagnosticOption::maybe_emit_warning(
                             tcx,
                             item_def_id,
-                            directive.condition.as_ref().map(|i| i.span),
-                            aggr.condition.as_ref().map(|i| i.span),
+                            directive.condition.as_ref().map(|i| i.span()),
+                            aggr.condition.as_ref().map(|i| i.span()),
                             "condition",
                         );
                         IgnoredDiagnosticOption::maybe_emit_warning(
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 6df7fac949c..87834c329e1 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -355,12 +355,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         | hir::ItemKind::Fn(_, generics, _)
                         | hir::ItemKind::TyAlias(_, generics)
                         | hir::ItemKind::Const(_, generics, _)
-                        | hir::ItemKind::TraitAlias(generics, _)
-                        | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
+                        | hir::ItemKind::TraitAlias(generics, _),
                     ..
                 })
                 | hir::Node::TraitItem(hir::TraitItem { generics, .. })
                 | hir::Node::ImplItem(hir::ImplItem { generics, .. })
+                | hir::Node::OpaqueTy(hir::OpaqueTy { generics, .. })
                     if param_ty =>
                 {
                     // We skip the 0'th arg (self) because we do not want
@@ -421,10 +421,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         | hir::ItemKind::Fn(_, generics, _)
                         | hir::ItemKind::TyAlias(_, generics)
                         | hir::ItemKind::Const(_, generics, _)
-                        | hir::ItemKind::TraitAlias(generics, _)
-                        | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
+                        | hir::ItemKind::TraitAlias(generics, _),
                     ..
-                }) if !param_ty => {
+                })
+                | hir::Node::OpaqueTy(hir::OpaqueTy { generics, .. })
+                    if !param_ty =>
+                {
                     // Missing generic type parameter bound.
                     if suggest_arbitrary_trait_bound(
                         self.tcx,
@@ -4542,7 +4544,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         // ... whose signature is `async` (i.e. this is an AFIT)
         let (sig, body) = item.expect_fn();
-        let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) =
+        let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(opaq_def, ..), .. }) =
             sig.decl.output
         else {
             // This should never happen, but let's not ICE.
@@ -4551,7 +4553,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         // Check that this is *not* a nested `impl Future` RPIT in an async fn
         // (i.e. `async fn foo() -> impl Future`)
-        if def.owner_id.to_def_id() != opaque_def_id {
+        if opaq_def.def_id.to_def_id() != opaque_def_id {
             return;
         }
 
@@ -5159,7 +5161,7 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
     };
     let async_span = tcx.sess.source_map().span_extend_while_whitespace(async_span);
 
-    let future = tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
+    let future = tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty();
     let [hir::GenericBound::Trait(trait_ref, _)] = future.bounds else {
         // `async fn` should always lower to a single bound... but don't ICE.
         return None;
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index a17c007debd..11d72106b22 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -20,7 +20,6 @@
 #![feature(associated_type_defaults)]
 #![feature(box_patterns)]
 #![feature(cfg_version)]
-#![feature(control_flow_enum)]
 #![feature(extract_if)]
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index de1d4ef15ac..d562692c1a8 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -9,12 +9,13 @@ use rustc_infer::infer::canonical::{
     Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
 };
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError};
+use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError, TypeTrace};
 use rustc_macros::extension;
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast, Variance};
+use rustc_type_ir::relate::Relate;
 
 use super::{FromSolverError, FulfillmentContext, ScrubbedTraitError, TraitEngine};
 use crate::error_reporting::InferCtxtErrorExt;
@@ -133,6 +134,20 @@ where
             .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
     }
 
+    pub fn eq_trace<T: Relate<TyCtxt<'tcx>>>(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        trace: TypeTrace<'tcx>,
+        expected: T,
+        actual: T,
+    ) -> Result<(), TypeError<'tcx>> {
+        self.infcx
+            .at(cause, param_env)
+            .eq_trace(DefineOpaqueTypes::Yes, trace, expected, actual)
+            .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
+    }
+
     /// Checks whether `expected` is a subtype of `actual`: `expected <: actual`.
     pub fn sub<T: ToTrace<'tcx>>(
         &self,
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index a2760fe6049..6e6f948a2cd 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -2,6 +2,9 @@ use std::fmt::Debug;
 use std::ops::ControlFlow;
 
 use rustc_hir::def_id::DefId;
+use rustc_infer::infer::at::ToTrace;
+use rustc_infer::infer::{BoundRegionConversionTime, TyCtxtInferExt};
+use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::util::PredicateSet;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
@@ -13,7 +16,7 @@ use smallvec::{SmallVec, smallvec};
 use tracing::debug;
 
 use crate::errors::DumpVTableEntries;
-use crate::traits::{impossible_predicates, is_vtable_safe_method};
+use crate::traits::{ObligationCtxt, impossible_predicates, is_vtable_safe_method};
 
 #[derive(Clone, Debug)]
 pub enum VtblSegment<'tcx> {
@@ -22,6 +25,8 @@ pub enum VtblSegment<'tcx> {
 }
 
 /// Prepare the segments for a vtable
+// FIXME: This should take a `PolyExistentialTraitRef`, since we don't care
+// about our `Self` type here.
 pub fn prepare_vtable_segments<'tcx, T>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyTraitRef<'tcx>,
@@ -327,14 +332,10 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe
     let ty::Dynamic(source, _, _) = *key.self_ty().kind() else {
         bug!();
     };
-    let source_principal = tcx
-        .normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap())
-        .with_self_ty(tcx, tcx.types.trait_object_dummy_self);
+    let source_principal =
+        source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self);
 
-    let target_principal = tcx
-        .normalize_erasing_regions(ty::ParamEnv::reveal_all(), key)
-        // We don't care about the self type, since it will always be the same thing.
-        .with_self_ty(tcx, tcx.types.trait_object_dummy_self);
+    let target_principal = ty::Binder::dummy(ty::ExistentialTraitRef::erase_self_ty(tcx, key));
 
     let vtable_segment_callback = {
         let mut vptr_offset = 0;
@@ -343,15 +344,18 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe
                 VtblSegment::MetadataDSA => {
                     vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
                 }
-                VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
-                    if tcx
-                        .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref)
-                        == target_principal
-                    {
+                VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => {
+                    if trait_refs_are_compatible(
+                        tcx,
+                        vtable_principal
+                            .map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)),
+                        target_principal,
+                    ) {
                         return ControlFlow::Break(vptr_offset);
                     }
 
-                    vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len();
+                    vptr_offset +=
+                        tcx.own_existential_vtable_entries(vtable_principal.def_id()).len();
 
                     if emit_vptr {
                         vptr_offset += 1;
@@ -383,17 +387,14 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
     let ty::Dynamic(target, _, _) = *target.kind() else {
         bug!();
     };
-    let target_principal = tcx
-        .normalize_erasing_regions(ty::ParamEnv::reveal_all(), target.principal()?)
-        .with_self_ty(tcx, tcx.types.trait_object_dummy_self);
+    let target_principal = target.principal()?;
 
     // Given that we have a target principal, it is a bug for there not to be a source principal.
     let ty::Dynamic(source, _, _) = *source.kind() else {
         bug!();
     };
-    let source_principal = tcx
-        .normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap())
-        .with_self_ty(tcx, tcx.types.trait_object_dummy_self);
+    let source_principal =
+        source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self);
 
     let vtable_segment_callback = {
         let mut vptr_offset = 0;
@@ -402,11 +403,15 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
                 VtblSegment::MetadataDSA => {
                     vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
                 }
-                VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
-                    vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len();
-                    if tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), trait_ref)
-                        == target_principal
-                    {
+                VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => {
+                    vptr_offset +=
+                        tcx.own_existential_vtable_entries(vtable_principal.def_id()).len();
+                    if trait_refs_are_compatible(
+                        tcx,
+                        vtable_principal
+                            .map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)),
+                        target_principal,
+                    ) {
                         if emit_vptr {
                             return ControlFlow::Break(Some(vptr_offset));
                         } else {
@@ -426,6 +431,41 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
     prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap()
 }
 
+fn trait_refs_are_compatible<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    hr_vtable_principal: ty::PolyExistentialTraitRef<'tcx>,
+    hr_target_principal: ty::PolyExistentialTraitRef<'tcx>,
+) -> bool {
+    if hr_vtable_principal.def_id() != hr_target_principal.def_id() {
+        return false;
+    }
+
+    let infcx = tcx.infer_ctxt().build();
+    let param_env = ty::ParamEnv::reveal_all();
+    let ocx = ObligationCtxt::new(&infcx);
+    let hr_source_principal =
+        ocx.normalize(&ObligationCause::dummy(), param_env, hr_vtable_principal);
+    let hr_target_principal =
+        ocx.normalize(&ObligationCause::dummy(), param_env, hr_target_principal);
+    infcx.enter_forall(hr_target_principal, |target_principal| {
+        let source_principal = infcx.instantiate_binder_with_fresh_vars(
+            DUMMY_SP,
+            BoundRegionConversionTime::HigherRankedType,
+            hr_source_principal,
+        );
+        let Ok(()) = ocx.eq_trace(
+            &ObligationCause::dummy(),
+            param_env,
+            ToTrace::to_trace(&ObligationCause::dummy(), hr_target_principal, hr_source_principal),
+            target_principal,
+            source_principal,
+        ) else {
+            return false;
+        };
+        ocx.select_all_or_error().is_empty()
+    })
+}
+
 pub(super) fn provide(providers: &mut Providers) {
     *providers = Providers {
         own_existential_vtable_entries,
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index 6d5859a5a65..17eddbfcd7f 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -195,10 +195,11 @@ pub(crate) mod rustc {
     impl<'tcx> From<&LayoutError<'tcx>> for Err {
         fn from(err: &LayoutError<'tcx>) -> Self {
             match err {
-                LayoutError::Unknown(..) | LayoutError::ReferencesError(..) => Self::UnknownLayout,
+                LayoutError::Unknown(..)
+                | LayoutError::ReferencesError(..)
+                | LayoutError::NormalizationFailure(..) => Self::UnknownLayout,
                 LayoutError::SizeOverflow(..) => Self::SizeOverflow,
                 LayoutError::Cycle(err) => Self::TypeError(*err),
-                err => unimplemented!("{:?}", err),
             }
         }
     }
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
index 1e5da4ec49d..9dabcea706f 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
@@ -40,7 +40,7 @@ mod rustc {
         /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s,
         /// then computes an answer using those trees.
         #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
-        pub fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> {
+        pub(crate) fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> {
             let Self { src, dst, assume, context } = self;
 
             let layout_cx = LayoutCx::new(context, ParamEnv::reveal_all());
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index f23c2cf2c07..3d6c09bf89c 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -357,7 +357,7 @@ fn fn_abi_of_instance<'tcx>(
     )
 }
 
-// Handle safe Rust thin and fat pointers.
+// Handle safe Rust thin and wide pointers.
 fn adjust_for_rust_scalar<'tcx>(
     cx: LayoutCx<'tcx>,
     attrs: &mut ArgAttributes,
@@ -810,7 +810,7 @@ fn make_thin_self_ptr<'tcx>(
     layout: TyAndLayout<'tcx>,
 ) -> TyAndLayout<'tcx> {
     let tcx = cx.tcx();
-    let fat_pointer_ty = if layout.is_unsized() {
+    let wide_pointer_ty = if layout.is_unsized() {
         // unsized `self` is passed as a pointer to `self`
         // FIXME (mikeyhew) change this to use &own if it is ever added to the language
         Ty::new_mut_ptr(tcx, layout.ty)
@@ -825,15 +825,15 @@ fn make_thin_self_ptr<'tcx>(
         // elsewhere in the compiler as a method on a `dyn Trait`.
         // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
         // get a built-in pointer type
-        let mut fat_pointer_layout = layout;
-        while !fat_pointer_layout.ty.is_unsafe_ptr() && !fat_pointer_layout.ty.is_ref() {
-            fat_pointer_layout = fat_pointer_layout
+        let mut wide_pointer_layout = layout;
+        while !wide_pointer_layout.ty.is_unsafe_ptr() && !wide_pointer_layout.ty.is_ref() {
+            wide_pointer_layout = wide_pointer_layout
                 .non_1zst_field(cx)
                 .expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type")
                 .1
         }
 
-        fat_pointer_layout.ty
+        wide_pointer_layout.ty
     };
 
     // we now have a type like `*mut RcBox<dyn Trait>`
@@ -842,7 +842,7 @@ fn make_thin_self_ptr<'tcx>(
     let unit_ptr_ty = Ty::new_mut_ptr(tcx, tcx.types.unit);
 
     TyAndLayout {
-        ty: fat_pointer_ty,
+        ty: wide_pointer_ty,
 
         // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing the `Result`
         // should always work because the type is always `*mut ()`.
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index 6726db8bb54..a057caa9329 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -316,19 +316,16 @@ fn associated_types_for_impl_traits_in_associated_fn(
 
     match tcx.def_kind(parent_def_id) {
         DefKind::Trait => {
-            struct RPITVisitor<'tcx> {
+            struct RPITVisitor {
                 rpits: FxIndexSet<LocalDefId>,
-                tcx: TyCtxt<'tcx>,
             }
 
-            impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> {
+            impl<'tcx> Visitor<'tcx> for RPITVisitor {
                 fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
-                    if let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind
-                        && self.rpits.insert(item_id.owner_id.def_id)
+                    if let hir::TyKind::OpaqueDef(opaq, _) = ty.kind
+                        && self.rpits.insert(opaq.def_id)
                     {
-                        let opaque_item =
-                            self.tcx.hir().expect_item(item_id.owner_id.def_id).expect_opaque_ty();
-                        for bound in opaque_item.bounds {
+                        for bound in opaq.bounds {
                             intravisit::walk_param_bound(self, bound);
                         }
                     }
@@ -336,7 +333,7 @@ fn associated_types_for_impl_traits_in_associated_fn(
                 }
             }
 
-            let mut visitor = RPITVisitor { tcx, rpits: FxIndexSet::default() };
+            let mut visitor = RPITVisitor { rpits: FxIndexSet::default() };
 
             if let Some(output) = tcx.hir().get_fn_output(fn_def_id) {
                 visitor.visit_fn_ret_ty(output);
@@ -379,7 +376,8 @@ fn associated_type_for_impl_trait_in_trait(
     tcx: TyCtxt<'_>,
     opaque_ty_def_id: LocalDefId,
 ) -> LocalDefId {
-    let (hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id)) =
+    let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
+    | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) =
         tcx.opaque_type_origin(opaque_ty_def_id)
     else {
         bug!("expected opaque for {opaque_ty_def_id:?}");
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index bac0d020d72..5e2232ff47d 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -132,6 +132,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
         TaitInBodyFinder { collector: self }.visit_expr(body);
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn visit_opaque_ty(&mut self, alias_ty: ty::AliasTy<'tcx>) {
         if !self.seen.insert(alias_ty.def_id.expect_local()) {
             return;
@@ -141,7 +142,8 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
         let origin = self.tcx.opaque_type_origin(alias_ty.def_id.expect_local());
         trace!(?origin);
         match origin {
-            rustc_hir::OpaqueTyOrigin::FnReturn(_) | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {}
+            rustc_hir::OpaqueTyOrigin::FnReturn { .. }
+            | rustc_hir::OpaqueTyOrigin::AsyncFn { .. } => {}
             rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty, .. } => {
                 if !in_assoc_ty && !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) {
                     return;
diff --git a/compiler/rustc_type_ir/src/data_structures/delayed_map.rs b/compiler/rustc_type_ir/src/data_structures/delayed_map.rs
new file mode 100644
index 00000000000..7e7406e3706
--- /dev/null
+++ b/compiler/rustc_type_ir/src/data_structures/delayed_map.rs
@@ -0,0 +1,92 @@
+use std::hash::Hash;
+
+use crate::data_structures::{HashMap, HashSet};
+
+const CACHE_CUTOFF: u32 = 32;
+
+/// A hashmap which only starts hashing after ignoring the first few inputs.
+///
+/// This is used in type folders as in nearly all cases caching is not worth it
+/// as nearly all folded types are tiny. However, there are very rare incredibly
+/// large types for which caching is necessary to avoid hangs.
+#[derive(Debug)]
+pub struct DelayedMap<K, V> {
+    cache: HashMap<K, V>,
+    count: u32,
+}
+
+impl<K, V> Default for DelayedMap<K, V> {
+    fn default() -> Self {
+        DelayedMap { cache: Default::default(), count: 0 }
+    }
+}
+
+impl<K: Hash + Eq, V> DelayedMap<K, V> {
+    #[inline(always)]
+    pub fn insert(&mut self, key: K, value: V) -> bool {
+        if self.count >= CACHE_CUTOFF {
+            self.cold_insert(key, value)
+        } else {
+            self.count += 1;
+            true
+        }
+    }
+
+    #[cold]
+    #[inline(never)]
+    fn cold_insert(&mut self, key: K, value: V) -> bool {
+        self.cache.insert(key, value).is_none()
+    }
+
+    #[inline(always)]
+    pub fn get(&self, key: &K) -> Option<&V> {
+        if self.cache.is_empty() { None } else { self.cold_get(key) }
+    }
+
+    #[cold]
+    #[inline(never)]
+    fn cold_get(&self, key: &K) -> Option<&V> {
+        self.cache.get(key)
+    }
+}
+
+#[derive(Debug)]
+pub struct DelayedSet<T> {
+    cache: HashSet<T>,
+    count: u32,
+}
+
+impl<T> Default for DelayedSet<T> {
+    fn default() -> Self {
+        DelayedSet { cache: Default::default(), count: 0 }
+    }
+}
+
+impl<T: Hash + Eq> DelayedSet<T> {
+    #[inline(always)]
+    pub fn insert(&mut self, value: T) -> bool {
+        if self.count >= CACHE_CUTOFF {
+            self.cold_insert(value)
+        } else {
+            self.count += 1;
+            true
+        }
+    }
+
+    #[cold]
+    #[inline(never)]
+    fn cold_insert(&mut self, value: T) -> bool {
+        self.cache.insert(value)
+    }
+
+    #[inline(always)]
+    pub fn contains(&self, value: &T) -> bool {
+        !self.cache.is_empty() && self.cold_contains(value)
+    }
+
+    #[cold]
+    #[inline(never)]
+    fn cold_contains(&self, value: &T) -> bool {
+        self.cache.contains(value)
+    }
+}
diff --git a/compiler/rustc_type_ir/src/data_structures.rs b/compiler/rustc_type_ir/src/data_structures/mod.rs
index 96036e53b0a..d9766d91845 100644
--- a/compiler/rustc_type_ir/src/data_structures.rs
+++ b/compiler/rustc_type_ir/src/data_structures/mod.rs
@@ -6,6 +6,8 @@ pub use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
 pub type IndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<FxHasher>>;
 pub type IndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>;
 
+mod delayed_map;
+
 #[cfg(feature = "nightly")]
 mod impl_ {
     pub use rustc_data_structures::sso::{SsoHashMap, SsoHashSet};
@@ -24,4 +26,5 @@ mod impl_ {
     }
 }
 
+pub use delayed_map::{DelayedMap, DelayedSet};
 pub use impl_::*;
diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs
index 3db9b8b0661..dac45ff2aba 100644
--- a/compiler/rustc_type_ir/src/elaborate.rs
+++ b/compiler/rustc_type_ir/src/elaborate.rs
@@ -4,6 +4,7 @@ use smallvec::smallvec;
 
 use crate::data_structures::HashSet;
 use crate::inherent::*;
+use crate::lang_items::TraitSolverLangItem;
 use crate::outlives::{Component, push_outlives_components};
 use crate::{self as ty, Interner, Upcast as _};
 
@@ -43,6 +44,46 @@ pub trait Elaboratable<I: Interner> {
     ) -> Self;
 }
 
+pub struct ClauseWithSupertraitSpan<I: Interner> {
+    pub pred: I::Predicate,
+    // Span of the original elaborated predicate.
+    pub original_span: I::Span,
+    // Span of the supertrait predicatae that lead to this clause.
+    pub supertrait_span: I::Span,
+}
+impl<I: Interner> ClauseWithSupertraitSpan<I> {
+    pub fn new(pred: I::Predicate, span: I::Span) -> Self {
+        ClauseWithSupertraitSpan { pred, original_span: span, supertrait_span: span }
+    }
+}
+impl<I: Interner> Elaboratable<I> for ClauseWithSupertraitSpan<I> {
+    fn predicate(&self) -> <I as Interner>::Predicate {
+        self.pred
+    }
+
+    fn child(&self, clause: <I as Interner>::Clause) -> Self {
+        ClauseWithSupertraitSpan {
+            pred: clause.as_predicate(),
+            original_span: self.original_span,
+            supertrait_span: self.supertrait_span,
+        }
+    }
+
+    fn child_with_derived_cause(
+        &self,
+        clause: <I as Interner>::Clause,
+        supertrait_span: <I as Interner>::Span,
+        _parent_trait_pred: crate::Binder<I, crate::TraitPredicate<I>>,
+        _index: usize,
+    ) -> Self {
+        ClauseWithSupertraitSpan {
+            pred: clause.as_predicate(),
+            original_span: self.original_span,
+            supertrait_span: supertrait_span,
+        }
+    }
+}
+
 pub fn elaborate<I: Interner, O: Elaboratable<I>>(
     cx: I,
     obligations: impl IntoIterator<Item = O>,
@@ -89,6 +130,70 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
                     return;
                 }
 
+                // HACK(effects): The following code is required to get implied bounds for effects associated
+                // types to work with super traits.
+                //
+                // Suppose `data` is a trait predicate with the form `<T as Tr>::Fx: EffectsCompat<somebool>`
+                // and we know that `trait Tr: ~const SuperTr`, we need to elaborate this predicate into
+                // `<T as SuperTr>::Fx: EffectsCompat<somebool>`.
+                //
+                // Since the semantics for elaborating bounds about effects is equivalent to elaborating
+                // bounds about super traits (elaborate `T: Tr` into `T: SuperTr`), we place effects elaboration
+                // next to super trait elaboration.
+                if cx.is_lang_item(data.def_id(), TraitSolverLangItem::EffectsCompat)
+                    && matches!(self.mode, Filter::All)
+                {
+                    // first, ensure that the predicate we've got looks like a `<T as Tr>::Fx: EffectsCompat<somebool>`.
+                    if let ty::Alias(ty::AliasTyKind::Projection, alias_ty) = data.self_ty().kind()
+                    {
+                        // look for effects-level bounds that look like `<Self as Tr>::Fx: TyCompat<<Self as SuperTr>::Fx>`
+                        // on the trait, which is proof to us that `Tr: ~const SuperTr`. We're looking for bounds on the
+                        // associated trait, so we use `explicit_implied_predicates_of` since it gives us more than just
+                        // `Self: SuperTr` bounds.
+                        let bounds = cx.explicit_implied_predicates_of(cx.parent(alias_ty.def_id));
+
+                        // instantiate the implied bounds, so we get `<T as Tr>::Fx` and not `<Self as Tr>::Fx`.
+                        let elaborated = bounds.iter_instantiated(cx, alias_ty.args).filter_map(
+                            |(clause, _)| {
+                                let ty::ClauseKind::Trait(tycompat_bound) =
+                                    clause.kind().skip_binder()
+                                else {
+                                    return None;
+                                };
+                                if !cx.is_lang_item(
+                                    tycompat_bound.def_id(),
+                                    TraitSolverLangItem::EffectsTyCompat,
+                                ) {
+                                    return None;
+                                }
+
+                                // extract `<T as SuperTr>::Fx` from the `TyCompat` bound.
+                                let supertrait_effects_ty =
+                                    tycompat_bound.trait_ref.args.type_at(1);
+                                let ty::Alias(ty::AliasTyKind::Projection, supertrait_alias_ty) =
+                                    supertrait_effects_ty.kind()
+                                else {
+                                    return None;
+                                };
+
+                                // The self types (`T`) must be equal for `<T as Tr>::Fx` and `<T as SuperTr>::Fx`.
+                                if supertrait_alias_ty.self_ty() != alias_ty.self_ty() {
+                                    return None;
+                                };
+
+                                // replace the self type in the original bound `<T as Tr>::Fx: EffectsCompat<somebool>`
+                                // to the effects type of the super trait. (`<T as SuperTr>::Fx`)
+                                let elaborated_bound = data.with_self_ty(cx, supertrait_effects_ty);
+                                Some(
+                                    elaboratable
+                                        .child(bound_clause.rebind(elaborated_bound).upcast(cx)),
+                                )
+                            },
+                        );
+                        self.extend_deduped(elaborated);
+                    }
+                }
+
                 let map_to_child_clause =
                     |(index, (clause, span)): (usize, (I::Clause, I::Span))| {
                         elaboratable.child_with_derived_cause(
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 59a83ea5412..69665df4bfc 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -460,6 +460,8 @@ pub trait Clause<I: Interner<Clause = Self>>:
     + IntoKind<Kind = ty::Binder<I, ty::ClauseKind<I>>>
     + Elaboratable<I>
 {
+    fn as_predicate(self) -> I::Predicate;
+
     fn as_trait_clause(self) -> Option<ty::Binder<I, ty::TraitPredicate<I>>> {
         self.kind()
             .map_bound(|clause| if let ty::ClauseKind::Trait(t) = clause { Some(t) } else { None })
diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs
index 265a4118827..c680c844746 100644
--- a/compiler/rustc_type_ir/src/lang_items.rs
+++ b/compiler/rustc_type_ir/src/lang_items.rs
@@ -20,11 +20,13 @@ pub enum TraitSolverLangItem {
     Destruct,
     DiscriminantKind,
     DynMetadata,
+    EffectsCompat,
     EffectsIntersection,
     EffectsIntersectionOutput,
     EffectsMaybe,
     EffectsNoRuntime,
     EffectsRuntime,
+    EffectsTyCompat,
     Fn,
     FnMut,
     FnOnce,
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index 76065c10d19..8146181df6c 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -755,3 +755,10 @@ impl fmt::Display for BoundConstness {
         }
     }
 }
+
+impl<I> Lift<I> for BoundConstness {
+    type Lifted = BoundConstness;
+    fn lift_to_interner(self, _: I) -> Option<Self::Lifted> {
+        Some(self)
+    }
+}
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index ab9fc218d19..742469a1c93 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -768,8 +768,10 @@ pub enum ProjectionElem {
     ConstantIndex {
         /// index or -index (in Python terms), depending on from_end
         offset: u64,
-        /// The thing being indexed must be at least this long. For arrays this
-        /// is always the exact length.
+        /// The thing being indexed must be at least this long -- otherwise, the
+        /// projection is UB.
+        ///
+        /// For arrays this is always the exact length.
         min_length: u64,
         /// Counting backwards from end? This is always false when indexing an
         /// array.
@@ -946,10 +948,10 @@ pub enum PointerCoercion {
     ArrayToPointer,
 
     /// Unsize a pointer/reference value, e.g., `&[T; n]` to
-    /// `&[T]`. Note that the source could be a thin or fat pointer.
-    /// This will do things like convert thin pointers to fat
+    /// `&[T]`. Note that the source could be a thin or wide pointer.
+    /// This will do things like convert thin pointers to wide
     /// pointers, or convert structs containing thin pointers to
-    /// structs containing fat pointers, or convert between fat
+    /// structs containing wide pointers, or convert between wide
     /// pointers.
     Unsize,
 }
diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs
index aeae866e9d3..e2d1ff7fdd3 100644
--- a/compiler/stable_mir/src/mir/visit.rs
+++ b/compiler/stable_mir/src/mir/visit.rs
@@ -76,9 +76,9 @@ pub trait MirVisitor {
         self.super_place(place, ptx, location)
     }
 
-    fn visit_projection_elem<'a>(
+    fn visit_projection_elem(
         &mut self,
-        place_ref: PlaceRef<'a>,
+        place_ref: PlaceRef<'_>,
         elem: &ProjectionElem,
         ptx: PlaceContext,
         location: Location,
diff --git a/config.example.toml b/config.example.toml
index 47ebb20d8fa..4b591b949b3 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -759,6 +759,16 @@
 # Build compiler with the optimization enabled and -Zvalidate-mir, currently only for `std`
 #validate-mir-opts = 3
 
+# Configure `std` features used during bootstrap.
+# Default features will be expanded in the following cases:
+#  - If `rust.llvm-libunwind` or `target.llvm-libunwind` is enabled:
+#    - "llvm-libunwind" will be added for in-tree LLVM builds.
+#    - "system-llvm-libunwind" will be added for system LLVM builds.
+#  - If `rust.backtrace` is enabled, "backtrace" will be added.
+#  - If `rust.profiler` or `target.profiler` is enabled, "profiler" will be added.
+#  - If building for a zkvm target, "compiler-builtins-mem" will be added.
+#std-features = ["panic_unwind"]
+
 # =============================================================================
 # Options for specific targets
 #
diff --git a/library/Cargo.lock b/library/Cargo.lock
index e883749730c..59b76d8d442 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -61,9 +61,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.126"
+version = "0.1.133"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "758019257ad46e191b587d8f711022a6ac1d1fb6745d75e1d76c587fdcbca770"
+checksum = "ab10bf45b2ed1b4f4c25401527a61684142c042b3c86ace7da7ea6881e26741b"
 dependencies = [
  "cc",
  "rustc-std-workspace-core",
@@ -135,9 +135,9 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.14.5"
+version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
 dependencies = [
  "allocator-api2",
  "compiler_builtins",
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index 1b76b4c4a50..259a3ed2beb 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2021"
 
 [dependencies]
 core = { path = "../core" }
-compiler_builtins = { version = "0.1.126", features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "0.1.133", features = ['rustc-dep-of-std'] }
 
 [dev-dependencies]
 rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
diff --git a/library/alloc/benches/str.rs b/library/alloc/benches/str.rs
index f020638e992..98c7c5413ca 100644
--- a/library/alloc/benches/str.rs
+++ b/library/alloc/benches/str.rs
@@ -347,3 +347,5 @@ make_test!(rsplitn_space_char, s, s.rsplitn(10, ' ').count());
 
 make_test!(split_space_str, s, s.split(" ").count());
 make_test!(split_ad_str, s, s.split("ad").count());
+
+make_test!(to_lowercase, s, s.to_lowercase());
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 6421504b896..5f207295683 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -228,6 +228,7 @@ mod thin;
 #[lang = "owned_box"]
 #[fundamental]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
 // The declaration of the `Box` struct must be kept in sync with the
 // compiler or ICEs will happen.
 pub struct Box<
diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs
index 5e59abf54ee..59f10b09c73 100644
--- a/library/alloc/src/collections/binary_heap/mod.rs
+++ b/library/alloc/src/collections/binary_heap/mod.rs
@@ -374,7 +374,10 @@ impl<'a, T: Ord, A: Allocator> PeekMut<'a, T, A> {
             // the caller could've mutated the element. It is removed from the
             // heap on the next line and pop() is not sensitive to its value.
         }
-        this.heap.pop().unwrap()
+
+        // SAFETY: Have a `PeekMut` element proves that the associated binary heap being non-empty,
+        // so the `pop` operation will not fail.
+        unsafe { this.heap.pop().unwrap_unchecked() }
     }
 }
 
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index 797d591a8b5..d496899e72b 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -696,6 +696,7 @@ impl CString {
 // memory-unsafe code from working by accident. Inline
 // to prevent LLVM from optimizing it away in debug builds.
 #[stable(feature = "cstring_drop", since = "1.13.0")]
+#[rustc_insignificant_dtor]
 impl Drop for CString {
     #[inline]
     fn drop(&mut self) {
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index ff5ddd16e07..c60c0743c7e 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -115,6 +115,7 @@
 #![feature(const_option)]
 #![feature(const_pin)]
 #![feature(const_size_of_val)]
+#![feature(const_vec_string_slice)]
 #![feature(core_intrinsics)]
 #![feature(deprecated_suggestion)]
 #![feature(deref_pure_trait)]
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index 436e0596e3d..8fdca8c4200 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -280,7 +280,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must
     /// be careful.
     #[inline]
-    pub fn ptr(&self) -> *mut T {
+    pub const fn ptr(&self) -> *mut T {
         self.inner.ptr()
     }
 
@@ -293,7 +293,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     ///
     /// This will always be `usize::MAX` if `T` is zero-sized.
     #[inline]
-    pub fn capacity(&self) -> usize {
+    pub const fn capacity(&self) -> usize {
         self.inner.capacity(size_of::<T>())
     }
 
@@ -488,17 +488,17 @@ impl<A: Allocator> RawVecInner<A> {
     }
 
     #[inline]
-    fn ptr<T>(&self) -> *mut T {
+    const fn ptr<T>(&self) -> *mut T {
         self.non_null::<T>().as_ptr()
     }
 
     #[inline]
-    fn non_null<T>(&self) -> NonNull<T> {
-        self.ptr.cast().into()
+    const fn non_null<T>(&self) -> NonNull<T> {
+        self.ptr.cast().as_non_null_ptr()
     }
 
     #[inline]
-    fn capacity(&self, elem_size: usize) -> usize {
+    const fn capacity(&self, elem_size: usize) -> usize {
         if elem_size == 0 { usize::MAX } else { self.cap.0 }
     }
 
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index f636f10d5c0..a92d22b1c30 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -180,10 +180,9 @@ impl<T> [T] {
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*))
     /// worst-case.
     ///
-    /// 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.
+    /// If the implementation of [`Ord`] for `T` does not implement a [total order], the function
+    /// may panic; even if the function exits normally, the resulting order of elements in the slice
+    /// is unspecified. See also the note on panicking below.
     ///
     /// When applicable, unstable sorting is preferred because it is generally faster than stable
     /// sorting and it doesn't allocate auxiliary memory. See
@@ -212,7 +211,15 @@ impl<T> [T] {
     ///
     /// # Panics
     ///
-    /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order].
+    /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order], or if
+    /// the [`Ord`] implementation itself panics.
+    ///
+    /// All safe functions on slices preserve the invariant that even if the function panics, all
+    /// original elements will remain in the slice and any possible modifications via interior
+    /// mutability are observed in the input. This ensures that recovery code (for instance inside
+    /// of a `Drop` or following a `catch_unwind`) will still have access to all the original
+    /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able
+    /// to dispose of all contained elements.
     ///
     /// # Examples
     ///
@@ -241,10 +248,9 @@ impl<T> [T] {
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*))
     /// worst-case.
     ///
-    /// 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.
+    /// If the comparison function `compare` does not implement a [total order], the function may
+    /// panic; even if the function exits normally, the resulting order of elements in the slice is
+    /// unspecified. See also the note on panicking below.
     ///
     /// 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
@@ -263,7 +269,14 @@ impl<T> [T] {
     ///
     /// # Panics
     ///
-    /// May panic if `compare` does not implement a [total order].
+    /// May panic if `compare` does not implement a [total order], or if `compare` itself panics.
+    ///
+    /// All safe functions on slices preserve the invariant that even if the function panics, all
+    /// original elements will remain in the slice and any possible modifications via interior
+    /// mutability are observed in the input. This ensures that recovery code (for instance inside
+    /// of a `Drop` or following a `catch_unwind`) will still have access to all the original
+    /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able
+    /// to dispose of all contained elements.
     ///
     /// # Examples
     ///
@@ -295,10 +308,9 @@ 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 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.
+    /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function
+    /// may panic; even if the function exits normally, the resulting order of elements in the slice
+    /// is unspecified. See also the note on panicking below.
     ///
     /// # Current implementation
     ///
@@ -313,7 +325,15 @@ impl<T> [T] {
     ///
     /// # Panics
     ///
-    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order].
+    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if
+    /// the [`Ord`] implementation or the key-function `f` panics.
+    ///
+    /// All safe functions on slices preserve the invariant that even if the function panics, all
+    /// original elements will remain in the slice and any possible modifications via interior
+    /// mutability are observed in the input. This ensures that recovery code (for instance inside
+    /// of a `Drop` or following a `catch_unwind`) will still have access to all the original
+    /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able
+    /// to dispose of all contained elements.
     ///
     /// # Examples
     ///
@@ -347,10 +367,9 @@ 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 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.
+    /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function
+    /// may panic; even if the function exits normally, the resulting order of elements in the slice
+    /// is unspecified. See also the note on panicking below.
     ///
     /// 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.
@@ -369,7 +388,15 @@ impl<T> [T] {
     ///
     /// # Panics
     ///
-    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order].
+    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if
+    /// the [`Ord`] implementation panics.
+    ///
+    /// All safe functions on slices preserve the invariant that even if the function panics, all
+    /// original elements will remain in the slice and any possible modifications via interior
+    /// mutability are observed in the input. This ensures that recovery code (for instance inside
+    /// of a `Drop` or following a `catch_unwind`) will still have access to all the original
+    /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able
+    /// to dispose of all contained elements.
     ///
     /// # Examples
     ///
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index 32212b61c6e..42501f9c315 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -9,6 +9,7 @@
 
 use core::borrow::{Borrow, BorrowMut};
 use core::iter::FusedIterator;
+use core::mem::MaybeUninit;
 #[stable(feature = "encode_utf16", since = "1.8.0")]
 pub use core::str::EncodeUtf16;
 #[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
@@ -365,14 +366,9 @@ impl str {
                   without modifying the original"]
     #[stable(feature = "unicode_case_mapping", since = "1.2.0")]
     pub fn to_lowercase(&self) -> String {
-        let out = convert_while_ascii(self.as_bytes(), u8::to_ascii_lowercase);
+        let (mut s, rest) = convert_while_ascii(self, u8::to_ascii_lowercase);
 
-        // Safety: we know this is a valid char boundary since
-        // out.len() is only progressed if ascii bytes are found
-        let rest = unsafe { self.get_unchecked(out.len()..) };
-
-        // Safety: We have written only valid ASCII to our vec
-        let mut s = unsafe { String::from_utf8_unchecked(out) };
+        let prefix_len = s.len();
 
         for (i, c) in rest.char_indices() {
             if c == 'Σ' {
@@ -381,8 +377,7 @@ impl str {
                 // in `SpecialCasing.txt`,
                 // so hard-code it rather than have a generic "condition" mechanism.
                 // See https://github.com/rust-lang/rust/issues/26035
-                let out_len = self.len() - rest.len();
-                let sigma_lowercase = map_uppercase_sigma(&self, i + out_len);
+                let sigma_lowercase = map_uppercase_sigma(self, prefix_len + i);
                 s.push(sigma_lowercase);
             } else {
                 match conversions::to_lower(c) {
@@ -458,14 +453,7 @@ impl str {
                   without modifying the original"]
     #[stable(feature = "unicode_case_mapping", since = "1.2.0")]
     pub fn to_uppercase(&self) -> String {
-        let out = convert_while_ascii(self.as_bytes(), u8::to_ascii_uppercase);
-
-        // Safety: we know this is a valid char boundary since
-        // out.len() is only progressed if ascii bytes are found
-        let rest = unsafe { self.get_unchecked(out.len()..) };
-
-        // Safety: We have written only valid ASCII to our vec
-        let mut s = unsafe { String::from_utf8_unchecked(out) };
+        let (mut s, rest) = convert_while_ascii(self, u8::to_ascii_uppercase);
 
         for c in rest.chars() {
             match conversions::to_upper(c) {
@@ -614,50 +602,87 @@ pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> {
     unsafe { Box::from_raw(Box::into_raw(v) as *mut str) }
 }
 
-/// Converts the bytes while the bytes are still ascii.
+/// Converts leading ascii bytes in `s` by calling the `convert` function.
+///
 /// For better average performance, this happens in chunks of `2*size_of::<usize>()`.
-/// Returns a vec with the converted bytes.
+///
+/// Returns a tuple of the converted prefix and the remainder starting from
+/// the first non-ascii character.
+///
+/// This function is only public so that it can be verified in a codegen test,
+/// see `issue-123712-str-to-lower-autovectorization.rs`.
+#[unstable(feature = "str_internals", issue = "none")]
+#[doc(hidden)]
 #[inline]
 #[cfg(not(test))]
 #[cfg(not(no_global_oom_handling))]
-fn convert_while_ascii(b: &[u8], convert: fn(&u8) -> u8) -> Vec<u8> {
-    let mut out = Vec::with_capacity(b.len());
+pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) {
+    // Process the input in chunks of 16 bytes to enable auto-vectorization.
+    // Previously the chunk size depended on the size of `usize`,
+    // but on 32-bit platforms with sse or neon is also the better choice.
+    // The only downside on other platforms would be a bit more loop-unrolling.
+    const N: usize = 16;
+
+    let mut slice = s.as_bytes();
+    let mut out = Vec::with_capacity(slice.len());
+    let mut out_slice = out.spare_capacity_mut();
+
+    let mut ascii_prefix_len = 0_usize;
+    let mut is_ascii = [false; N];
+
+    while slice.len() >= N {
+        // SAFETY: checked in loop condition
+        let chunk = unsafe { slice.get_unchecked(..N) };
+        // SAFETY: out_slice has at least same length as input slice and gets sliced with the same offsets
+        let out_chunk = unsafe { out_slice.get_unchecked_mut(..N) };
+
+        for j in 0..N {
+            is_ascii[j] = chunk[j] <= 127;
+        }
 
-    const USIZE_SIZE: usize = mem::size_of::<usize>();
-    const MAGIC_UNROLL: usize = 2;
-    const N: usize = USIZE_SIZE * MAGIC_UNROLL;
-    const NONASCII_MASK: usize = usize::from_ne_bytes([0x80; USIZE_SIZE]);
+        // Auto-vectorization for this check is a bit fragile, sum and comparing against the chunk
+        // size gives the best result, specifically a pmovmsk instruction on x86.
+        // See https://github.com/llvm/llvm-project/issues/96395 for why llvm currently does not
+        // currently recognize other similar idioms.
+        if is_ascii.iter().map(|x| *x as u8).sum::<u8>() as usize != N {
+            break;
+        }
 
-    let mut i = 0;
-    unsafe {
-        while i + N <= b.len() {
-            // Safety: we have checks the sizes `b` and `out` to know that our
-            let in_chunk = b.get_unchecked(i..i + N);
-            let out_chunk = out.spare_capacity_mut().get_unchecked_mut(i..i + N);
-
-            let mut bits = 0;
-            for j in 0..MAGIC_UNROLL {
-                // read the bytes 1 usize at a time (unaligned since we haven't checked the alignment)
-                // safety: in_chunk is valid bytes in the range
-                bits |= in_chunk.as_ptr().cast::<usize>().add(j).read_unaligned();
-            }
-            // if our chunks aren't ascii, then return only the prior bytes as init
-            if bits & NONASCII_MASK != 0 {
-                break;
-            }
+        for j in 0..N {
+            out_chunk[j] = MaybeUninit::new(convert(&chunk[j]));
+        }
 
-            // perform the case conversions on N bytes (gets heavily autovec'd)
-            for j in 0..N {
-                // safety: in_chunk and out_chunk is valid bytes in the range
-                let out = out_chunk.get_unchecked_mut(j);
-                out.write(convert(in_chunk.get_unchecked(j)));
-            }
+        ascii_prefix_len += N;
+        slice = unsafe { slice.get_unchecked(N..) };
+        out_slice = unsafe { out_slice.get_unchecked_mut(N..) };
+    }
 
-            // mark these bytes as initialised
-            i += N;
+    // handle the remainder as individual bytes
+    while slice.len() > 0 {
+        let byte = slice[0];
+        if byte > 127 {
+            break;
+        }
+        // SAFETY: out_slice has at least same length as input slice
+        unsafe {
+            *out_slice.get_unchecked_mut(0) = MaybeUninit::new(convert(&byte));
         }
-        out.set_len(i);
+        ascii_prefix_len += 1;
+        slice = unsafe { slice.get_unchecked(1..) };
+        out_slice = unsafe { out_slice.get_unchecked_mut(1..) };
     }
 
-    out
+    unsafe {
+        // SAFETY: ascii_prefix_len bytes have been initialized above
+        out.set_len(ascii_prefix_len);
+
+        // SAFETY: We have written only valid ascii to the output vec
+        let ascii_string = String::from_utf8_unchecked(out);
+
+        // SAFETY: we know this is a valid char boundary
+        // since we only skipped over leading ascii bytes
+        let rest = core::str::from_utf8_unchecked(slice);
+
+        (ascii_string, rest)
+    }
 }
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index ee878e879e9..82dbf030608 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1059,7 +1059,8 @@ impl String {
     #[inline]
     #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn into_bytes(self) -> Vec<u8> {
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn into_bytes(self) -> Vec<u8> {
         self.vec
     }
 
@@ -1076,8 +1077,11 @@ impl String {
     #[must_use]
     #[stable(feature = "string_as_str", since = "1.7.0")]
     #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_str")]
-    pub fn as_str(&self) -> &str {
-        self
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn as_str(&self) -> &str {
+        // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error
+        // at construction.
+        unsafe { str::from_utf8_unchecked(self.vec.as_slice()) }
     }
 
     /// Converts a `String` into a mutable string slice.
@@ -1096,8 +1100,11 @@ impl String {
     #[must_use]
     #[stable(feature = "string_as_str", since = "1.7.0")]
     #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_mut_str")]
-    pub fn as_mut_str(&mut self) -> &mut str {
-        self
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn as_mut_str(&mut self) -> &mut str {
+        // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error
+        // at construction.
+        unsafe { str::from_utf8_unchecked_mut(self.vec.as_mut_slice()) }
     }
 
     /// Appends a given string slice onto the end of this `String`.
@@ -1168,7 +1175,8 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn capacity(&self) -> usize {
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn capacity(&self) -> usize {
         self.vec.capacity()
     }
 
@@ -1431,8 +1439,9 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn as_bytes(&self) -> &[u8] {
-        &self.vec
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn as_bytes(&self) -> &[u8] {
+        self.vec.as_slice()
     }
 
     /// Shortens this `String` to the specified length.
@@ -1784,7 +1793,8 @@ impl String {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
         &mut self.vec
     }
 
@@ -1805,8 +1815,9 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     #[rustc_confusables("length", "size")]
-    pub fn len(&self) -> usize {
+    pub const fn len(&self) -> usize {
         self.vec.len()
     }
 
@@ -1824,7 +1835,8 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn is_empty(&self) -> bool {
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
 
@@ -2589,7 +2601,7 @@ impl ops::Deref for String {
 
     #[inline]
     fn deref(&self) -> &str {
-        unsafe { str::from_utf8_unchecked(&self.vec) }
+        self.as_str()
     }
 }
 
@@ -2600,7 +2612,7 @@ unsafe impl ops::DerefPure for String {}
 impl ops::DerefMut for String {
     #[inline]
     fn deref_mut(&mut self) -> &mut str {
-        unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) }
+        self.as_mut_str()
     }
 }
 
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index ced789c4f92..5d099a49854 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -237,6 +237,7 @@ macro_rules! acquire {
 /// [rc_examples]: crate::rc#examples
 #[cfg_attr(not(test), rustc_diagnostic_item = "Arc")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
 pub struct Arc<
     T: ?Sized,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 1984cfeefc1..830512ceee8 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1240,7 +1240,8 @@ impl<T, A: Allocator> Vec<T, A> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn capacity(&self) -> usize {
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn capacity(&self) -> usize {
         self.buf.capacity()
     }
 
@@ -1548,8 +1549,22 @@ impl<T, A: Allocator> Vec<T, A> {
     #[inline]
     #[stable(feature = "vec_as_slice", since = "1.7.0")]
     #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_slice")]
-    pub fn as_slice(&self) -> &[T] {
-        self
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn as_slice(&self) -> &[T] {
+        // SAFETY: `slice::from_raw_parts` requires pointee is a contiguous, aligned buffer of size
+        // `len` containing properly-initialized `T`s. Data must not be mutated for the returned
+        // lifetime. Further, `len * mem::size_of::<T>` <= `ISIZE::MAX`, and allocation does not
+        // "wrap" through overflowing memory addresses.
+        //
+        // * Vec API guarantees that self.buf:
+        //      * contains only properly-initialized items within 0..len
+        //      * is aligned, contiguous, and valid for `len` reads
+        //      * obeys size and address-wrapping constraints
+        //
+        // * We only construct `&mut` references to `self.buf` through `&mut self` methods; borrow-
+        //   check ensures that it is not possible to mutably alias `self.buf` within the
+        //   returned lifetime.
+        unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
     }
 
     /// Extracts a mutable slice of the entire vector.
@@ -1566,8 +1581,22 @@ impl<T, A: Allocator> Vec<T, A> {
     #[inline]
     #[stable(feature = "vec_as_slice", since = "1.7.0")]
     #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_mut_slice")]
-    pub fn as_mut_slice(&mut self) -> &mut [T] {
-        self
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn as_mut_slice(&mut self) -> &mut [T] {
+        // SAFETY: `slice::from_raw_parts_mut` requires pointee is a contiguous, aligned buffer of
+        // size `len` containing properly-initialized `T`s. Data must not be accessed through any
+        // other pointer for the returned lifetime. Further, `len * mem::size_of::<T>` <=
+        // `ISIZE::MAX` and allocation does not "wrap" through overflowing memory addresses.
+        //
+        // * Vec API guarantees that self.buf:
+        //      * contains only properly-initialized items within 0..len
+        //      * is aligned, contiguous, and valid for `len` reads
+        //      * obeys size and address-wrapping constraints
+        //
+        // * We only construct references to `self.buf` through `&self` and `&mut self` methods;
+        //   borrow-check ensures that it is not possible to construct a reference to `self.buf`
+        //   within the returned lifetime.
+        unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
     }
 
     /// Returns a raw pointer to the vector's buffer, or a dangling raw pointer
@@ -1624,9 +1653,10 @@ impl<T, A: Allocator> Vec<T, A> {
     /// [`as_ptr`]: Vec::as_ptr
     /// [`as_non_null`]: Vec::as_non_null
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     #[rustc_never_returns_null_ptr]
     #[inline]
-    pub fn as_ptr(&self) -> *const T {
+    pub const fn as_ptr(&self) -> *const T {
         // We shadow the slice method of the same name to avoid going through
         // `deref`, which creates an intermediate reference.
         self.buf.ptr()
@@ -1685,9 +1715,10 @@ impl<T, A: Allocator> Vec<T, A> {
     /// [`as_ptr`]: Vec::as_ptr
     /// [`as_non_null`]: Vec::as_non_null
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     #[rustc_never_returns_null_ptr]
     #[inline]
-    pub fn as_mut_ptr(&mut self) -> *mut T {
+    pub const fn as_mut_ptr(&mut self) -> *mut T {
         // We shadow the slice method of the same name to avoid going through
         // `deref_mut`, which creates an intermediate reference.
         self.buf.ptr()
@@ -2628,8 +2659,9 @@ impl<T, A: Allocator> Vec<T, A> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
     #[rustc_confusables("length", "size")]
-    pub fn len(&self) -> usize {
+    pub const fn len(&self) -> usize {
         self.len
     }
 
@@ -2646,7 +2678,8 @@ impl<T, A: Allocator> Vec<T, A> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[cfg_attr(not(test), rustc_diagnostic_item = "vec_is_empty")]
-    pub fn is_empty(&self) -> bool {
+    #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")]
+    pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
 
@@ -3197,7 +3230,7 @@ impl<T, A: Allocator> ops::Deref for Vec<T, A> {
 
     #[inline]
     fn deref(&self) -> &[T] {
-        unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
+        self.as_slice()
     }
 }
 
@@ -3205,7 +3238,7 @@ impl<T, A: Allocator> ops::Deref for Vec<T, A> {
 impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
     #[inline]
     fn deref_mut(&mut self) -> &mut [T] {
-        unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
+        self.as_mut_slice()
     }
 }
 
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index 1d07a7690da..58d39416d95 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -7,7 +7,6 @@
 #![feature(const_cow_is_borrowed)]
 #![feature(const_heap)]
 #![cfg_attr(bootstrap, feature(const_mut_refs))]
-#![feature(const_slice_from_raw_parts_mut)]
 #![feature(const_ptr_write)]
 #![feature(const_try)]
 #![feature(core_intrinsics)]
diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs
index a80e5275dab..6f930ab0853 100644
--- a/library/alloc/tests/str.rs
+++ b/library/alloc/tests/str.rs
@@ -1854,7 +1854,10 @@ fn to_lowercase() {
     assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α");
 
     // https://github.com/rust-lang/rust/issues/124714
+    // input lengths around the boundary of the chunk size used by the ascii prefix optimization
+    assert_eq!("abcdefghijklmnoΣ".to_lowercase(), "abcdefghijklmnoς");
     assert_eq!("abcdefghijklmnopΣ".to_lowercase(), "abcdefghijklmnopς");
+    assert_eq!("abcdefghijklmnopqΣ".to_lowercase(), "abcdefghijklmnopqς");
 
     // a really long string that has it's lowercase form
     // even longer. this tests that implementations don't assume
diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs
index a6f799c4a7d..68f00d07529 100644
--- a/library/core/src/alloc/global.rs
+++ b/library/core/src/alloc/global.rs
@@ -124,8 +124,8 @@ pub unsafe trait GlobalAlloc {
     ///
     /// # Safety
     ///
-    /// This function is unsafe because undefined behavior can result
-    /// if the caller does not ensure that `layout` has non-zero size.
+    /// `layout` must have non-zero size. Attempting to allocate for a zero-sized `layout` may
+    /// result in undefined behavior.
     ///
     /// (Extension subtraits might provide more specific bounds on
     /// behavior, e.g., guarantee a sentinel address or a null pointer
@@ -156,14 +156,14 @@ pub unsafe trait GlobalAlloc {
     ///
     /// # Safety
     ///
-    /// This function is unsafe because undefined behavior can result
-    /// if the caller does not ensure all of the following:
+    /// The caller must ensure:
     ///
-    /// * `ptr` must denote a block of memory currently allocated via
-    ///   this allocator,
+    /// * `ptr` is a block of memory currently allocated via this allocator and,
     ///
-    /// * `layout` must be the same layout that was used
-    ///   to allocate that block of memory.
+    /// * `layout` is the same layout that was used to allocate that block of
+    ///   memory.
+    ///
+    /// Otherwise undefined behavior can result.
     #[stable(feature = "global_alloc", since = "1.28.0")]
     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);
 
@@ -172,7 +172,8 @@ pub unsafe trait GlobalAlloc {
     ///
     /// # Safety
     ///
-    /// This function is unsafe for the same reasons that `alloc` is.
+    /// The caller has to ensure that `layout` has non-zero size. Like `alloc`
+    /// zero sized `layout` can result in undefined behaviour.
     /// However the allocated block of memory is guaranteed to be initialized.
     ///
     /// # Errors
@@ -220,20 +221,21 @@ pub unsafe trait GlobalAlloc {
     ///
     /// # Safety
     ///
-    /// This function is unsafe because undefined behavior can result
-    /// if the caller does not ensure all of the following:
+    /// The caller must ensure that:
     ///
-    /// * `ptr` must be currently allocated via this allocator,
+    /// * `ptr` is allocated via this allocator,
     ///
-    /// * `layout` must be the same layout that was used
+    /// * `layout` is the same layout that was used
     ///   to allocate that block of memory,
     ///
-    /// * `new_size` must be greater than zero.
+    /// * `new_size` is greater than zero.
     ///
     /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
-    ///   must not overflow `isize` (i.e., the rounded value must be less than or
+    ///   does not overflow `isize` (i.e., the rounded value must be less than or
     ///   equal to `isize::MAX`).
     ///
+    /// If these are not followed, undefined behaviour can result.
+    ///
     /// (Extension subtraits might provide more specific bounds on
     /// behavior, e.g., guarantee a sentinel address or a null pointer
     /// in response to a zero-size allocation request.)
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index a3e91bc0670..95cf55a923e 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -494,8 +494,9 @@ impl<T> Cell<T> {
     /// ```
     #[inline]
     #[stable(feature = "move_cell", since = "1.17.0")]
+    #[rustc_const_unstable(feature = "const_cell", issue = "131283")]
     #[rustc_confusables("swap")]
-    pub fn replace(&self, val: T) -> T {
+    pub const fn replace(&self, val: T) -> T {
         // SAFETY: This can cause data races if called from a separate thread,
         // but `Cell` is `!Sync` so this won't happen.
         mem::replace(unsafe { &mut *self.value.get() }, val)
@@ -514,7 +515,8 @@ impl<T> Cell<T> {
     /// assert_eq!(five, 5);
     /// ```
     #[stable(feature = "move_cell", since = "1.17.0")]
-    #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
+    #[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_allow_const_fn_unstable(const_precise_live_drops)]
     pub const fn into_inner(self) -> T {
         self.value.into_inner()
     }
@@ -534,7 +536,8 @@ impl<T: Copy> Cell<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get(&self) -> T {
+    #[rustc_const_unstable(feature = "const_cell", issue = "131283")]
+    pub const fn get(&self) -> T {
         // SAFETY: This can cause data races if called from a separate thread,
         // but `Cell` is `!Sync` so this won't happen.
         unsafe { *self.value.get() }
@@ -612,7 +615,8 @@ impl<T: ?Sized> Cell<T> {
     /// ```
     #[inline]
     #[stable(feature = "cell_get_mut", since = "1.11.0")]
-    pub fn get_mut(&mut self) -> &mut T {
+    #[rustc_const_unstable(feature = "const_cell", issue = "131283")]
+    pub const fn get_mut(&mut self) -> &mut T {
         self.value.get_mut()
     }
 
@@ -631,7 +635,8 @@ impl<T: ?Sized> Cell<T> {
     /// ```
     #[inline]
     #[stable(feature = "as_cell", since = "1.37.0")]
-    pub fn from_mut(t: &mut T) -> &Cell<T> {
+    #[rustc_const_unstable(feature = "const_cell", issue = "131283")]
+    pub const fn from_mut(t: &mut T) -> &Cell<T> {
         // SAFETY: `&mut` ensures unique access.
         unsafe { &*(t as *mut T as *const Cell<T>) }
     }
@@ -685,7 +690,8 @@ impl<T> Cell<[T]> {
     /// assert_eq!(slice_cell.len(), 3);
     /// ```
     #[stable(feature = "as_cell", since = "1.37.0")]
-    pub fn as_slice_of_cells(&self) -> &[Cell<T>] {
+    #[rustc_const_unstable(feature = "const_cell", issue = "131283")]
+    pub const fn as_slice_of_cells(&self) -> &[Cell<T>] {
         // SAFETY: `Cell<T>` has the same memory layout as `T`.
         unsafe { &*(self as *const Cell<[T]> as *const [Cell<T>]) }
     }
@@ -705,7 +711,8 @@ impl<T, const N: usize> Cell<[T; N]> {
     /// let array_cell: &[Cell<i32>; 3] = cell_array.as_array_of_cells();
     /// ```
     #[unstable(feature = "as_array_of_cells", issue = "88248")]
-    pub fn as_array_of_cells(&self) -> &[Cell<T>; N] {
+    #[rustc_const_unstable(feature = "as_array_of_cells", issue = "88248")]
+    pub const fn as_array_of_cells(&self) -> &[Cell<T>; N] {
         // SAFETY: `Cell<T>` has the same memory layout as `T`.
         unsafe { &*(self as *const Cell<[T; N]> as *const [Cell<T>; N]) }
     }
@@ -857,7 +864,8 @@ impl<T> RefCell<T> {
     /// let five = c.into_inner();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
+    #[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_allow_const_fn_unstable(const_precise_live_drops)]
     #[inline]
     pub const fn into_inner(self) -> T {
         // Since this function takes `self` (the `RefCell`) by value, the
@@ -1895,11 +1903,17 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
 /// uniqueness guarantee for mutable references is unaffected. There is *no* legal way to obtain
 /// aliasing `&mut`, not even with `UnsafeCell<T>`.
 ///
+/// `UnsafeCell` does nothing to avoid data races; they are still undefined behavior. If multiple
+/// threads have access to the same `UnsafeCell`, they must follow the usual rules of the
+/// [concurrent memory model]: conflicting non-synchronized accesses must be done via the APIs in
+/// [`core::sync::atomic`].
+///
 /// The `UnsafeCell` API itself is technically very simple: [`.get()`] gives you a raw pointer
 /// `*mut T` to its contents. It is up to _you_ as the abstraction designer to use that raw pointer
 /// correctly.
 ///
 /// [`.get()`]: `UnsafeCell::get`
+/// [concurrent memory model]: ../sync/atomic/index.html#memory-model-for-atomic-accesses
 ///
 /// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious:
 ///
@@ -1922,10 +1936,6 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
 /// live memory and the compiler is allowed to insert spurious reads if it can prove that this
 /// memory has not yet been deallocated.
 ///
-/// - At all times, you must avoid data races. If multiple threads have access to
-/// the same `UnsafeCell`, then any writes must have a proper happens-before relation to all other
-/// accesses (or use atomics).
-///
 /// To assist with proper design, the following scenarios are explicitly declared legal
 /// for single-threaded code:
 ///
@@ -2098,8 +2108,8 @@ impl<T> UnsafeCell<T> {
     /// ```
     #[inline(always)]
     #[stable(feature = "rust1", since = "1.0.0")]
-    // When this is const stabilized, please remove `primitive_into_inner` below.
-    #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
+    #[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_allow_const_fn_unstable(const_precise_live_drops)]
     pub const fn into_inner(self) -> T {
         self.value
     }
@@ -2171,7 +2181,8 @@ impl<T: ?Sized> UnsafeCell<T> {
     /// ```
     #[inline(always)]
     #[stable(feature = "unsafe_cell_get_mut", since = "1.50.0")]
-    #[rustc_const_unstable(feature = "const_unsafecell_get_mut", issue = "88836")]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
+    #[rustc_const_stable(feature = "const_unsafecell_get_mut", since = "CURRENT_RUSTC_VERSION")]
     pub const fn get_mut(&mut self) -> &mut T {
         &mut self.value
     }
@@ -2245,47 +2256,6 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {}
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
 impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T> {}
 
-// Special cases of UnsafeCell::into_inner where T is a primitive. These are
-// used by Atomic*::into_inner.
-//
-// The real UnsafeCell::into_inner cannot be used yet in a stable const function.
-// That is blocked on a "precise drop analysis" unstable const feature.
-// https://github.com/rust-lang/rust/issues/73255
-macro_rules! unsafe_cell_primitive_into_inner {
-    ($($primitive:ident $atomic:literal)*) => {
-        $(
-            #[cfg(target_has_atomic_load_store = $atomic)]
-            impl UnsafeCell<$primitive> {
-                pub(crate) const fn primitive_into_inner(self) -> $primitive {
-                    self.value
-                }
-            }
-        )*
-    };
-}
-
-unsafe_cell_primitive_into_inner! {
-    i8 "8"
-    u8 "8"
-    i16 "16"
-    u16 "16"
-    i32 "32"
-    u32 "32"
-    i64 "64"
-    u64 "64"
-    i128 "128"
-    u128 "128"
-    isize "ptr"
-    usize "ptr"
-}
-
-#[cfg(target_has_atomic_load_store = "ptr")]
-impl<T> UnsafeCell<*mut T> {
-    pub(crate) const fn primitive_into_inner(self) -> *mut T {
-        self.value
-    }
-}
-
 /// [`UnsafeCell`], but [`Sync`].
 ///
 /// This is just an `UnsafeCell`, except it implements `Sync`
diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs
index 87df8a4e272..14c587e0c48 100644
--- a/library/core/src/cell/once.rs
+++ b/library/core/src/cell/once.rs
@@ -309,7 +309,8 @@ impl<T> OnceCell<T> {
     /// ```
     #[inline]
     #[stable(feature = "once_cell", since = "1.70.0")]
-    #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
+    #[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_allow_const_fn_unstable(const_precise_live_drops)]
     pub const fn into_inner(self) -> Option<T> {
         // Because `into_inner` takes `self` by value, the compiler statically verifies
         // that it is not currently borrowed. So it is safe to move out `Option<T>`.
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 55e67e5c255..7f3c998aaa5 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -69,7 +69,7 @@ impl char {
     /// assert_eq!(char::from_u32(value_at_max + 1), None);
     /// ```
     #[stable(feature = "assoc_char_consts", since = "1.52.0")]
-    pub const MAX: char = '\u{10ffff}';
+    pub const MAX: char = '\u{10FFFF}';
 
     /// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a
     /// decoding error.
@@ -1841,7 +1841,6 @@ pub const fn encode_utf16_raw(mut code: u32, dst: &mut [u16]) -> &mut [u16] {
         }
         (2, [a, b, ..]) => {
             code -= 0x1_0000;
-
             *a = (code >> 10) as u16 | 0xD800;
             *b = (code & 0x3FF) as u16 | 0xDC00;
         }
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 818a36002e7..4377b4993b8 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -275,49 +275,56 @@ pub macro PartialEq($item:item) {
 /// Trait for comparisons corresponding to [equivalence relations](
 /// https://en.wikipedia.org/wiki/Equivalence_relation).
 ///
-/// This means, that in addition to `a == b` and `a != b` being strict inverses,
-/// the relation must be (for all `a`, `b` and `c`):
+/// The primary difference to [`PartialEq`] is the additional requirement for reflexivity. A type
+/// that implements [`PartialEq`] guarantees that for all `a`, `b` and `c`:
 ///
-/// - reflexive: `a == a`;
-/// - symmetric: `a == b` implies `b == a` (required by `PartialEq` as well); and
-/// - transitive: `a == b` and `b == c` implies `a == c` (required by `PartialEq` as well).
+/// - symmetric: `a == b` implies `b == a` and `a != b` implies `!(a == b)`
+/// - transitive: `a == b` and `b == c` implies `a == c`
 ///
-/// This property cannot be checked by the compiler, and therefore `Eq` implies
-/// [`PartialEq`], and has no extra methods.
+/// `Eq`, which builds on top of [`PartialEq`] also implies:
+///
+/// - reflexive: `a == a`
+///
+/// This property cannot be checked by the compiler, and therefore `Eq` is a trait without methods.
 ///
 /// Violating this property is a logic error. The behavior resulting from a logic error is not
 /// specified, but users of the trait must ensure that such logic errors do *not* result in
 /// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
 /// methods.
 ///
-/// Implement `Eq` in addition to `PartialEq` if it's guaranteed that
-/// `PartialEq::eq(a, a)` always returns `true` (reflexivity), in addition to
-/// the symmetric and transitive properties already required by `PartialEq`.
+/// Floating point types such as [`f32`] and [`f64`] implement only [`PartialEq`] but *not* `Eq`
+/// because `NaN` != `NaN`.
 ///
 /// ## Derivable
 ///
-/// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has
-/// no extra methods, it is only informing the compiler that this is an
-/// equivalence relation rather than a partial equivalence relation. Note that
-/// the `derive` strategy requires all fields are `Eq`, which isn't
+/// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has no extra methods, it
+/// is only informing the compiler that this is an equivalence relation rather than a partial
+/// equivalence relation. Note that the `derive` strategy requires all fields are `Eq`, which isn't
 /// always desired.
 ///
 /// ## How can I implement `Eq`?
 ///
-/// If you cannot use the `derive` strategy, specify that your type implements
-/// `Eq`, which has no methods:
+/// If you cannot use the `derive` strategy, specify that your type implements `Eq`, which has no
+/// extra methods:
 ///
 /// ```
-/// enum BookFormat { Paperback, Hardback, Ebook }
+/// enum BookFormat {
+///     Paperback,
+///     Hardback,
+///     Ebook,
+/// }
+///
 /// struct Book {
 ///     isbn: i32,
 ///     format: BookFormat,
 /// }
+///
 /// impl PartialEq for Book {
 ///     fn eq(&self, other: &Self) -> bool {
 ///         self.isbn == other.isbn
 ///     }
 /// }
+///
 /// impl Eq for Book {}
 /// ```
 #[doc(alias = "==")]
@@ -325,11 +332,9 @@ pub macro PartialEq($item:item) {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "Eq"]
 pub trait Eq: PartialEq<Self> {
-    // this method is used solely by #[derive(Eq)] to assert
-    // that every component of a type implements `Eq`
-    // itself. The current deriving infrastructure means doing this
-    // assertion without using a method on this trait is nearly
-    // impossible.
+    // this method is used solely by `impl Eq or #[derive(Eq)]` to assert that every component of a
+    // type implements `Eq` itself. The current deriving infrastructure means doing this assertion
+    // without using a method on this trait is nearly impossible.
     //
     // This should never be implemented by hand.
     #[doc(hidden)]
@@ -693,17 +698,14 @@ impl<T: Clone> Clone for Reverse<T> {
 
 /// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order).
 ///
-/// Implementations must be consistent with the [`PartialOrd`] implementation, and ensure
-/// `max`, `min`, and `clamp` are consistent with `cmp`:
+/// Implementations must be consistent with the [`PartialOrd`] implementation, and ensure `max`,
+/// `min`, and `clamp` are consistent with `cmp`:
 ///
 /// - `partial_cmp(a, b) == Some(cmp(a, b))`.
 /// - `max(a, b) == max_by(a, b, cmp)` (ensured by the default implementation).
 /// - `min(a, b) == min_by(a, b, cmp)` (ensured by the default implementation).
-/// - For `a.clamp(min, max)`, see the [method docs](#method.clamp)
-///   (ensured by the default implementation).
-///
-/// It's easy to accidentally make `cmp` and `partial_cmp` disagree by
-/// deriving some of the traits and manually implementing others.
+/// - For `a.clamp(min, max)`, see the [method docs](#method.clamp) (ensured by the default
+///   implementation).
 ///
 /// Violating these requirements is a logic error. The behavior resulting from a logic error is not
 /// specified, but users of the trait must ensure that such logic errors do *not* result in
@@ -712,15 +714,14 @@ impl<T: Clone> Clone for Reverse<T> {
 ///
 /// ## Corollaries
 ///
-/// From the above and the requirements of `PartialOrd`, it follows that for
-/// all `a`, `b` and `c`:
+/// From the above and the requirements of `PartialOrd`, it follows that for all `a`, `b` and `c`:
 ///
 /// - exactly one of `a < b`, `a == b` or `a > b` is true; and
-/// - `<` is transitive: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
+/// - `<` is transitive: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and
+///   `>`.
 ///
-/// Mathematically speaking, the `<` operator defines a strict [weak order]. In
-/// cases where `==` conforms to mathematical equality, it also defines a
-/// strict [total order].
+/// Mathematically speaking, the `<` operator defines a strict [weak order]. In cases where `==`
+/// conforms to mathematical equality, it also defines a strict [total order].
 ///
 /// [weak order]: https://en.wikipedia.org/wiki/Weak_ordering
 /// [total order]: https://en.wikipedia.org/wiki/Total_order
@@ -730,13 +731,12 @@ impl<T: Clone> Clone for Reverse<T> {
 /// This trait can be used with `#[derive]`.
 ///
 /// When `derive`d on structs, it will produce a
-/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering
-/// based on the top-to-bottom declaration order of the struct's members.
+/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering based on the
+/// top-to-bottom declaration order of the struct's members.
 ///
-/// When `derive`d on enums, variants are ordered primarily by their discriminants.
-/// Secondarily, they are ordered by their fields.
-/// By default, the discriminant is smallest for variants at the top, and
-/// largest for variants at the bottom. Here's an example:
+/// When `derive`d on enums, variants are ordered primarily by their discriminants. Secondarily,
+/// they are ordered by their fields. By default, the discriminant is smallest for variants at the
+/// top, and largest for variants at the bottom. Here's an example:
 ///
 /// ```
 /// #[derive(PartialEq, Eq, PartialOrd, Ord)]
@@ -748,8 +748,7 @@ impl<T: Clone> Clone for Reverse<T> {
 /// assert!(E::Top < E::Bottom);
 /// ```
 ///
-/// However, manually setting the discriminants can override this default
-/// behavior:
+/// However, manually setting the discriminants can override this default behavior:
 ///
 /// ```
 /// #[derive(PartialEq, Eq, PartialOrd, Ord)]
@@ -765,51 +764,178 @@ impl<T: Clone> Clone for Reverse<T> {
 ///
 /// Lexicographical comparison is an operation with the following properties:
 ///  - Two sequences are compared element by element.
-///  - The first mismatching element defines which sequence is lexicographically less or greater than the other.
-///  - If one sequence is a prefix of another, the shorter sequence is lexicographically less than the other.
-///  - If two sequences have equivalent elements and are of the same length, then the sequences are lexicographically equal.
+///  - The first mismatching element defines which sequence is lexicographically less or greater
+///    than the other.
+///  - If one sequence is a prefix of another, the shorter sequence is lexicographically less than
+///    the other.
+///  - If two sequences have equivalent elements and are of the same length, then the sequences are
+///    lexicographically equal.
 ///  - An empty sequence is lexicographically less than any non-empty sequence.
 ///  - Two empty sequences are lexicographically equal.
 ///
 /// ## How can I implement `Ord`?
 ///
-/// `Ord` requires that the type also be [`PartialOrd`] and [`Eq`] (which requires [`PartialEq`]).
+/// `Ord` requires that the type also be [`PartialOrd`], [`PartialEq`], and [`Eq`].
 ///
-/// Then you must define an implementation for [`cmp`]. You may find it useful to use
-/// [`cmp`] on your type's fields.
+/// Because `Ord` implies a stronger ordering relationship than [`PartialOrd`], and both `Ord` and
+/// [`PartialOrd`] must agree, you must choose how to implement `Ord` **first**. You can choose to
+/// derive it, or implement it manually. If you derive it, you should derive all four traits. If you
+/// implement it manually, you should manually implement all four traits, based on the
+/// implementation of `Ord`.
 ///
-/// Here's an example where you want to sort people by height only, disregarding `id`
-/// and `name`:
+/// Here's an example where you want to define the `Character` comparison by `health` and
+/// `experience` only, disregarding the field `mana`:
 ///
 /// ```
 /// use std::cmp::Ordering;
 ///
-/// #[derive(Eq)]
-/// struct Person {
-///     id: u32,
-///     name: String,
-///     height: u32,
+/// struct Character {
+///     health: u32,
+///     experience: u32,
+///     mana: f32,
 /// }
 ///
-/// impl Ord for Person {
-///     fn cmp(&self, other: &Self) -> Ordering {
-///         self.height.cmp(&other.height)
+/// impl Ord for Character {
+///     fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+///         self.experience
+///             .cmp(&other.experience)
+///             .then(self.health.cmp(&other.health))
 ///     }
 /// }
 ///
-/// impl PartialOrd for Person {
+/// impl PartialOrd for Character {
 ///     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
 ///         Some(self.cmp(other))
 ///     }
 /// }
 ///
-/// impl PartialEq for Person {
+/// impl PartialEq for Character {
 ///     fn eq(&self, other: &Self) -> bool {
-///         self.height == other.height
+///         self.health == other.health && self.experience == other.experience
+///     }
+/// }
+///
+/// impl Eq for Character {}
+/// ```
+///
+/// If all you need is to `slice::sort` a type by a field value, it can be simpler to use
+/// `slice::sort_by_key`.
+///
+/// ## Examples of incorrect `Ord` implementations
+///
+/// ```
+/// use std::cmp::Ordering;
+///
+/// #[derive(Debug)]
+/// struct Character {
+///     health: f32,
+/// }
+///
+/// impl Ord for Character {
+///     fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+///         if self.health < other.health {
+///             Ordering::Less
+///         } else if self.health > other.health {
+///             Ordering::Greater
+///         } else {
+///             Ordering::Equal
+///         }
+///     }
+/// }
+///
+/// impl PartialOrd for Character {
+///     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+///         Some(self.cmp(other))
+///     }
+/// }
+///
+/// impl PartialEq for Character {
+///     fn eq(&self, other: &Self) -> bool {
+///         self.health == other.health
+///     }
+/// }
+///
+/// impl Eq for Character {}
+///
+/// let a = Character { health: 4.5 };
+/// let b = Character { health: f32::NAN };
+///
+/// // Mistake: floating-point values do not form a total order and using the built-in comparison
+/// // operands to implement `Ord` irregardless of that reality does not change it. Use
+/// // `f32::total_cmp` if you need a total order for floating-point values.
+///
+/// // Reflexivity requirement of `Ord` is not given.
+/// assert!(a == a);
+/// assert!(b != b);
+///
+/// // Antisymmetry requirement of `Ord` is not given. Only one of a < c and c < a is allowed to be
+/// // true, not both or neither.
+/// assert_eq!((a < b) as u8 + (b < a) as u8, 0);
+/// ```
+///
+/// ```
+/// use std::cmp::Ordering;
+///
+/// #[derive(Debug)]
+/// struct Character {
+///     health: u32,
+///     experience: u32,
+/// }
+///
+/// impl PartialOrd for Character {
+///     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+///         Some(self.cmp(other))
+///     }
+/// }
+///
+/// impl Ord for Character {
+///     fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+///         if self.health < 50 {
+///             self.health.cmp(&other.health)
+///         } else {
+///             self.experience.cmp(&other.experience)
+///         }
+///     }
+/// }
+///
+/// // For performance reasons implementing `PartialEq` this way is not the idiomatic way, but it
+/// // ensures consistent behavior between `PartialEq`, `PartialOrd` and `Ord` in this example.
+/// impl PartialEq for Character {
+///     fn eq(&self, other: &Self) -> bool {
+///         self.cmp(other) == Ordering::Equal
 ///     }
 /// }
+///
+/// impl Eq for Character {}
+///
+/// let a = Character {
+///     health: 3,
+///     experience: 5,
+/// };
+/// let b = Character {
+///     health: 10,
+///     experience: 77,
+/// };
+/// let c = Character {
+///     health: 143,
+///     experience: 2,
+/// };
+///
+/// // Mistake: The implementation of `Ord` compares different fields depending on the value of
+/// // `self.health`, the resulting order is not total.
+///
+/// // Transitivity requirement of `Ord` is not given. If a is smaller than b and b is smaller than
+/// // c, by transitive property a must also be smaller than c.
+/// assert!(a < b && b < c && c < a);
+///
+/// // Antisymmetry requirement of `Ord` is not given. Only one of a < c and c < a is allowed to be
+/// // true, not both or neither.
+/// assert_eq!((a < c) as u8 + (c < a) as u8, 2);
 /// ```
 ///
+/// The documentation of [`PartialOrd`] contains further examples, for example it's wrong for
+/// [`PartialOrd`] and [`PartialEq`] to disagree.
+///
 /// [`cmp`]: Ord::cmp
 #[doc(alias = "<")]
 #[doc(alias = ">")]
@@ -924,8 +1050,12 @@ pub macro Ord($item:item) {
 
 /// Trait for types that form a [partial order](https://en.wikipedia.org/wiki/Partial_order).
 ///
-/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using
-/// the `<`, `<=`, `>`, and `>=` operators, respectively.
+/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using the `<`, `<=`, `>`, and
+/// `>=` operators, respectively.
+///
+/// This trait should **only** contain the comparison logic for a type **if one plans on only
+/// implementing `PartialOrd` but not [`Ord`]**. Otherwise the comparison logic should be in [`Ord`]
+/// and this trait implemented with `Some(self.cmp(other))`.
 ///
 /// The methods of this trait must be consistent with each other and with those of [`PartialEq`].
 /// The following conditions must hold:
@@ -937,26 +1067,25 @@ pub macro Ord($item:item) {
 /// 5. `a >= b` if and only if `a > b || a == b`
 /// 6. `a != b` if and only if `!(a == b)`.
 ///
-/// Conditions 2–5 above are ensured by the default implementation.
-/// Condition 6 is already ensured by [`PartialEq`].
+/// Conditions 2–5 above are ensured by the default implementation. Condition 6 is already ensured
+/// by [`PartialEq`].
 ///
 /// If [`Ord`] is also implemented for `Self` and `Rhs`, it must also be consistent with
-/// `partial_cmp` (see the documentation of that trait for the exact requirements). It's
-/// easy to accidentally make them disagree by deriving some of the traits and manually
-/// implementing others.
+/// `partial_cmp` (see the documentation of that trait for the exact requirements). It's easy to
+/// accidentally make them disagree by deriving some of the traits and manually implementing others.
 ///
-/// The comparison relations must satisfy the following conditions
-/// (for all `a`, `b`, `c` of type `A`, `B`, `C`):
+/// The comparison relations must satisfy the following conditions (for all `a`, `b`, `c` of type
+/// `A`, `B`, `C`):
 ///
-/// - **Transitivity**: if `A: PartialOrd<B>` and `B: PartialOrd<C>` and `A:
-///   PartialOrd<C>`, then `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
-///   This must also work for longer chains, such as when `A: PartialOrd<B>`, `B: PartialOrd<C>`,
-///   `C: PartialOrd<D>`, and `A: PartialOrd<D>` all exist.
-/// - **Duality**: if `A: PartialOrd<B>` and `B: PartialOrd<A>`, then `a < b` if and only if `b > a`.
+/// - **Transitivity**: if `A: PartialOrd<B>` and `B: PartialOrd<C>` and `A: PartialOrd<C>`, then `a
+///   < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. This must also
+///   work for longer chains, such as when `A: PartialOrd<B>`, `B: PartialOrd<C>`, `C:
+///   PartialOrd<D>`, and `A: PartialOrd<D>` all exist.
+/// - **Duality**: if `A: PartialOrd<B>` and `B: PartialOrd<A>`, then `a < b` if and only if `b >
+///   a`.
 ///
-/// Note that the `B: PartialOrd<A>` (dual) and `A: PartialOrd<C>`
-/// (transitive) impls are not forced to exist, but these requirements apply
-/// whenever they do exist.
+/// Note that the `B: PartialOrd<A>` (dual) and `A: PartialOrd<C>` (transitive) impls are not forced
+/// to exist, but these requirements apply whenever they do exist.
 ///
 /// Violating these requirements is a logic error. The behavior resulting from a logic error is not
 /// specified, but users of the trait must ensure that such logic errors do *not* result in
@@ -992,12 +1121,10 @@ pub macro Ord($item:item) {
 ///
 /// ## Strict and non-strict partial orders
 ///
-/// The `<` and `>` operators behave according to a *strict* partial order.
-/// However, `<=` and `>=` do **not** behave according to a *non-strict*
-/// partial order.
-/// That is because mathematically, a non-strict partial order would require
-/// reflexivity, i.e. `a <= a` would need to be true for every `a`. This isn't
-/// always the case for types that implement `PartialOrd`, for example:
+/// The `<` and `>` operators behave according to a *strict* partial order. However, `<=` and `>=`
+/// do **not** behave according to a *non-strict* partial order. That is because mathematically, a
+/// non-strict partial order would require reflexivity, i.e. `a <= a` would need to be true for
+/// every `a`. This isn't always the case for types that implement `PartialOrd`, for example:
 ///
 /// ```
 /// let a = f64::sqrt(-1.0);
@@ -1009,13 +1136,12 @@ pub macro Ord($item:item) {
 /// This trait can be used with `#[derive]`.
 ///
 /// When `derive`d on structs, it will produce a
-/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering
-/// based on the top-to-bottom declaration order of the struct's members.
+/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering based on the
+/// top-to-bottom declaration order of the struct's members.
 ///
-/// When `derive`d on enums, variants are primarily ordered by their discriminants.
-/// Secondarily, they are ordered by their fields.
-/// By default, the discriminant is smallest for variants at the top, and
-/// largest for variants at the bottom. Here's an example:
+/// When `derive`d on enums, variants are primarily ordered by their discriminants. Secondarily,
+/// they are ordered by their fields. By default, the discriminant is smallest for variants at the
+/// top, and largest for variants at the bottom. Here's an example:
 ///
 /// ```
 /// #[derive(PartialEq, PartialOrd)]
@@ -1027,8 +1153,7 @@ pub macro Ord($item:item) {
 /// assert!(E::Top < E::Bottom);
 /// ```
 ///
-/// However, manually setting the discriminants can override this default
-/// behavior:
+/// However, manually setting the discriminants can override this default behavior:
 ///
 /// ```
 /// #[derive(PartialEq, PartialOrd)]
@@ -1046,8 +1171,8 @@ pub macro Ord($item:item) {
 /// generated from default implementations.
 ///
 /// However it remains possible to implement the others separately for types which do not have a
-/// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 ==
-/// false` (cf. IEEE 754-2008 section 5.11).
+/// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 == false`
+/// (cf. IEEE 754-2008 section 5.11).
 ///
 /// `PartialOrd` requires your type to be [`PartialEq`].
 ///
@@ -1056,7 +1181,6 @@ pub macro Ord($item:item) {
 /// ```
 /// use std::cmp::Ordering;
 ///
-/// #[derive(Eq)]
 /// struct Person {
 ///     id: u32,
 ///     name: String,
@@ -1080,11 +1204,13 @@ pub macro Ord($item:item) {
 ///         self.height == other.height
 ///     }
 /// }
+///
+/// impl Eq for Person {}
 /// ```
 ///
-/// You may also find it useful to use [`partial_cmp`] on your type's fields. Here
-/// is an example of `Person` types who have a floating-point `height` field that
-/// is the only field to be used for sorting:
+/// You may also find it useful to use [`partial_cmp`] on your type's fields. Here is an example of
+/// `Person` types who have a floating-point `height` field that is the only field to be used for
+/// sorting:
 ///
 /// ```
 /// use std::cmp::Ordering;
@@ -1108,6 +1234,38 @@ pub macro Ord($item:item) {
 /// }
 /// ```
 ///
+/// ## Examples of incorrect `PartialOrd` implementations
+///
+/// ```
+/// use std::cmp::Ordering;
+///
+/// #[derive(PartialEq, Debug)]
+/// struct Character {
+///     health: u32,
+///     experience: u32,
+/// }
+///
+/// impl PartialOrd for Character {
+///     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+///         Some(self.health.cmp(&other.health))
+///     }
+/// }
+///
+/// let a = Character {
+///     health: 10,
+///     experience: 5,
+/// };
+/// let b = Character {
+///     health: 10,
+///     experience: 77,
+/// };
+///
+/// // Mistake: `PartialEq` and `PartialOrd` disagree with each other.
+///
+/// assert_eq!(a.partial_cmp(&b).unwrap(), Ordering::Equal); // a == b according to `PartialOrd`.
+/// assert_ne!(a, b); // a != b according to `PartialEq`.
+/// ```
+///
 /// # Examples
 ///
 /// ```
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index e7726da8d91..aecd725eca5 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -208,75 +208,119 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\
       8081828384858687888990919293949596979899";
 
 macro_rules! impl_Display {
-    ($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
-        #[cfg(not(feature = "optimize_for_size"))]
-        fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            // 2^128 is about 3*10^38, so 39 gives an extra byte of space
-            let mut buf = [MaybeUninit::<u8>::uninit(); 39];
-            let mut curr = buf.len();
-            let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
-            let lut_ptr = DEC_DIGITS_LUT.as_ptr();
+    ($($t:ident $(as $positive:ident)? named $name:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => {
 
-            // SAFETY: Since `d1` and `d2` are always less than or equal to `198`, we
-            // can copy from `lut_ptr[d1..d1 + 1]` and `lut_ptr[d2..d2 + 1]`. To show
-            // that it's OK to copy into `buf_ptr`, notice that at the beginning
-            // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at
-            // each step this is kept the same as `n` is divided. Since `n` is always
-            // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]`
-            // is safe to access.
-            unsafe {
-                // need at least 16 bits for the 4-characters-at-a-time to work.
-                assert!(crate::mem::size_of::<$u>() >= 2);
+        $(
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl fmt::Display for $t {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                // If it's a signed integer.
+                $(
+                    let is_nonnegative = *self >= 0;
 
-                // eagerly decode 4 characters at a time
-                while n >= 10000 {
-                    let rem = (n % 10000) as usize;
-                    n /= 10000;
+                    #[cfg(not(feature = "optimize_for_size"))]
+                    {
+                        if !is_nonnegative {
+                            // convert the negative num to positive by summing 1 to its 2s complement
+                            return (!self as $positive).wrapping_add(1)._fmt(false, f);
+                        }
+                    }
+                    #[cfg(feature = "optimize_for_size")]
+                    {
+                        if !is_nonnegative {
+                            // convert the negative num to positive by summing 1 to its 2s complement
+                            return $gen_name((!self.$conv_fn()).wrapping_add(1), false, f);
+                        }
+                    }
+                )?
+                // If it's a positive integer.
+                #[cfg(not(feature = "optimize_for_size"))]
+                {
+                    self._fmt(true, f)
+                }
+                #[cfg(feature = "optimize_for_size")]
+                {
+                    $gen_name(self.$conv_fn(), true, f)
+                }
+            }
+        }
 
-                    let d1 = (rem / 100) << 1;
-                    let d2 = (rem % 100) << 1;
-                    curr -= 4;
+        #[cfg(not(feature = "optimize_for_size"))]
+        impl $t {
+            fn _fmt(mut self: $t, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                const SIZE: usize = $t::MAX.ilog(10) as usize + 1;
+                let mut buf = [MaybeUninit::<u8>::uninit(); SIZE];
+                let mut curr = SIZE;
+                let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
+                let lut_ptr = DEC_DIGITS_LUT.as_ptr();
+
+                // SAFETY: Since `d1` and `d2` are always less than or equal to `198`, we
+                // can copy from `lut_ptr[d1..d1 + 1]` and `lut_ptr[d2..d2 + 1]`. To show
+                // that it's OK to copy into `buf_ptr`, notice that at the beginning
+                // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at
+                // each step this is kept the same as `n` is divided. Since `n` is always
+                // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]`
+                // is safe to access.
+                unsafe {
+                    // need at least 16 bits for the 4-characters-at-a-time to work.
+                    #[allow(overflowing_literals)]
+                    #[allow(unused_comparisons)]
+                    // This block will be removed for smaller types at compile time and in the worst
+                    // case, it will prevent to have the `10000` literal to overflow for `i8` and `u8`.
+                    if core::mem::size_of::<$t>() >= 2 {
+                        // eagerly decode 4 characters at a time
+                        while self >= 10000 {
+                            let rem = (self % 10000) as usize;
+                            self /= 10000;
+
+                            let d1 = (rem / 100) << 1;
+                            let d2 = (rem % 100) << 1;
+                            curr -= 4;
+
+                            // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since
+                            // otherwise `curr < 0`. But then `n` was originally at least `10000^10`
+                            // which is `10^40 > 2^128 > n`.
+                            ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(curr), 2);
+                            ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(curr + 2), 2);
+                        }
+                    }
 
-                    // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since
-                    // otherwise `curr < 0`. But then `n` was originally at least `10000^10`
-                    // which is `10^40 > 2^128 > n`.
-                    ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
-                    ptr::copy_nonoverlapping(lut_ptr.add(d2), buf_ptr.add(curr + 2), 2);
-                }
+                    // if we reach here numbers are <= 9999, so at most 4 chars long
+                    let mut n = self as usize; // possibly reduce 64bit math
 
-                // if we reach here numbers are <= 9999, so at most 4 chars long
-                let mut n = n as usize; // possibly reduce 64bit math
+                    // decode 2 more chars, if > 2 chars
+                    if n >= 100 {
+                        let d1 = (n % 100) << 1;
+                        n /= 100;
+                        curr -= 2;
+                        ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
+                    }
 
-                // decode 2 more chars, if > 2 chars
-                if n >= 100 {
-                    let d1 = (n % 100) << 1;
-                    n /= 100;
-                    curr -= 2;
-                    ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
+                    // if we reach here numbers are <= 100, so at most 2 chars long
+                    // The biggest it can be is 99, and 99 << 1 == 198, so a `u8` is enough.
+                    // decode last 1 or 2 chars
+                    if n < 10 {
+                        curr -= 1;
+                        *buf_ptr.add(curr) = (n as u8) + b'0';
+                    } else {
+                        let d1 = n << 1;
+                        curr -= 2;
+                        ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
+                    }
                 }
 
-                // decode last 1 or 2 chars
-                if n < 10 {
-                    curr -= 1;
-                    *buf_ptr.add(curr) = (n as u8) + b'0';
-                } else {
-                    let d1 = n << 1;
-                    curr -= 2;
-                    ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
-                }
+                // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid
+                // UTF-8 since `DEC_DIGITS_LUT` is
+                let buf_slice = unsafe {
+                    str::from_utf8_unchecked(
+                        slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr))
+                };
+                f.pad_integral(is_nonnegative, "", buf_slice)
             }
-
-            // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid
-            // UTF-8 since `DEC_DIGITS_LUT` is
-            let buf_slice = unsafe {
-                str::from_utf8_unchecked(
-                    slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr))
-            };
-            f.pad_integral(is_nonnegative, "", buf_slice)
-        }
+        })*
 
         #[cfg(feature = "optimize_for_size")]
-        fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fn $gen_name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             // 2^128 is about 3*10^38, so 39 gives an extra byte of space
             let mut buf = [MaybeUninit::<u8>::uninit(); 39];
             let mut curr = buf.len();
@@ -306,21 +350,6 @@ macro_rules! impl_Display {
             };
             f.pad_integral(is_nonnegative, "", buf_slice)
         }
-
-        $(#[stable(feature = "rust1", since = "1.0.0")]
-        impl fmt::Display for $t {
-            #[allow(unused_comparisons)]
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                let is_nonnegative = *self >= 0;
-                let n = if is_nonnegative {
-                    self.$conv_fn()
-                } else {
-                    // convert the negative num to positive by summing 1 to it's 2 complement
-                    (!self.$conv_fn()).wrapping_add(1)
-                };
-                $name(n, is_nonnegative, f)
-            }
-        })*
     };
 }
 
@@ -374,7 +403,6 @@ macro_rules! impl_Exp {
                 (n, exponent, exponent, added_precision)
             };
 
-            // 39 digits (worst case u128) + . = 40
             // Since `curr` always decreases by the number of digits copied, this means
             // that `curr >= 0`.
             let mut buf = [MaybeUninit::<u8>::uninit(); 40];
@@ -469,7 +497,7 @@ macro_rules! impl_Exp {
                     let n = if is_nonnegative {
                         self.$conv_fn()
                     } else {
-                        // convert the negative num to positive by summing 1 to it's 2 complement
+                        // convert the negative num to positive by summing 1 to its 2s complement
                         (!self.$conv_fn()).wrapping_add(1)
                     };
                     $name(n, is_nonnegative, false, f)
@@ -484,7 +512,7 @@ macro_rules! impl_Exp {
                     let n = if is_nonnegative {
                         self.$conv_fn()
                     } else {
-                        // convert the negative num to positive by summing 1 to it's 2 complement
+                        // convert the negative num to positive by summing 1 to its 2s complement
                         (!self.$conv_fn()).wrapping_add(1)
                     };
                     $name(n, is_nonnegative, true, f)
@@ -499,8 +527,17 @@ macro_rules! impl_Exp {
 mod imp {
     use super::*;
     impl_Display!(
-        i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
-            as u64 via to_u64 named fmt_u64
+        i8 as u8 named fmt_i8,
+        u8 named fmt_u8,
+        i16 as u16  named fmt_i16,
+        u16 named fmt_u16,
+        i32 as u32 named fmt_i32,
+        u32 named fmt_u32,
+        i64 as u64 named fmt_i64,
+        u64 named fmt_u64,
+        isize as usize named fmt_isize,
+        usize named fmt_usize,
+        ; as u64 via to_u64 named fmt_u64
     );
     impl_Exp!(
         i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
@@ -511,8 +548,21 @@ mod imp {
 #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
 mod imp {
     use super::*;
-    impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named fmt_u32);
-    impl_Display!(i64, u64 as u64 via to_u64 named fmt_u64);
+    impl_Display!(
+        i8 as u8 named fmt_i8,
+        u8 named fmt_u8,
+        i16 as u16  named fmt_i16,
+        u16 named fmt_u16,
+        i32 as u32 named fmt_i32,
+        u32 named fmt_u32,
+        isize as usize named fmt_isize,
+        usize named fmt_usize,
+        ; as u32 via to_u32 named fmt_u32);
+    impl_Display!(
+        i64 as u64 named fmt_i64,
+        u64 named fmt_u64,
+        ; as u64 via to_u64 named fmt_u64);
+
     impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32);
     impl_Exp!(i64, u64 as u64 via to_u64 named exp_u64);
 }
@@ -619,7 +669,7 @@ impl fmt::Display for i128 {
         let n = if is_nonnegative {
             self.to_u128()
         } else {
-            // convert the negative num to positive by summing 1 to it's 2 complement
+            // convert the negative num to positive by summing 1 to its 2s complement
             (!self.to_u128()).wrapping_add(1)
         };
         fmt_u128(n, is_nonnegative, f)
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 881a89f4d10..d7a2f1909ca 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1425,8 +1425,7 @@ extern "rust-intrinsic" {
     ///
     /// If the computed offset is non-zero, then both the starting and resulting pointer must be
     /// either in bounds or at the end of an allocated object. If either pointer is out
-    /// of bounds or arithmetic overflow occurs then any further use of the returned value will
-    /// result in undefined behavior.
+    /// of bounds or arithmetic overflow occurs then this operation is undefined behavior.
     ///
     /// The stabilized version of this intrinsic is [`pointer::offset`].
     #[must_use = "returns a new pointer rather than modifying its argument"]
@@ -2659,12 +2658,17 @@ extern "rust-intrinsic" {
     ///
     /// `catch_fn` must not unwind.
     ///
-    /// The third argument is a function called if an unwind occurs (both Rust unwinds and foreign
-    /// unwinds). This function takes the data pointer and a pointer to the target-specific
-    /// exception object that was caught. For more information, see the compiler's source as well as
-    /// std's `catch_unwind` implementation.
+    /// The third argument is a function called if an unwind occurs (both Rust `panic` and foreign
+    /// unwinds). This function takes the data pointer and a pointer to the target- and
+    /// runtime-specific exception object that was caught.
     ///
-    /// The stable version of this intrinsic is `std::panic::catch_unwind`.
+    /// Note that in the case of a foreign unwinding operation, the exception object data may not be
+    /// safely usable from Rust, and should not be directly exposed via the standard library. To
+    /// prevent unsafe access, the library implementation may either abort the process or present an
+    /// opaque error type to the user.
+    ///
+    /// For more information, see the compiler's source, as well as the documentation for the stable
+    /// version of this intrinsic, `std::panic::catch_unwind`.
     #[rustc_nounwind]
     pub fn catch_unwind(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32;
 
@@ -3160,7 +3164,7 @@ pub const fn type_id<T: ?Sized + 'static>() -> u128 {
 /// change the possible layouts of pointers.
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
-#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
 pub const fn aggregate_raw_ptr<P: AggregateRawPtr<D, Metadata = M>, D, M>(_data: D, _meta: M) -> P {
@@ -3185,7 +3189,7 @@ impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*mut T> for *mut P {
 /// This is used to implement functions like `ptr::metadata`.
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
-#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
 pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *const P) -> M {
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index fb0aa5398a5..a2ab39caade 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -213,7 +213,7 @@
 //!  - All other locals need to be declared with `let` somewhere and then can be accessed by name.
 //!
 //! #### Places
-//!  - Locals implicit convert to places.
+//!  - Locals implicitly convert to places.
 //!  - Field accesses, derefs, and indexing work normally.
 //!  - Fields in variants can be accessed via the [`Variant`] and [`Field`] associated functions,
 //!    see their documentation for details.
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 01cadd78cc0..e323e88f261 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -118,12 +118,10 @@
 #![feature(const_array_into_iter_constructors)]
 #![feature(const_bigint_helper_methods)]
 #![feature(const_black_box)]
-#![feature(const_cell_into_inner)]
 #![feature(const_char_encode_utf16)]
 #![feature(const_char_encode_utf8)]
 #![feature(const_eval_select)]
 #![feature(const_exact_div)]
-#![feature(const_float_classify)]
 #![feature(const_fmt_arguments_new)]
 #![feature(const_hash)]
 #![feature(const_heap)]
@@ -140,7 +138,6 @@
 #![feature(const_option_ext)]
 #![feature(const_pin)]
 #![feature(const_pointer_is_aligned)]
-#![feature(const_ptr_as_ref)]
 #![feature(const_ptr_is_null)]
 #![feature(const_ptr_sub_ptr)]
 #![feature(const_ptr_write)]
@@ -148,11 +145,7 @@
 #![feature(const_replace)]
 #![feature(const_size_of_val)]
 #![feature(const_size_of_val_raw)]
-#![feature(const_slice_from_raw_parts_mut)]
 #![feature(const_slice_from_ref)]
-#![feature(const_slice_split_at_mut)]
-#![feature(const_str_as_mut)]
-#![feature(const_str_from_utf8_unchecked_mut)]
 #![feature(const_strict_overflow_ops)]
 #![feature(const_swap)]
 #![feature(const_try)]
@@ -161,12 +154,9 @@
 #![feature(const_typed_swap)]
 #![feature(const_ub_checks)]
 #![feature(const_unicode_case_lookup)]
-#![feature(const_unsafecell_get_mut)]
 #![feature(coverage_attribute)]
 #![feature(do_not_recommend)]
 #![feature(duration_consts_float)]
-#![feature(f128_const)]
-#![feature(f16_const)]
 #![feature(internal_impls_macro)]
 #![feature(ip)]
 #![feature(is_ascii_octdigit)]
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index 100271fa54c..764df4fe4b0 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -288,7 +288,7 @@ impl f128 {
     // concerns about portability, so this implementation is for
     // private use internally.
     #[inline]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub(crate) const fn abs_private(self) -> f128 {
         // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
         unsafe {
@@ -319,7 +319,7 @@ impl f128 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn is_infinite(self) -> bool {
         (self == f128::INFINITY) | (self == f128::NEG_INFINITY)
     }
@@ -346,7 +346,7 @@ impl f128 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn is_finite(self) -> bool {
         // There's no need to handle NaN separately: if self is NaN,
         // the comparison is not true, exactly as desired.
@@ -380,7 +380,7 @@ impl f128 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn is_subnormal(self) -> bool {
         matches!(self.classify(), FpCategory::Subnormal)
     }
@@ -412,7 +412,7 @@ impl f128 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn is_normal(self) -> bool {
         matches!(self.classify(), FpCategory::Normal)
     }
@@ -437,7 +437,7 @@ impl f128 {
     /// ```
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn classify(self) -> FpCategory {
         let bits = self.to_bits();
         match (bits & Self::MAN_MASK, bits & Self::EXP_MASK) {
@@ -910,7 +910,7 @@ impl f128 {
     /// ```
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128_const", issue = "116909")]
+    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
     pub const fn to_bits(self) -> u128 {
         // SAFETY: `u128` is a plain old datatype so we can always transmute to it.
@@ -959,7 +959,7 @@ impl f128 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128_const", issue = "116909")]
+    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn from_bits(v: u128) -> Self {
         // It turns out the safety issues with sNaN were overblown! Hooray!
         // SAFETY: `u128` is a plain old datatype so we can always transmute from it.
@@ -986,7 +986,7 @@ impl f128 {
     /// ```
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128_const", issue = "116909")]
+    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
     pub const fn to_be_bytes(self) -> [u8; 16] {
         self.to_bits().to_be_bytes()
@@ -1012,7 +1012,7 @@ impl f128 {
     /// ```
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128_const", issue = "116909")]
+    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
     pub const fn to_le_bytes(self) -> [u8; 16] {
         self.to_bits().to_le_bytes()
@@ -1049,7 +1049,7 @@ impl f128 {
     /// ```
     #[inline]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128_const", issue = "116909")]
+    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
     pub const fn to_ne_bytes(self) -> [u8; 16] {
         self.to_bits().to_ne_bytes()
@@ -1077,7 +1077,7 @@ impl f128 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128_const", issue = "116909")]
+    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn from_be_bytes(bytes: [u8; 16]) -> Self {
         Self::from_bits(u128::from_be_bytes(bytes))
     }
@@ -1104,7 +1104,7 @@ impl f128 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128_const", issue = "116909")]
+    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn from_le_bytes(bytes: [u8; 16]) -> Self {
         Self::from_bits(u128::from_le_bytes(bytes))
     }
@@ -1141,7 +1141,7 @@ impl f128 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "f128_const", issue = "116909")]
+    #[rustc_const_unstable(feature = "f128", issue = "116909")]
     pub const fn from_ne_bytes(bytes: [u8; 16]) -> Self {
         Self::from_bits(u128::from_ne_bytes(bytes))
     }
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index 6bdc569df28..897fc8c105d 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -282,7 +282,7 @@ impl f16 {
     // concerns about portability, so this implementation is for
     // private use internally.
     #[inline]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub(crate) const fn abs_private(self) -> f16 {
         // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
         unsafe { mem::transmute::<u16, f16>(mem::transmute::<f16, u16>(self) & !Self::SIGN_MASK) }
@@ -310,7 +310,7 @@ impl f16 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn is_infinite(self) -> bool {
         (self == f16::INFINITY) | (self == f16::NEG_INFINITY)
     }
@@ -336,7 +336,7 @@ impl f16 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn is_finite(self) -> bool {
         // There's no need to handle NaN separately: if self is NaN,
         // the comparison is not true, exactly as desired.
@@ -368,7 +368,7 @@ impl f16 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn is_subnormal(self) -> bool {
         matches!(self.classify(), FpCategory::Subnormal)
     }
@@ -398,7 +398,7 @@ impl f16 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn is_normal(self) -> bool {
         matches!(self.classify(), FpCategory::Normal)
     }
@@ -422,7 +422,7 @@ impl f16 {
     /// ```
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn classify(self) -> FpCategory {
         let b = self.to_bits();
         match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
@@ -896,7 +896,7 @@ impl f16 {
     /// ```
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16_const", issue = "116909")]
+    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
     pub const fn to_bits(self) -> u16 {
         // SAFETY: `u16` is a plain old datatype so we can always transmute to it.
@@ -944,7 +944,7 @@ impl f16 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16_const", issue = "116909")]
+    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn from_bits(v: u16) -> Self {
         // It turns out the safety issues with sNaN were overblown! Hooray!
         // SAFETY: `u16` is a plain old datatype so we can always transmute from it.
@@ -970,7 +970,7 @@ impl f16 {
     /// ```
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16_const", issue = "116909")]
+    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
     pub const fn to_be_bytes(self) -> [u8; 2] {
         self.to_bits().to_be_bytes()
@@ -995,7 +995,7 @@ impl f16 {
     /// ```
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16_const", issue = "116909")]
+    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
     pub const fn to_le_bytes(self) -> [u8; 2] {
         self.to_bits().to_le_bytes()
@@ -1033,7 +1033,7 @@ impl f16 {
     /// ```
     #[inline]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16_const", issue = "116909")]
+    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "this returns the result of the operation, without modifying the original"]
     pub const fn to_ne_bytes(self) -> [u8; 2] {
         self.to_bits().to_ne_bytes()
@@ -1057,7 +1057,7 @@ impl f16 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16_const", issue = "116909")]
+    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn from_be_bytes(bytes: [u8; 2]) -> Self {
         Self::from_bits(u16::from_be_bytes(bytes))
     }
@@ -1080,7 +1080,7 @@ impl f16 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16_const", issue = "116909")]
+    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn from_le_bytes(bytes: [u8; 2]) -> Self {
         Self::from_bits(u16::from_le_bytes(bytes))
     }
@@ -1114,7 +1114,7 @@ impl f16 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "f16_const", issue = "116909")]
+    #[rustc_const_unstable(feature = "f16", issue = "116909")]
     pub const fn from_ne_bytes(bytes: [u8; 2]) -> Self {
         Self::from_bits(u16::from_ne_bytes(bytes))
     }
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index d0eb6bb3f28..a9a2595c25c 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -517,7 +517,7 @@ impl f32 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     #[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :)
     pub const fn is_nan(self) -> bool {
@@ -528,7 +528,6 @@ impl f32 {
     // concerns about portability, so this implementation is for
     // private use internally.
     #[inline]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
     pub(crate) const fn abs_private(self) -> f32 {
         // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
         unsafe { mem::transmute::<u32, f32>(mem::transmute::<f32, u32>(self) & !Self::SIGN_MASK) }
@@ -551,7 +550,7 @@ impl f32 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn is_infinite(self) -> bool {
         // Getting clever with transmutation can result in incorrect answers on some FPUs
@@ -576,7 +575,7 @@ impl f32 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn is_finite(self) -> bool {
         // There's no need to handle NaN separately: if self is NaN,
@@ -604,7 +603,7 @@ impl f32 {
     /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
     #[must_use]
     #[stable(feature = "is_subnormal", since = "1.53.0")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn is_subnormal(self) -> bool {
         matches!(self.classify(), FpCategory::Subnormal)
@@ -631,7 +630,7 @@ impl f32 {
     /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn is_normal(self) -> bool {
         matches!(self.classify(), FpCategory::Normal)
@@ -651,7 +650,7 @@ impl f32 {
     /// assert_eq!(inf.classify(), FpCategory::Infinite);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
     pub const fn classify(self) -> FpCategory {
         // We used to have complicated logic here that avoids the simple bit-based tests to work
         // around buggy codegen for x87 targets (see
@@ -687,7 +686,7 @@ impl f32 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn is_sign_positive(self) -> bool {
         !self.is_sign_negative()
@@ -712,7 +711,7 @@ impl f32 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn is_sign_negative(self) -> bool {
         // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 4bc275ad147..aa7a54ca650 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -516,7 +516,7 @@ impl f64 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     #[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :)
     pub const fn is_nan(self) -> bool {
@@ -527,7 +527,6 @@ impl f64 {
     // concerns about portability, so this implementation is for
     // private use internally.
     #[inline]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
     pub(crate) const fn abs_private(self) -> f64 {
         // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
         unsafe { mem::transmute::<u64, f64>(mem::transmute::<f64, u64>(self) & !Self::SIGN_MASK) }
@@ -550,7 +549,7 @@ impl f64 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn is_infinite(self) -> bool {
         // Getting clever with transmutation can result in incorrect answers on some FPUs
@@ -575,7 +574,7 @@ impl f64 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn is_finite(self) -> bool {
         // There's no need to handle NaN separately: if self is NaN,
@@ -603,7 +602,7 @@ impl f64 {
     /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
     #[must_use]
     #[stable(feature = "is_subnormal", since = "1.53.0")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn is_subnormal(self) -> bool {
         matches!(self.classify(), FpCategory::Subnormal)
@@ -630,7 +629,7 @@ impl f64 {
     /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn is_normal(self) -> bool {
         matches!(self.classify(), FpCategory::Normal)
@@ -650,7 +649,7 @@ impl f64 {
     /// assert_eq!(inf.classify(), FpCategory::Infinite);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
     pub const fn classify(self) -> FpCategory {
         // We used to have complicated logic here that avoids the simple bit-based tests to work
         // around buggy codegen for x87 targets (see
@@ -686,7 +685,7 @@ impl f64 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn is_sign_positive(self) -> bool {
         !self.is_sign_negative()
@@ -720,7 +719,7 @@ impl f64 {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
+    #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn is_sign_negative(self) -> bool {
         // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index ab73dc19fcc..7a8158b8231 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -171,14 +171,13 @@ impl<B, C> ControlFlow<B, C> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(control_flow_enum)]
     /// use std::ops::ControlFlow;
     ///
     /// assert_eq!(ControlFlow::<i32, String>::Break(3).break_value(), Some(3));
     /// assert_eq!(ControlFlow::<String, i32>::Continue(3).break_value(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
+    #[stable(feature = "control_flow_enum", since = "CURRENT_RUSTC_VERSION")]
     pub fn break_value(self) -> Option<B> {
         match self {
             ControlFlow::Continue(..) => None,
@@ -189,11 +188,8 @@ impl<B, C> ControlFlow<B, C> {
     /// Maps `ControlFlow<B, C>` to `ControlFlow<T, C>` by applying a function
     /// to the break value in case it exists.
     #[inline]
-    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
-    pub fn map_break<T, F>(self, f: F) -> ControlFlow<T, C>
-    where
-        F: FnOnce(B) -> T,
-    {
+    #[stable(feature = "control_flow_enum", since = "CURRENT_RUSTC_VERSION")]
+    pub fn map_break<T>(self, f: impl FnOnce(B) -> T) -> ControlFlow<T, C> {
         match self {
             ControlFlow::Continue(x) => ControlFlow::Continue(x),
             ControlFlow::Break(x) => ControlFlow::Break(f(x)),
@@ -206,14 +202,13 @@ impl<B, C> ControlFlow<B, C> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(control_flow_enum)]
     /// use std::ops::ControlFlow;
     ///
     /// assert_eq!(ControlFlow::<i32, String>::Break(3).continue_value(), None);
     /// assert_eq!(ControlFlow::<String, i32>::Continue(3).continue_value(), Some(3));
     /// ```
     #[inline]
-    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
+    #[stable(feature = "control_flow_enum", since = "CURRENT_RUSTC_VERSION")]
     pub fn continue_value(self) -> Option<C> {
         match self {
             ControlFlow::Continue(x) => Some(x),
@@ -224,11 +219,8 @@ impl<B, C> ControlFlow<B, C> {
     /// Maps `ControlFlow<B, C>` to `ControlFlow<B, T>` by applying a function
     /// to the continue value in case it exists.
     #[inline]
-    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
-    pub fn map_continue<T, F>(self, f: F) -> ControlFlow<B, T>
-    where
-        F: FnOnce(C) -> T,
-    {
+    #[stable(feature = "control_flow_enum", since = "CURRENT_RUSTC_VERSION")]
+    pub fn map_continue<T>(self, f: impl FnOnce(C) -> T) -> ControlFlow<B, T> {
         match self {
             ControlFlow::Continue(x) => ControlFlow::Continue(f(x)),
             ControlFlow::Break(x) => ControlFlow::Break(x),
diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs
index 25c4b87f4e7..5464bf645d9 100644
--- a/library/core/src/ops/mod.rs
+++ b/library/core/src/ops/mod.rs
@@ -162,7 +162,7 @@ pub use self::async_function::{AsyncFn, AsyncFnMut, AsyncFnOnce};
 pub use self::bit::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
 pub use self::bit::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign};
-#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
+#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
 pub use self::control_flow::ControlFlow;
 #[unstable(feature = "coroutine_trait", issue = "43122")]
 pub use self::coroutine::{Coroutine, CoroutineState};
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index a66ef16e3ca..154e52e288b 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -2543,3 +2543,27 @@ impl<T> Option<Option<T>> {
         }
     }
 }
+
+impl<T, const N: usize> [Option<T>; N] {
+    /// Transposes a `[Option<T>; N]` into a `Option<[T; N]>`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(option_array_transpose)]
+    /// # use std::option::Option;
+    ///
+    /// let data = [Some(0); 1000];
+    /// let data: Option<[u8; 1000]> = data.transpose();
+    /// assert_eq!(data, Some([0; 1000]));
+    ///
+    /// let data = [Some(0), None];
+    /// let data: Option<[u8; 2]> = data.transpose();
+    /// assert_eq!(data, None);
+    /// ```
+    #[inline]
+    #[unstable(feature = "option_array_transpose", issue = "130828")]
+    pub fn transpose(self) -> Option<[T; N]> {
+        self.try_map(core::convert::identity)
+    }
+}
diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs
index e2a842046a9..1ad5c07d15c 100644
--- a/library/core/src/panic/location.rs
+++ b/library/core/src/panic/location.rs
@@ -44,7 +44,7 @@ impl<'a> Location<'a> {
     ///
     /// # Examples
     ///
-    /// ```standalone
+    /// ```standalone_crate
     /// use std::panic::Location;
     ///
     /// /// Returns the [`Location`] at which it is called.
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index 962da6643dd..c25501f1200 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1251,7 +1251,7 @@ mod prim_f16 {}
 ///   - **Unchanged NaN propagation**: The quiet bit and payload are copied from any input operand
 ///     that is a NaN. If the inputs and outputs do not have the same size (i.e., for `as` casts), the
 ///     same rules as for "quieting NaN propagation" apply, with one caveat: if the output is smaller
-///     than the input, droppig the low-order bits may result in a payload of 0; a payload of 0 is not
+///     than the input, dropping the low-order bits may result in a payload of 0; a payload of 0 is not
 ///     possible with a signaling NaN (the all-0 significand encodes an infinity) so unchanged NaN
 ///     propagation cannot occur with some inputs.
 ///   - **Target-specific NaN**: The quiet bit is set and the payload is picked from a target-specific
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 1146ca6ef43..332c5e904d7 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -92,7 +92,7 @@ impl<T: ?Sized> *const T {
     /// }
     /// ```
     #[unstable(feature = "set_ptr_value", issue = "75091")]
-    #[rustc_const_unstable(feature = "set_ptr_value", issue = "75091")]
+    #[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[inline]
     pub const fn with_metadata_of<U>(self, meta: *const U) -> *const U
@@ -346,7 +346,7 @@ impl<T: ?Sized> *const T {
         if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) }
     }
 
-    /// Adds an offset to a pointer.
+    /// Adds a signed offset to a pointer.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -355,7 +355,8 @@ impl<T: ?Sized> *const T {
     ///
     /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
+    /// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
+    ///   "wrapping around"), must fit in an `isize`.
     ///
     /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
     ///   [allocated object], and the entire memory range between `self` and the result must be in
@@ -398,7 +399,7 @@ impl<T: ?Sized> *const T {
         unsafe { intrinsics::offset(self, count) }
     }
 
-    /// Calculates the offset from a pointer in bytes.
+    /// Adds a signed offset in bytes to a pointer.
     ///
     /// `count` is in units of **bytes**.
     ///
@@ -412,14 +413,13 @@ impl<T: ?Sized> *const T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_offset(self, count: isize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `offset`.
         unsafe { self.cast::<u8>().offset(count).with_metadata_of(self) }
     }
 
-    /// Calculates the offset from a pointer using wrapping arithmetic.
+    /// Adds a signed offset to a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -481,7 +481,7 @@ impl<T: ?Sized> *const T {
         unsafe { intrinsics::arith_offset(self, count) }
     }
 
-    /// Calculates the offset from a pointer in bytes using wrapping arithmetic.
+    /// Adds a signed offset in bytes to a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of **bytes**.
     ///
@@ -495,7 +495,6 @@ impl<T: ?Sized> *const T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     pub const fn wrapping_byte_offset(self, count: isize) -> Self {
         self.cast::<u8>().wrapping_offset(count).with_metadata_of(self)
     }
@@ -645,7 +644,6 @@ impl<T: ?Sized> *const T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_offset_from<U: ?Sized>(self, origin: *const U) -> isize {
         // SAFETY: the caller must uphold the safety contract for `offset_from`.
@@ -807,7 +805,11 @@ impl<T: ?Sized> *const T {
         }
     }
 
-    /// Adds an offset to a pointer (convenience for `.offset(count as isize)`).
+    /// Adds an unsigned offset to a pointer.
+    ///
+    /// This can only move the pointer forward (or not move it). If you need to move forward or
+    /// backward depending on the value, then you might want [`offset`](#method.offset) instead
+    /// which takes a signed offset.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -816,7 +818,8 @@ impl<T: ?Sized> *const T {
     ///
     /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
+    /// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
+    ///   "wrapping around"), must fit in an `isize`.
     ///
     /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
     ///   [allocated object], and the entire memory range between `self` and the result must be in
@@ -859,7 +862,7 @@ impl<T: ?Sized> *const T {
         unsafe { intrinsics::offset(self, count) }
     }
 
-    /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`).
+    /// Adds an unsigned offset in bytes to a pointer.
     ///
     /// `count` is in units of bytes.
     ///
@@ -873,15 +876,17 @@ impl<T: ?Sized> *const T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_add(self, count: usize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `add`.
         unsafe { self.cast::<u8>().add(count).with_metadata_of(self) }
     }
 
-    /// Subtracts an offset from a pointer (convenience for
-    /// `.offset((count as isize).wrapping_neg())`).
+    /// Subtracts an unsigned offset from a pointer.
+    ///
+    /// This can only move the pointer backward (or not move it). If you need to move forward or
+    /// backward depending on the value, then you might want [`offset`](#method.offset) instead
+    /// which takes a signed offset.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -890,7 +895,8 @@ impl<T: ?Sized> *const T {
     ///
     /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
+    /// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
+    ///   "wrapping around"), must fit in an `isize`.
     ///
     /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
     ///   [allocated object], and the entire memory range between `self` and the result must be in
@@ -941,8 +947,7 @@ impl<T: ?Sized> *const T {
         }
     }
 
-    /// Calculates the offset from a pointer in bytes (convenience for
-    /// `.byte_offset((count as isize).wrapping_neg())`).
+    /// Subtracts an unsigned offset in bytes from a pointer.
     ///
     /// `count` is in units of bytes.
     ///
@@ -956,15 +961,13 @@ impl<T: ?Sized> *const T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_sub(self, count: usize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `sub`.
         unsafe { self.cast::<u8>().sub(count).with_metadata_of(self) }
     }
 
-    /// Calculates the offset from a pointer using wrapping arithmetic.
-    /// (convenience for `.wrapping_offset(count as isize)`)
+    /// Adds an unsigned offset to a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -1025,8 +1028,7 @@ impl<T: ?Sized> *const T {
         self.wrapping_offset(count as isize)
     }
 
-    /// Calculates the offset from a pointer in bytes using wrapping arithmetic.
-    /// (convenience for `.wrapping_byte_offset(count as isize)`)
+    /// Adds an unsigned offset in bytes to a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of bytes.
     ///
@@ -1039,13 +1041,11 @@ impl<T: ?Sized> *const T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     pub const fn wrapping_byte_add(self, count: usize) -> Self {
         self.cast::<u8>().wrapping_add(count).with_metadata_of(self)
     }
 
-    /// Calculates the offset from a pointer using wrapping arithmetic.
-    /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`)
+    /// Subtracts an unsigned offset from a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -1106,8 +1106,7 @@ impl<T: ?Sized> *const T {
         self.wrapping_offset((count as isize).wrapping_neg())
     }
 
-    /// Calculates the offset from a pointer in bytes using wrapping arithmetic.
-    /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`)
+    /// Subtracts an unsigned offset in bytes from a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of bytes.
     ///
@@ -1120,7 +1119,6 @@ impl<T: ?Sized> *const T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     pub const fn wrapping_byte_sub(self, count: usize) -> Self {
         self.cast::<u8>().wrapping_sub(count).with_metadata_of(self)
     }
@@ -1554,7 +1552,6 @@ impl<T> *const [T] {
     #[inline]
     #[stable(feature = "slice_ptr_len", since = "1.79.0")]
     #[rustc_const_stable(feature = "const_slice_ptr_len", since = "1.79.0")]
-    #[rustc_allow_const_fn_unstable(ptr_metadata)]
     pub const fn len(self) -> usize {
         metadata(self)
     }
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index 76a0e2ba774..feeaf78d3e7 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -92,7 +92,7 @@ pub trait Thin = Pointee<Metadata = ()>;
 ///
 /// assert_eq!(std::ptr::metadata("foo"), 3_usize);
 /// ```
-#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")]
 #[inline]
 pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
     ptr_metadata(ptr)
@@ -106,7 +106,7 @@ pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
 ///
 /// [`slice::from_raw_parts`]: crate::slice::from_raw_parts
 #[unstable(feature = "ptr_metadata", issue = "81513")]
-#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")]
 #[inline]
 pub const fn from_raw_parts<T: ?Sized>(
     data_pointer: *const impl Thin,
@@ -120,7 +120,7 @@ pub const fn from_raw_parts<T: ?Sized>(
 ///
 /// See the documentation of [`from_raw_parts`] for more details.
 #[unstable(feature = "ptr_metadata", issue = "81513")]
-#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
+#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")]
 #[inline]
 pub const fn from_raw_parts_mut<T: ?Sized>(
     data_pointer: *mut impl Thin,
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 4f97048eab1..67f1b0cd16d 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -599,7 +599,6 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
 #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
-#[rustc_allow_const_fn_unstable(ptr_metadata)]
 #[rustc_diagnostic_item = "ptr_null"]
 pub const fn null<T: ?Sized + Thin>() -> *const T {
     from_raw_parts(without_provenance::<()>(0), ())
@@ -625,7 +624,6 @@ pub const fn null<T: ?Sized + Thin>() -> *const T {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
 #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
-#[rustc_allow_const_fn_unstable(ptr_metadata)]
 #[rustc_diagnostic_item = "ptr_null_mut"]
 pub const fn null_mut<T: ?Sized + Thin>() -> *mut T {
     from_raw_parts_mut(without_provenance_mut::<()>(0), ())
@@ -949,7 +947,6 @@ pub const fn from_mut<T: ?Sized>(r: &mut T) -> *mut T {
 #[inline]
 #[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
 #[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")]
-#[rustc_allow_const_fn_unstable(ptr_metadata)]
 #[rustc_diagnostic_item = "ptr_slice_from_raw_parts"]
 pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
     from_raw_parts(data, len)
@@ -995,7 +992,7 @@ pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
 /// ```
 #[inline]
 #[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
-#[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")]
+#[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "CURRENT_RUSTC_VERSION")]
 #[rustc_diagnostic_item = "ptr_slice_from_raw_parts_mut"]
 pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
     from_raw_parts_mut(data, len)
@@ -1912,6 +1909,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
 /// than trying to adapt this to accommodate that change.
 ///
 /// Any questions go to @nagisa.
+#[cfg_attr(not(bootstrap), allow(ptr_to_integer_transmute_in_consts))]
 #[lang = "align_offset"]
 pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
     // FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <=
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 8e33cf081ba..287073497f8 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -74,7 +74,7 @@ impl<T: ?Sized> *mut T {
     /// }
     /// ```
     #[unstable(feature = "set_ptr_value", issue = "75091")]
-    #[rustc_const_unstable(feature = "set_ptr_value", issue = "75091")]
+    #[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[inline]
     pub const fn with_metadata_of<U>(self, meta: *const U) -> *mut U
@@ -344,7 +344,7 @@ impl<T: ?Sized> *mut T {
         if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) }
     }
 
-    /// Adds an offset to a pointer.
+    /// Adds a signed offset to a pointer.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -353,7 +353,8 @@ impl<T: ?Sized> *mut T {
     ///
     /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
+    /// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
+    ///   "wrapping around"), must fit in an `isize`.
     ///
     /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
     ///   [allocated object], and the entire memory range between `self` and the result must be in
@@ -398,7 +399,7 @@ impl<T: ?Sized> *mut T {
         unsafe { intrinsics::offset(self, count) }
     }
 
-    /// Calculates the offset from a pointer in bytes.
+    /// Adds a signed offset in bytes to a pointer.
     ///
     /// `count` is in units of **bytes**.
     ///
@@ -412,14 +413,14 @@ impl<T: ?Sized> *mut T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_offset(self, count: isize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `offset`.
         unsafe { self.cast::<u8>().offset(count).with_metadata_of(self) }
     }
 
-    /// Calculates the offset from a pointer using wrapping arithmetic.
+    /// Adds a signed offset to a pointer using wrapping arithmetic.
+    ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
     ///
@@ -478,7 +479,7 @@ impl<T: ?Sized> *mut T {
         unsafe { intrinsics::arith_offset(self, count) as *mut T }
     }
 
-    /// Calculates the offset from a pointer in bytes using wrapping arithmetic.
+    /// Adds a signed offset in bytes to a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of **bytes**.
     ///
@@ -492,7 +493,6 @@ impl<T: ?Sized> *mut T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     pub const fn wrapping_byte_offset(self, count: isize) -> Self {
         self.cast::<u8>().wrapping_offset(count).with_metadata_of(self)
     }
@@ -808,7 +808,6 @@ impl<T: ?Sized> *mut T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_offset_from<U: ?Sized>(self, origin: *const U) -> isize {
         // SAFETY: the caller must uphold the safety contract for `offset_from`.
@@ -888,7 +887,11 @@ impl<T: ?Sized> *mut T {
         unsafe { (self as *const T).sub_ptr(origin) }
     }
 
-    /// Adds an offset to a pointer (convenience for `.offset(count as isize)`).
+    /// Adds an unsigned offset to a pointer.
+    ///
+    /// This can only move the pointer forward (or not move it). If you need to move forward or
+    /// backward depending on the value, then you might want [`offset`](#method.offset) instead
+    /// which takes a signed offset.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -897,7 +900,8 @@ impl<T: ?Sized> *mut T {
     ///
     /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
+    /// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
+    ///   "wrapping around"), must fit in an `isize`.
     ///
     /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
     ///   [allocated object], and the entire memory range between `self` and the result must be in
@@ -940,7 +944,7 @@ impl<T: ?Sized> *mut T {
         unsafe { intrinsics::offset(self, count) }
     }
 
-    /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`).
+    /// Adds an unsigned offset in bytes to a pointer.
     ///
     /// `count` is in units of bytes.
     ///
@@ -954,15 +958,17 @@ impl<T: ?Sized> *mut T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_add(self, count: usize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `add`.
         unsafe { self.cast::<u8>().add(count).with_metadata_of(self) }
     }
 
-    /// Subtracts an offset from a pointer (convenience for
-    /// `.offset((count as isize).wrapping_neg())`).
+    /// Subtracts an unsigned offset from a pointer.
+    ///
+    /// This can only move the pointer backward (or not move it). If you need to move forward or
+    /// backward depending on the value, then you might want [`offset`](#method.offset) instead
+    /// which takes a signed offset.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -971,7 +977,8 @@ impl<T: ?Sized> *mut T {
     ///
     /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
+    /// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
+    ///   "wrapping around"), must fit in an `isize`.
     ///
     /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
     ///   [allocated object], and the entire memory range between `self` and the result must be in
@@ -1022,8 +1029,7 @@ impl<T: ?Sized> *mut T {
         }
     }
 
-    /// Calculates the offset from a pointer in bytes (convenience for
-    /// `.byte_offset((count as isize).wrapping_neg())`).
+    /// Subtracts an unsigned offset in bytes from a pointer.
     ///
     /// `count` is in units of bytes.
     ///
@@ -1037,15 +1043,13 @@ impl<T: ?Sized> *mut T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_sub(self, count: usize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `sub`.
         unsafe { self.cast::<u8>().sub(count).with_metadata_of(self) }
     }
 
-    /// Calculates the offset from a pointer using wrapping arithmetic.
-    /// (convenience for `.wrapping_offset(count as isize)`)
+    /// Adds an unsigned offset to a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -1104,8 +1108,7 @@ impl<T: ?Sized> *mut T {
         self.wrapping_offset(count as isize)
     }
 
-    /// Calculates the offset from a pointer in bytes using wrapping arithmetic.
-    /// (convenience for `.wrapping_byte_offset(count as isize)`)
+    /// Adds an unsigned offset in bytes to a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of bytes.
     ///
@@ -1118,13 +1121,11 @@ impl<T: ?Sized> *mut T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     pub const fn wrapping_byte_add(self, count: usize) -> Self {
         self.cast::<u8>().wrapping_add(count).with_metadata_of(self)
     }
 
-    /// Calculates the offset from a pointer using wrapping arithmetic.
-    /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`)
+    /// Subtracts an unsigned offset from a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
@@ -1183,8 +1184,7 @@ impl<T: ?Sized> *mut T {
         self.wrapping_offset((count as isize).wrapping_neg())
     }
 
-    /// Calculates the offset from a pointer in bytes using wrapping arithmetic.
-    /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`)
+    /// Subtracts an unsigned offset in bytes from a pointer using wrapping arithmetic.
     ///
     /// `count` is in units of bytes.
     ///
@@ -1197,7 +1197,6 @@ impl<T: ?Sized> *mut T {
     #[inline(always)]
     #[stable(feature = "pointer_byte_offsets", since = "1.75.0")]
     #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")]
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     pub const fn wrapping_byte_sub(self, count: usize) -> Self {
         self.cast::<u8>().wrapping_sub(count).with_metadata_of(self)
     }
@@ -1804,7 +1803,6 @@ impl<T> *mut [T] {
     #[inline(always)]
     #[stable(feature = "slice_ptr_len", since = "1.79.0")]
     #[rustc_const_stable(feature = "const_slice_ptr_len", since = "1.79.0")]
-    #[rustc_allow_const_fn_unstable(ptr_metadata)]
     pub const fn len(self) -> usize {
         metadata(self)
     }
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index daa40b3c9d2..6c5834a1ece 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -394,7 +394,8 @@ impl<T: ?Sized> NonNull<T> {
     ///
     /// [the module documentation]: crate::ptr#safety
     #[stable(feature = "nonnull", since = "1.25.0")]
-    #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
+    #[rustc_const_stable(feature = "const_ptr_as_ref", since = "CURRENT_RUSTC_VERSION")]
     #[must_use]
     #[inline(always)]
     pub const unsafe fn as_mut<'a>(&mut self) -> &'a mut T {
@@ -567,7 +568,6 @@ impl<T: ?Sized> NonNull<T> {
     #[must_use]
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[stable(feature = "non_null_convenience", since = "1.80.0")]
     #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")]
     pub const unsafe fn byte_add(self, count: usize) -> Self {
@@ -651,7 +651,6 @@ impl<T: ?Sized> NonNull<T> {
     #[must_use]
     #[inline(always)]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
-    #[rustc_allow_const_fn_unstable(set_ptr_value)]
     #[stable(feature = "non_null_convenience", since = "1.80.0")]
     #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")]
     pub const unsafe fn byte_sub(self, count: usize) -> Self {
@@ -1435,7 +1434,10 @@ impl<T> NonNull<[T]> {
     /// (Note that this example artificially demonstrates a use of this method,
     /// but `let slice = NonNull::from(&x[..]);` would be a better way to write code like this.)
     #[stable(feature = "nonnull_slice_from_raw_parts", since = "1.70.0")]
-    #[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")]
+    #[rustc_const_stable(
+        feature = "const_slice_from_raw_parts_mut",
+        since = "CURRENT_RUSTC_VERSION"
+    )]
     #[must_use]
     #[inline]
     pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self {
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index dd8fa1ae343..90ddc9c1d85 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -111,7 +111,6 @@ impl<T> [T] {
     #[lang = "slice_len_fn"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")]
-    #[rustc_allow_const_fn_unstable(ptr_metadata)]
     #[inline]
     #[must_use]
     pub const fn len(&self) -> usize {
@@ -172,7 +171,8 @@ impl<T> [T] {
     /// assert_eq!(None, y.first_mut());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
+    #[rustc_const_stable(feature = "const_slice_first_last", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     #[must_use]
     pub const fn first_mut(&mut self) -> Option<&mut T> {
@@ -214,7 +214,8 @@ impl<T> [T] {
     /// assert_eq!(x, &[3, 4, 5]);
     /// ```
     #[stable(feature = "slice_splits", since = "1.5.0")]
-    #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
+    #[rustc_const_stable(feature = "const_slice_first_last", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     #[must_use]
     pub const fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> {
@@ -256,7 +257,8 @@ impl<T> [T] {
     /// assert_eq!(x, &[4, 5, 3]);
     /// ```
     #[stable(feature = "slice_splits", since = "1.5.0")]
-    #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
+    #[rustc_const_stable(feature = "const_slice_first_last", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     #[must_use]
     pub const fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> {
@@ -298,7 +300,8 @@ impl<T> [T] {
     /// assert_eq!(None, y.last_mut());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
+    #[rustc_const_stable(feature = "const_slice_first_last", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     #[must_use]
     pub const fn last_mut(&mut self) -> Option<&mut T> {
@@ -353,7 +356,8 @@ impl<T> [T] {
     /// ```
     #[inline]
     #[stable(feature = "slice_first_last_chunk", since = "1.77.0")]
-    #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")]
+    #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
     pub const fn first_chunk_mut<const N: usize>(&mut self) -> Option<&mut [T; N]> {
         if self.len() < N {
             None
@@ -418,7 +422,8 @@ impl<T> [T] {
     /// ```
     #[inline]
     #[stable(feature = "slice_first_last_chunk", since = "1.77.0")]
-    #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")]
+    #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
     pub const fn split_first_chunk_mut<const N: usize>(
         &mut self,
     ) -> Option<(&mut [T; N], &mut [T])> {
@@ -488,7 +493,8 @@ impl<T> [T] {
     /// ```
     #[inline]
     #[stable(feature = "slice_first_last_chunk", since = "1.77.0")]
-    #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")]
+    #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
     pub const fn split_last_chunk_mut<const N: usize>(
         &mut self,
     ) -> Option<(&mut [T], &mut [T; N])> {
@@ -557,7 +563,8 @@ impl<T> [T] {
     /// ```
     #[inline]
     #[stable(feature = "slice_first_last_chunk", since = "1.77.0")]
-    #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")]
+    #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
     pub const fn last_chunk_mut<const N: usize>(&mut self) -> Option<&mut [T; N]> {
         if self.len() < N {
             None
@@ -1900,7 +1907,8 @@ impl<T> [T] {
     #[inline]
     #[track_caller]
     #[must_use]
-    #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")]
+    #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "CURRENT_RUSTC_VERSION")]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
     pub const fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
         match self.split_at_mut_checked(mid) {
             Some(pair) => pair,
@@ -2002,7 +2010,8 @@ impl<T> [T] {
     /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
     /// ```
     #[stable(feature = "slice_split_at_unchecked", since = "1.79.0")]
-    #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")]
+    #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "CURRENT_RUSTC_VERSION")]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
     #[inline]
     #[must_use]
     pub const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
@@ -2102,7 +2111,8 @@ impl<T> [T] {
     /// assert_eq!(None, v.split_at_mut_checked(7));
     /// ```
     #[stable(feature = "split_at_checked", since = "1.80.0")]
-    #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")]
+    #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "CURRENT_RUSTC_VERSION")]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
     #[inline]
     #[must_use]
     pub const fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut [T], &mut [T])> {
diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs
index 2cf3fecb475..84e916b9a84 100644
--- a/library/core/src/slice/raw.rs
+++ b/library/core/src/slice/raw.rs
@@ -171,7 +171,8 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
 /// [`NonNull::dangling()`]: ptr::NonNull::dangling
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")]
+#[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "CURRENT_RUSTC_VERSION")]
+#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
 #[must_use]
 #[rustc_diagnostic_item = "slice_from_raw_parts_mut"]
 pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs
index d6459607221..194db56fdaf 100644
--- a/library/core/src/str/converts.rs
+++ b/library/core/src/str/converts.rs
@@ -195,7 +195,11 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
 #[inline]
 #[must_use]
 #[stable(feature = "str_mut_extras", since = "1.20.0")]
-#[rustc_const_unstable(feature = "const_str_from_utf8_unchecked_mut", issue = "91005")]
+#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
+#[rustc_const_stable(
+    feature = "const_str_from_utf8_unchecked_mut",
+    since = "CURRENT_RUSTC_VERSION"
+)]
 #[rustc_diagnostic_item = "str_from_utf8_unchecked_mut"]
 pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
     // SAFETY: the caller must guarantee that the bytes `v`
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 3d535214637..e93c52f2799 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -339,7 +339,8 @@ impl str {
     /// assert_eq!("🍔∈🌏", s);
     /// ```
     #[stable(feature = "str_mut_extras", since = "1.20.0")]
-    #[rustc_const_unstable(feature = "const_str_as_mut", issue = "130086")]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
+    #[rustc_const_stable(feature = "const_str_as_mut", since = "CURRENT_RUSTC_VERSION")]
     #[must_use]
     #[inline(always)]
     pub const unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
@@ -385,7 +386,8 @@ impl str {
     /// It is your responsibility to make sure that the string slice only gets
     /// modified in a way that it remains valid UTF-8.
     #[stable(feature = "str_as_mut_ptr", since = "1.36.0")]
-    #[rustc_const_unstable(feature = "const_str_as_mut", issue = "130086")]
+    #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))]
+    #[rustc_const_stable(feature = "const_str_as_mut", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_never_returns_null_ptr]
     #[must_use]
     #[inline(always)]
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index b06a3bd4487..42b68e28273 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -24,25 +24,42 @@
 //!
 //! ## Memory model for atomic accesses
 //!
-//! Rust atomics currently follow the same rules as [C++20 atomics][cpp], specifically `atomic_ref`.
-//! Basically, creating a *shared reference* to one of the Rust atomic types corresponds to creating
-//! an `atomic_ref` in C++; the `atomic_ref` is destroyed when the lifetime of the shared reference
-//! ends. A Rust atomic type that is exclusively owned or behind a mutable reference does *not*
-//! correspond to an “atomic object” in C++, since the underlying primitive can be mutably accessed,
-//! for example with `get_mut`, to perform non-atomic operations.
+//! Rust atomics currently follow the same rules as [C++20 atomics][cpp], specifically the rules
+//! from the [`intro.races`][cpp-intro.races] section, without the "consume" memory ordering. Since
+//! C++ uses an object-based memory model whereas Rust is access-based, a bit of translation work
+//! has to be done to apply the C++ rules to Rust: whenever C++ talks about "the value of an
+//! object", we understand that to mean the resulting bytes obtained when doing a read. When the C++
+//! standard talks about "the value of an atomic object", this refers to the result of doing an
+//! atomic load (via the operations provided in this module). A "modification of an atomic object"
+//! refers to an atomic store.
 //!
-//! [cpp]: https://en.cppreference.com/w/cpp/atomic
+//! The end result is *almost* equivalent to saying that creating a *shared reference* to one of the
+//! Rust atomic types corresponds to creating an `atomic_ref` in C++, with the `atomic_ref` being
+//! destroyed when the lifetime of the shared reference ends. The main difference is that Rust
+//! permits concurrent atomic and non-atomic reads to the same memory as those cause no issue in the
+//! C++ memory model, they are just forbidden in C++ because memory is partitioned into "atomic
+//! objects" and "non-atomic objects" (with `atomic_ref` temporarily converting a non-atomic object
+//! into an atomic object).
+//!
+//! The most important aspect of this model is that *data races* are undefined behavior. A data race
+//! is defined as conflicting non-synchronized accesses where at least one of the accesses is
+//! non-atomic. Here, accesses are *conflicting* if they affect overlapping regions of memory and at
+//! least one of them is a write. They are *non-synchronized* if neither of them *happens-before*
+//! the other, according to the happens-before order of the memory model.
 //!
-//! Each method takes an [`Ordering`] which represents the strength of
-//! the memory barrier for that operation. These orderings are the
-//! same as the [C++20 atomic orderings][1]. For more information see the [nomicon][2].
+//! The other possible cause of undefined behavior in the memory model are mixed-size accesses: Rust
+//! inherits the C++ limitation that non-synchronized conflicting atomic accesses may not partially
+//! overlap. In other words, every pair of non-synchronized atomic accesses must be either disjoint,
+//! access the exact same memory (including using the same access size), or both be reads.
 //!
-//! [1]: https://en.cppreference.com/w/cpp/atomic/memory_order
-//! [2]: ../../../nomicon/atomics.html
+//! Each atomic access takes an [`Ordering`] which defines how the operation interacts with the
+//! happens-before order. These orderings behave the same as the corresponding [C++20 atomic
+//! orderings][cpp_memory_order]. For more information, see the [nomicon].
 //!
-//! Since C++ does not support mixing atomic and non-atomic accesses, or non-synchronized
-//! different-sized accesses to the same data, Rust does not support those operations either.
-//! Note that both of those restrictions only apply if the accesses are non-synchronized.
+//! [cpp]: https://en.cppreference.com/w/cpp/atomic
+//! [cpp-intro.races]: https://timsong-cpp.github.io/cppwp/n4868/intro.multithread#intro.races
+//! [cpp_memory_order]: https://en.cppreference.com/w/cpp/atomic/memory_order
+//! [nomicon]: ../../../nomicon/atomics.html
 //!
 //! ```rust,no_run undefined_behavior
 //! use std::sync::atomic::{AtomicU16, AtomicU8, Ordering};
@@ -52,27 +69,29 @@
 //! let atomic = AtomicU16::new(0);
 //!
 //! thread::scope(|s| {
-//!     // This is UB: mixing atomic and non-atomic accesses
-//!     s.spawn(|| atomic.store(1, Ordering::Relaxed));
-//!     s.spawn(|| unsafe { atomic.as_ptr().write(2) });
+//!     // This is UB: conflicting non-synchronized accesses, at least one of which is non-atomic.
+//!     s.spawn(|| atomic.store(1, Ordering::Relaxed)); // atomic store
+//!     s.spawn(|| unsafe { atomic.as_ptr().write(2) }); // non-atomic write
 //! });
 //!
 //! thread::scope(|s| {
-//!     // This is UB: even reads are not allowed to be mixed
-//!     s.spawn(|| atomic.load(Ordering::Relaxed));
-//!     s.spawn(|| unsafe { atomic.as_ptr().read() });
+//!     // This is fine: the accesses do not conflict (as none of them performs any modification).
+//!     // In C++ this would be disallowed since creating an `atomic_ref` precludes
+//!     // further non-atomic accesses, but Rust does not have that limitation.
+//!     s.spawn(|| atomic.load(Ordering::Relaxed)); // atomic load
+//!     s.spawn(|| unsafe { atomic.as_ptr().read() }); // non-atomic read
 //! });
 //!
 //! thread::scope(|s| {
-//!     // This is fine, `join` synchronizes the code in a way such that atomic
-//!     // and non-atomic accesses can't happen "at the same time"
-//!     let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed));
-//!     handle.join().unwrap();
-//!     s.spawn(|| unsafe { atomic.as_ptr().write(2) });
+//!     // This is fine: `join` synchronizes the code in a way such that the atomic
+//!     // store happens-before the non-atomic write.
+//!     let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed)); // atomic store
+//!     handle.join().unwrap(); // synchronize
+//!     s.spawn(|| unsafe { atomic.as_ptr().write(2) }); // non-atomic write
 //! });
 //!
 //! thread::scope(|s| {
-//!     // This is UB: using different-sized atomic accesses to the same data
+//!     // This is UB: non-synchronized conflicting differently-sized atomic accesses.
 //!     s.spawn(|| atomic.store(1, Ordering::Relaxed));
 //!     s.spawn(|| unsafe {
 //!         let differently_sized = transmute::<&AtomicU16, &AtomicU8>(&atomic);
@@ -81,8 +100,8 @@
 //! });
 //!
 //! thread::scope(|s| {
-//!     // This is fine, `join` synchronizes the code in a way such that
-//!     // differently-sized accesses can't happen "at the same time"
+//!     // This is fine: `join` synchronizes the code in a way such that
+//!     // the 1-byte store happens-before the 2-byte store.
 //!     let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed));
 //!     handle.join().unwrap();
 //!     s.spawn(|| unsafe {
@@ -137,7 +156,7 @@
 //!
 //! # Atomic accesses to read-only memory
 //!
-//! In general, *all* atomic accesses on read-only memory are Undefined Behavior. For instance, attempting
+//! In general, *all* atomic accesses on read-only memory are undefined behavior. For instance, attempting
 //! to do a `compare_exchange` that will definitely fail (making it conceptually a read-only
 //! operation) can still cause a segmentation fault if the underlying memory page is mapped read-only. Since
 //! atomic `load`s might be implemented using compare-exchange operations, even a `load` can fault
@@ -153,7 +172,7 @@
 //!
 //! As an exception from the general rule stated above, "sufficiently small" atomic loads with
 //! `Ordering::Relaxed` are implemented in a way that works on read-only memory, and are hence not
-//! Undefined Behavior. The exact size limit for what makes a load "sufficiently small" varies
+//! undefined behavior. The exact size limit for what makes a load "sufficiently small" varies
 //! depending on the target:
 //!
 //! | `target_arch` | Size limit |
@@ -577,7 +596,7 @@ impl AtomicBool {
     #[stable(feature = "atomic_access", since = "1.15.0")]
     #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")]
     pub const fn into_inner(self) -> bool {
-        self.v.primitive_into_inner() != 0
+        self.v.into_inner() != 0
     }
 
     /// Loads a value from the bool.
@@ -1394,7 +1413,7 @@ impl<T> AtomicPtr<T> {
     #[stable(feature = "atomic_access", since = "1.15.0")]
     #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")]
     pub const fn into_inner(self) -> *mut T {
-        self.p.primitive_into_inner()
+        self.p.into_inner()
     }
 
     /// Loads a value from the pointer.
@@ -2389,7 +2408,7 @@ macro_rules! atomic_int {
             #[$stable_access]
             #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")]
             pub const fn into_inner(self) -> $int_type {
-                self.v.primitive_into_inner()
+                self.v.into_inner()
             }
 
             /// Loads a value from the atomic integer.
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 604c0d48743..196e91ee3e9 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -18,7 +18,6 @@
 #![feature(const_align_offset)]
 #![feature(const_array_from_ref)]
 #![feature(const_black_box)]
-#![feature(const_cell_into_inner)]
 #![feature(const_hash)]
 #![feature(const_heap)]
 #![feature(const_ip)]
@@ -30,7 +29,6 @@
 #![feature(const_option_ext)]
 #![feature(const_pin)]
 #![feature(const_pointer_is_aligned)]
-#![feature(const_ptr_as_ref)]
 #![feature(const_ptr_write)]
 #![feature(const_result)]
 #![feature(const_slice_from_ref)]
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 5522d556a59..72b597a8083 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -1166,7 +1166,7 @@ impl fmt::Debug for Ident {
     }
 }
 
-/// A literal string (`"hello"`), byte string (`b"hello"`),
+/// A literal string (`"hello"`), byte string (`b"hello"`), C string (`c"hello"`),
 /// character (`'a'`), byte character (`b'a'`), an integer or floating point number
 /// with or without a suffix (`1`, `1u8`, `2.3`, `2.3f32`).
 /// Boolean literals like `true` and `false` do not belong here, they are `Ident`s.
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index d55114227af..f2669326065 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -17,10 +17,10 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
 panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core", public = true }
-compiler_builtins = { version = "0.1.126" }
+compiler_builtins = { version = "0.1.133" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
-hashbrown = { version = "0.14", default-features = false, features = [
+hashbrown = { version = "0.15", default-features = false, features = [
     'rustc-dep-of-std',
 ] }
 # FIXME(#127890): `object` depends on `memchr`, but `memchr` > v2.5 causes
diff --git a/library/std/build.rs b/library/std/build.rs
index 359ae4f20ee..032326556bd 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -7,6 +7,7 @@ fn main() {
     let target_vendor =
         env::var("CARGO_CFG_TARGET_VENDOR").expect("CARGO_CFG_TARGET_VENDOR was not set");
     let target_env = env::var("CARGO_CFG_TARGET_ENV").expect("CARGO_CFG_TARGET_ENV was not set");
+    let target_abi = env::var("CARGO_CFG_TARGET_ABI").expect("CARGO_CFG_TARGET_ABI was not set");
     let target_pointer_width: u32 = env::var("CARGO_CFG_TARGET_POINTER_WIDTH")
         .expect("CARGO_CFG_TARGET_POINTER_WIDTH was not set")
         .parse()
@@ -96,30 +97,24 @@ fn main() {
     let has_reliable_f16 = match (target_arch.as_str(), target_os.as_str()) {
         // We can always enable these in Miri as that is not affected by codegen bugs.
         _ if is_miri => true,
-        // Selection failure until recent LLVM <https://github.com/llvm/llvm-project/issues/93894>
-        // FIXME(llvm19): can probably be removed at the version bump
-        ("loongarch64", _) => false,
         // Selection failure <https://github.com/llvm/llvm-project/issues/50374>
         ("s390x", _) => false,
         // Unsupported <https://github.com/llvm/llvm-project/issues/94434>
         ("arm64ec", _) => false,
         // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
-        ("x86_64", "windows") => false,
-        // Apple has a special ABI for `f16` that we do not yet support
-        // FIXME(builtins): fixed by <https://github.com/rust-lang/compiler-builtins/pull/675>
-        ("x86" | "x86_64", _) if target_vendor == "apple" => false,
-        // Missing `__gnu_h2f_ieee` and `__gnu_f2h_ieee`
+        ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false,
+        // Infinite recursion <https://github.com/llvm/llvm-project/issues/97981>
+        ("csky", _) => false,
+        ("hexagon", _) => false,
+        ("loongarch64", _) => false,
+        ("mips" | "mips64" | "mips32r6" | "mips64r6", _) => false,
         ("powerpc" | "powerpc64", _) => false,
-        // Missing `__gnu_h2f_ieee` and `__gnu_f2h_ieee`
-        ("mips" | "mips32r6" | "mips64" | "mips64r6", _) => false,
-        // Missing `__extendhfsf` and `__truncsfhf`
-        ("riscv32" | "riscv64", _) => false,
-        // Most OSs are missing `__extendhfsf` and `__truncsfhf`
-        (_, "linux" | "macos") => true,
-        // Almost all OSs besides Linux and MacOS are missing symbols until compiler-builtins can
-        // be updated. <https://github.com/rust-lang/rust/pull/125016> will get some of these, the
-        // next CB update should get the rest.
-        _ => false,
+        ("sparc" | "sparc64", _) => false,
+        ("wasm32" | "wasm64", _) => false,
+        // `f16` support only requires that symbols converting to and from `f32` are available. We
+        // provide these in `compiler-builtins`, so `f16` should be available on all platforms that
+        // do not have other ABI issues or LLVM crashes.
+        _ => true,
     };
 
     let has_reliable_f128 = match (target_arch.as_str(), target_os.as_str()) {
@@ -135,10 +130,10 @@ fn main() {
         // ABI unsupported  <https://github.com/llvm/llvm-project/issues/41838>
         ("sparc", _) => false,
         // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
-        ("x86_64", "windows") => false,
+        ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false,
         // 64-bit Linux is about the only platform to have f128 symbols by default
         (_, "linux") if target_pointer_width == 64 => true,
-        // Same as for f16, except MacOS is also missing f128 symbols.
+        // Almost all OSs are missing symbol. compiler-builtins will have to add them.
         _ => false,
     };
 
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index 1a18721b15e..f2e523dca77 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -909,8 +909,11 @@ where
     /// Attempts to get mutable references to `N` values in the map at once.
     ///
     /// Returns an array of length `N` with the results of each query. For soundness, at most one
-    /// mutable reference will be returned to any value. `None` will be returned if any of the
-    /// keys are duplicates or missing.
+    /// mutable reference will be returned to any value. `None` will be used if the key is missing.
+    ///
+    /// # Panics
+    ///
+    /// Panics if any keys are overlapping.
     ///
     /// # Examples
     ///
@@ -924,16 +927,23 @@ where
     /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691);
     /// libraries.insert("Library of Congress".to_string(), 1800);
     ///
+    /// // Get Athenæum and Bodleian Library
+    /// let [Some(a), Some(b)] = libraries.get_many_mut([
+    ///     "Athenæum",
+    ///     "Bodleian Library",
+    /// ]) else { panic!() };
+    ///
+    /// // Assert values of Athenæum and Library of Congress
     /// let got = libraries.get_many_mut([
     ///     "Athenæum",
     ///     "Library of Congress",
     /// ]);
     /// assert_eq!(
     ///     got,
-    ///     Some([
-    ///         &mut 1807,
-    ///         &mut 1800,
-    ///     ]),
+    ///     [
+    ///         Some(&mut 1807),
+    ///         Some(&mut 1800),
+    ///     ],
     /// );
     ///
     /// // Missing keys result in None
@@ -941,18 +951,31 @@ where
     ///     "Athenæum",
     ///     "New York Public Library",
     /// ]);
-    /// assert_eq!(got, None);
+    /// assert_eq!(
+    ///     got,
+    ///     [
+    ///         Some(&mut 1807),
+    ///         None
+    ///     ]
+    /// );
+    /// ```
     ///
-    /// // Duplicate keys result in None
+    /// ```should_panic
+    /// #![feature(map_many_mut)]
+    /// use std::collections::HashMap;
+    ///
+    /// let mut libraries = HashMap::new();
+    /// libraries.insert("Athenæum".to_string(), 1807);
+    ///
+    /// // Duplicate keys panic!
     /// let got = libraries.get_many_mut([
     ///     "Athenæum",
     ///     "Athenæum",
     /// ]);
-    /// assert_eq!(got, None);
     /// ```
     #[inline]
     #[unstable(feature = "map_many_mut", issue = "97601")]
-    pub fn get_many_mut<Q: ?Sized, const N: usize>(&mut self, ks: [&Q; N]) -> Option<[&'_ mut V; N]>
+    pub fn get_many_mut<Q: ?Sized, const N: usize>(&mut self, ks: [&Q; N]) -> [Option<&'_ mut V>; N]
     where
         K: Borrow<Q>,
         Q: Hash + Eq,
@@ -963,10 +986,10 @@ where
     /// Attempts to get mutable references to `N` values in the map at once, without validating that
     /// the values are unique.
     ///
-    /// Returns an array of length `N` with the results of each query. `None` will be returned if
-    /// any of the keys are missing.
+    /// Returns an array of length `N` with the results of each query. `None` will be used if
+    /// the key is missing.
     ///
-    /// For a safe alternative see [`get_many_mut`](Self::get_many_mut).
+    /// For a safe alternative see [`get_many_mut`](`HashMap::get_many_mut`).
     ///
     /// # Safety
     ///
@@ -987,31 +1010,39 @@ where
     /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691);
     /// libraries.insert("Library of Congress".to_string(), 1800);
     ///
-    /// let got = libraries.get_many_mut([
+    /// // SAFETY: The keys do not overlap.
+    /// let [Some(a), Some(b)] = (unsafe { libraries.get_many_unchecked_mut([
+    ///     "Athenæum",
+    ///     "Bodleian Library",
+    /// ]) }) else { panic!() };
+    ///
+    /// // SAFETY: The keys do not overlap.
+    /// let got = unsafe { libraries.get_many_unchecked_mut([
     ///     "Athenæum",
     ///     "Library of Congress",
-    /// ]);
+    /// ]) };
     /// assert_eq!(
     ///     got,
-    ///     Some([
-    ///         &mut 1807,
-    ///         &mut 1800,
-    ///     ]),
+    ///     [
+    ///         Some(&mut 1807),
+    ///         Some(&mut 1800),
+    ///     ],
     /// );
     ///
-    /// // Missing keys result in None
-    /// let got = libraries.get_many_mut([
+    /// // SAFETY: The keys do not overlap.
+    /// let got = unsafe { libraries.get_many_unchecked_mut([
     ///     "Athenæum",
     ///     "New York Public Library",
-    /// ]);
-    /// assert_eq!(got, None);
+    /// ]) };
+    /// // Missing keys result in None
+    /// assert_eq!(got, [Some(&mut 1807), None]);
     /// ```
     #[inline]
     #[unstable(feature = "map_many_mut", issue = "97601")]
     pub unsafe fn get_many_unchecked_mut<Q: ?Sized, const N: usize>(
         &mut self,
         ks: [&Q; N],
-    ) -> Option<[&'_ mut V; N]>
+    ) -> [Option<&'_ mut V>; N]
     where
         K: Borrow<Q>,
         Q: Hash + Eq,
@@ -1407,6 +1438,14 @@ impl<K, V> Clone for Iter<'_, K, V> {
     }
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for Iter<'_, K, V> {
+    #[inline]
+    fn default() -> Self {
+        Iter { base: Default::default() }
+    }
+}
+
 #[stable(feature = "std_debug", since = "1.16.0")]
 impl<K: Debug, V: Debug> fmt::Debug for Iter<'_, K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1445,6 +1484,14 @@ impl<'a, K, V> IterMut<'a, K, V> {
     }
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for IterMut<'_, K, V> {
+    #[inline]
+    fn default() -> Self {
+        IterMut { base: Default::default() }
+    }
+}
+
 /// An owning iterator over the entries of a `HashMap`.
 ///
 /// This `struct` is created by the [`into_iter`] method on [`HashMap`]
@@ -1475,6 +1522,14 @@ impl<K, V> IntoIter<K, V> {
     }
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for IntoIter<K, V> {
+    #[inline]
+    fn default() -> Self {
+        IntoIter { base: Default::default() }
+    }
+}
+
 /// An iterator over the keys of a `HashMap`.
 ///
 /// This `struct` is created by the [`keys`] method on [`HashMap`]. See its
@@ -1507,6 +1562,14 @@ impl<K, V> Clone for Keys<'_, K, V> {
     }
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for Keys<'_, K, V> {
+    #[inline]
+    fn default() -> Self {
+        Keys { inner: Default::default() }
+    }
+}
+
 #[stable(feature = "std_debug", since = "1.16.0")]
 impl<K: Debug, V> fmt::Debug for Keys<'_, K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1546,6 +1609,14 @@ impl<K, V> Clone for Values<'_, K, V> {
     }
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for Values<'_, K, V> {
+    #[inline]
+    fn default() -> Self {
+        Values { inner: Default::default() }
+    }
+}
+
 #[stable(feature = "std_debug", since = "1.16.0")]
 impl<K, V: Debug> fmt::Debug for Values<'_, K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1634,6 +1705,14 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
     inner: IterMut<'a, K, V>,
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for ValuesMut<'_, K, V> {
+    #[inline]
+    fn default() -> Self {
+        ValuesMut { inner: Default::default() }
+    }
+}
+
 /// An owning iterator over the keys of a `HashMap`.
 ///
 /// This `struct` is created by the [`into_keys`] method on [`HashMap`].
@@ -1656,6 +1735,14 @@ pub struct IntoKeys<K, V> {
     inner: IntoIter<K, V>,
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for IntoKeys<K, V> {
+    #[inline]
+    fn default() -> Self {
+        IntoKeys { inner: Default::default() }
+    }
+}
+
 /// An owning iterator over the values of a `HashMap`.
 ///
 /// This `struct` is created by the [`into_values`] method on [`HashMap`].
@@ -1678,6 +1765,14 @@ pub struct IntoValues<K, V> {
     inner: IntoIter<K, V>,
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K, V> Default for IntoValues<K, V> {
+    #[inline]
+    fn default() -> Self {
+        IntoValues { inner: Default::default() }
+    }
+}
+
 /// A builder for computing where in a HashMap a key-value pair would be stored.
 ///
 /// See the [`HashMap::raw_entry_mut`] docs for usage examples.
@@ -2978,64 +3073,6 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
     pub fn remove(self) -> V {
         self.base.remove()
     }
-
-    /// Replaces the entry, returning the old key and value. The new key in the hash map will be
-    /// the key used to create this entry.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(map_entry_replace)]
-    /// use std::collections::hash_map::{Entry, HashMap};
-    /// use std::rc::Rc;
-    ///
-    /// let mut map: HashMap<Rc<String>, u32> = HashMap::new();
-    /// map.insert(Rc::new("Stringthing".to_string()), 15);
-    ///
-    /// let my_key = Rc::new("Stringthing".to_string());
-    ///
-    /// if let Entry::Occupied(entry) = map.entry(my_key) {
-    ///     // Also replace the key with a handle to our other key.
-    ///     let (old_key, old_value): (Rc<String>, u32) = entry.replace_entry(16);
-    /// }
-    ///
-    /// ```
-    #[inline]
-    #[unstable(feature = "map_entry_replace", issue = "44286")]
-    pub fn replace_entry(self, value: V) -> (K, V) {
-        self.base.replace_entry(value)
-    }
-
-    /// Replaces the key in the hash map with the key used to create this entry.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(map_entry_replace)]
-    /// use std::collections::hash_map::{Entry, HashMap};
-    /// use std::rc::Rc;
-    ///
-    /// let mut map: HashMap<Rc<String>, u32> = HashMap::new();
-    /// let known_strings: Vec<Rc<String>> = Vec::new();
-    ///
-    /// // Initialise known strings, run program, etc.
-    ///
-    /// reclaim_memory(&mut map, &known_strings);
-    ///
-    /// fn reclaim_memory(map: &mut HashMap<Rc<String>, u32>, known_strings: &[Rc<String>] ) {
-    ///     for s in known_strings {
-    ///         if let Entry::Occupied(entry) = map.entry(Rc::clone(s)) {
-    ///             // Replaces the entry's key with our version of it in `known_strings`.
-    ///             entry.replace_key();
-    ///         }
-    ///     }
-    /// }
-    /// ```
-    #[inline]
-    #[unstable(feature = "map_entry_replace", issue = "44286")]
-    pub fn replace_key(self) -> K {
-        self.base.replace_key()
-    }
 }
 
 impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs
index c28dd7b6b50..fa8ea95b891 100644
--- a/library/std/src/collections/hash/map/tests.rs
+++ b/library/std/src/collections/hash/map/tests.rs
@@ -274,7 +274,7 @@ fn test_lots_of_insertions() {
     for _ in 0..loops {
         assert!(m.is_empty());
 
-        let count = if cfg!(miri) { 101 } else { 1001 };
+        let count = if cfg!(miri) { 66 } else { 1001 };
 
         for i in 1..count {
             assert!(m.insert(i, i).is_none());
@@ -1018,6 +1018,7 @@ mod test_extract_if {
     }
 
     #[test]
+    #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
     fn drop_panic_leak() {
         static PREDS: AtomicUsize = AtomicUsize::new(0);
         static DROPS: AtomicUsize = AtomicUsize::new(0);
@@ -1047,6 +1048,7 @@ mod test_extract_if {
     }
 
     #[test]
+    #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
     fn pred_panic_leak() {
         static PREDS: AtomicUsize = AtomicUsize::new(0);
         static DROPS: AtomicUsize = AtomicUsize::new(0);
@@ -1076,6 +1078,7 @@ mod test_extract_if {
 
     // Same as above, but attempt to use the iterator again after the panic in the predicate
     #[test]
+    #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
     fn pred_panic_reuse() {
         static PREDS: AtomicUsize = AtomicUsize::new(0);
         static DROPS: AtomicUsize = AtomicUsize::new(0);
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs
index 4a113ddea3a..210f5715225 100644
--- a/library/std/src/collections/hash/set.rs
+++ b/library/std/src/collections/hash/set.rs
@@ -724,38 +724,6 @@ where
         self.base.get_or_insert(value)
     }
 
-    /// Inserts an owned copy of the given `value` into the set if it is not
-    /// present, then returns a reference to the value in the set.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(hash_set_entry)]
-    ///
-    /// use std::collections::HashSet;
-    ///
-    /// let mut set: HashSet<String> = ["cat", "dog", "horse"]
-    ///     .iter().map(|&pet| pet.to_owned()).collect();
-    ///
-    /// assert_eq!(set.len(), 3);
-    /// for &pet in &["cat", "dog", "fish"] {
-    ///     let value = set.get_or_insert_owned(pet);
-    ///     assert_eq!(value, pet);
-    /// }
-    /// assert_eq!(set.len(), 4); // a new "fish" was inserted
-    /// ```
-    #[inline]
-    #[unstable(feature = "hash_set_entry", issue = "60896")]
-    pub fn get_or_insert_owned<Q: ?Sized>(&mut self, value: &Q) -> &T
-    where
-        T: Borrow<Q>,
-        Q: Hash + Eq + ToOwned<Owned = T>,
-    {
-        // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with
-        // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`.
-        self.base.get_or_insert_owned(value)
-    }
-
     /// Inserts a value computed from `f` into the set if the given `value` is
     /// not present, then returns a reference to the value in the set.
     ///
@@ -1276,6 +1244,14 @@ pub struct Iter<'a, K: 'a> {
     base: base::Iter<'a, K>,
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K> Default for Iter<'_, K> {
+    #[inline]
+    fn default() -> Self {
+        Iter { base: Default::default() }
+    }
+}
+
 /// An owning iterator over the items of a `HashSet`.
 ///
 /// This `struct` is created by the [`into_iter`] method on [`HashSet`]
@@ -1297,6 +1273,14 @@ pub struct IntoIter<K> {
     base: base::IntoIter<K>,
 }
 
+#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")]
+impl<K> Default for IntoIter<K> {
+    #[inline]
+    fn default() -> Self {
+        IntoIter { base: Default::default() }
+    }
+}
+
 /// A draining iterator over the items of a `HashSet`.
 ///
 /// This `struct` is created by the [`drain`] method on [`HashSet`].
diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs
index 7aa2167e213..8ee8a3e8bf6 100644
--- a/library/std/src/collections/hash/set/tests.rs
+++ b/library/std/src/collections/hash/set/tests.rs
@@ -429,6 +429,7 @@ fn test_extract_if() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_extract_if_drop_panic_leak() {
     static PREDS: AtomicU32 = AtomicU32::new(0);
     static DROPS: AtomicU32 = AtomicU32::new(0);
@@ -459,6 +460,7 @@ fn test_extract_if_drop_panic_leak() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_extract_if_pred_panic_leak() {
     static PREDS: AtomicU32 = AtomicU32::new(0);
     static DROPS: AtomicU32 = AtomicU32::new(0);
diff --git a/library/std/src/env/tests.rs b/library/std/src/env/tests.rs
index fc7aee29733..d0217261068 100644
--- a/library/std/src/env/tests.rs
+++ b/library/std/src/env/tests.rs
@@ -1,7 +1,7 @@
 use super::*;
 
 #[test]
-#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi", target_env = "sgx"), ignore)]
 fn test_self_exe_path() {
     let path = current_exe();
     assert!(path.is_ok());
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index db7867337dd..124ef121b18 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -8,7 +8,15 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 #![deny(unsafe_op_in_unsafe_fn)]
 
-#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx", target_os = "xous"))))]
+#[cfg(all(
+    test,
+    not(any(
+        target_os = "emscripten",
+        target_os = "wasi",
+        target_env = "sgx",
+        target_os = "xous"
+    ))
+))]
 mod tests;
 
 use crate::ffi::OsString;
diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs
index d89ecd317d6..bff0f823c4b 100644
--- a/library/std/src/io/buffered/tests.rs
+++ b/library/std/src/io/buffered/tests.rs
@@ -164,6 +164,7 @@ fn test_buffered_reader_stream_position() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_buffered_reader_stream_position_panic() {
     let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
     let mut reader = BufReader::with_capacity(4, io::Cursor::new(inner));
@@ -487,7 +488,7 @@ fn dont_panic_in_drop_on_panicked_flush() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn panic_in_write_doesnt_flush_in_drop() {
     static WRITES: AtomicUsize = AtomicUsize::new(0);
 
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index 80ba8455df3..a839a2fbac1 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -124,6 +124,7 @@ const TAG_SIMPLE: usize = 0b11;
 /// is_unwind_safe::<std::io::Error>();
 /// ```
 #[repr(transparent)]
+#[rustc_insignificant_dtor]
 pub(super) struct Repr(NonNull<()>, PhantomData<ErrorData<Box<Custom>>>);
 
 // All the types `Repr` stores internally are Send + Sync, and so is it.
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index dd6458c38c6..8fedcb241d0 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -2382,8 +2382,6 @@ pub trait BufRead: Read {
     /// about Ferris from a binary string, skipping the fun fact:
     ///
     /// ```
-    /// #![feature(bufread_skip_until)]
-    ///
     /// use std::io::{self, BufRead};
     ///
     /// let mut cursor = io::Cursor::new(b"Ferris\0Likes long walks on the beach\0Crustacean\0");
@@ -2407,7 +2405,7 @@ pub trait BufRead: Read {
     /// assert_eq!(num_bytes, 11);
     /// assert_eq!(animal, b"Crustacean\0");
     /// ```
-    #[unstable(feature = "bufread_skip_until", issue = "111735")]
+    #[stable(feature = "bufread_skip_until", since = "CURRENT_RUSTC_VERSION")]
     fn skip_until(&mut self, byte: u8) -> Result<usize> {
         skip_until(self, byte)
     }
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 6de069a518e..bf242e715bd 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -394,6 +394,7 @@ impl Stdin {
     ///   in which case it will wait for the Enter key to be pressed before
     ///   continuing
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("get_line")]
     pub fn read_line(&self, buf: &mut String) -> io::Result<usize> {
         self.lock().read_line(buf)
     }
diff --git a/library/std/src/io/stdio/tests.rs b/library/std/src/io/stdio/tests.rs
index ea76a271d12..bf8f3a5adfb 100644
--- a/library/std/src/io/stdio/tests.rs
+++ b/library/std/src/io/stdio/tests.rs
@@ -25,7 +25,7 @@ fn stderrlock_unwind_safe() {
 fn assert_unwind_safe<T: UnwindSafe + RefUnwindSafe>() {}
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn panic_doesnt_poison() {
     thread::spawn(|| {
         let _a = stdin();
@@ -48,17 +48,17 @@ fn panic_doesnt_poison() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn test_lock_stderr() {
     test_lock(stderr, || stderr().lock());
 }
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn test_lock_stdin() {
     test_lock(stdin, || stdin().lock());
 }
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn test_lock_stdout() {
     test_lock(stdout, || stdout().lock());
 }
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index b81e7c18abb..65a9aa66c7c 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -153,7 +153,7 @@
 //! the [`io`], [`fs`], and [`net`] modules.
 //!
 //! The [`thread`] module contains Rust's threading abstractions. [`sync`]
-//! contains further primitive shared memory types, including [`atomic`] and
+//! contains further primitive shared memory types, including [`atomic`], [`mpmc`] and
 //! [`mpsc`], which contains the channel types for message passing.
 //!
 //! # Use before and after `main()`
@@ -177,6 +177,7 @@
 //! - after-main use of thread-locals, which also affects additional features:
 //!   - [`thread::current()`]
 //!   - [`thread::scope()`]
+//!   - [`sync::mpmc`]
 //!   - [`sync::mpsc`]
 //! - before-main stdio file descriptors are not guaranteed to be open on unix platforms
 //!
@@ -202,6 +203,7 @@
 //! [`atomic`]: sync::atomic
 //! [`for`]: ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for
 //! [`str`]: prim@str
+//! [`mpmc`]: sync::mpmc
 //! [`mpsc`]: sync::mpsc
 //! [`std::cmp`]: cmp
 //! [`std::slice`]: mod@slice
diff --git a/library/std/src/net/ip_addr.rs b/library/std/src/net/ip_addr.rs
index 8a9426b61f9..4d673a1d66d 100644
--- a/library/std/src/net/ip_addr.rs
+++ b/library/std/src/net/ip_addr.rs
@@ -1,5 +1,5 @@
 // Tests for this module
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", all(target_os = "wasi", target_env = "p1")))))]
 mod tests;
 
 #[stable(feature = "ip_addr", since = "1.7.0")]
diff --git a/library/std/src/net/socket_addr.rs b/library/std/src/net/socket_addr.rs
index 84922aabdb5..ba9c948a2e9 100644
--- a/library/std/src/net/socket_addr.rs
+++ b/library/std/src/net/socket_addr.rs
@@ -1,5 +1,5 @@
 // Tests for this module
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", all(target_os = "wasi", target_env = "p1")))))]
 mod tests;
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs
index 06ed4f6a03d..67a0f7e439d 100644
--- a/library/std/src/net/tcp.rs
+++ b/library/std/src/net/tcp.rs
@@ -1,6 +1,13 @@
 #![deny(unsafe_op_in_unsafe_fn)]
 
-#[cfg(all(test, not(any(target_os = "emscripten", target_os = "xous"))))]
+#[cfg(all(
+    test,
+    not(any(
+        target_os = "emscripten",
+        all(target_os = "wasi", target_env = "p1"),
+        target_os = "xous"
+    ))
+))]
 mod tests;
 
 use crate::fmt;
@@ -561,7 +568,7 @@ impl TcpStream {
 
     /// Moves this TCP stream into or out of nonblocking mode.
     ///
-    /// This will result in `read`, `write`, `recv` and `send` operations
+    /// This will result in `read`, `write`, `recv` and `send` system operations
     /// becoming nonblocking, i.e., immediately returning from their calls.
     /// If the IO operation is successful, `Ok` is returned and no further
     /// action is required. If the IO operation could not be completed and needs
diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs
index d26517d74e4..a7b5cdf4ec0 100644
--- a/library/std/src/net/tcp/tests.rs
+++ b/library/std/src/net/tcp/tests.rs
@@ -57,6 +57,7 @@ fn connect_timeout_error() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn listen_localhost() {
     let socket_addr = next_test_ip4();
     let listener = t!(TcpListener::bind(&socket_addr));
@@ -73,6 +74,7 @@ fn listen_localhost() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn connect_loopback() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -94,6 +96,7 @@ fn connect_loopback() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn smoke_test() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -114,6 +117,7 @@ fn smoke_test() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn read_eof() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -133,6 +137,7 @@ fn read_eof() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn write_close() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -161,6 +166,7 @@ fn write_close() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn multiple_connect_serial() {
     each_ip(&mut |addr| {
         let max = 10;
@@ -183,6 +189,7 @@ fn multiple_connect_serial() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn multiple_connect_interleaved_greedy_schedule() {
     const MAX: usize = 10;
     each_ip(&mut |addr| {
@@ -220,6 +227,7 @@ fn multiple_connect_interleaved_greedy_schedule() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn multiple_connect_interleaved_lazy_schedule() {
     const MAX: usize = 10;
     each_ip(&mut |addr| {
@@ -255,6 +263,7 @@ fn multiple_connect_interleaved_lazy_schedule() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn socket_and_peer_name() {
     each_ip(&mut |addr| {
         let listener = t!(TcpListener::bind(&addr));
@@ -270,6 +279,7 @@ fn socket_and_peer_name() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn partial_read() {
     each_ip(&mut |addr| {
         let (tx, rx) = channel();
@@ -291,6 +301,7 @@ fn partial_read() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn read_buf() {
     each_ip(&mut |addr| {
         let srv = t!(TcpListener::bind(&addr));
@@ -389,6 +400,7 @@ fn double_bind() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn tcp_clone_smoke() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -420,6 +432,7 @@ fn tcp_clone_smoke() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn tcp_clone_two_read() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -454,6 +467,7 @@ fn tcp_clone_two_read() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn tcp_clone_two_write() {
     each_ip(&mut |addr| {
         let acceptor = t!(TcpListener::bind(&addr));
@@ -483,6 +497,7 @@ fn tcp_clone_two_write() {
 #[test]
 // FIXME: https://github.com/fortanix/rust-sgx/issues/110
 #[cfg_attr(target_env = "sgx", ignore)]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn shutdown_smoke() {
     each_ip(&mut |addr| {
         let a = t!(TcpListener::bind(&addr));
@@ -505,6 +520,7 @@ fn shutdown_smoke() {
 #[test]
 // FIXME: https://github.com/fortanix/rust-sgx/issues/110
 #[cfg_attr(target_env = "sgx", ignore)]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn close_readwrite_smoke() {
     each_ip(&mut |addr| {
         let a = t!(TcpListener::bind(&addr));
@@ -547,6 +563,7 @@ fn close_readwrite_smoke() {
 #[cfg_attr(target_env = "sgx", ignore)]
 // On windows, shutdown will not wake up blocking I/O operations.
 #[cfg_attr(windows, ignore)]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn close_read_wakes_up() {
     each_ip(&mut |addr| {
         let listener = t!(TcpListener::bind(&addr));
@@ -574,6 +591,7 @@ fn close_read_wakes_up() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn clone_while_reading() {
     each_ip(&mut |addr| {
         let accept = t!(TcpListener::bind(&addr));
@@ -614,6 +632,7 @@ fn clone_while_reading() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn clone_accept_smoke() {
     each_ip(&mut |addr| {
         let a = t!(TcpListener::bind(&addr));
@@ -632,6 +651,7 @@ fn clone_accept_smoke() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn clone_accept_concurrent() {
     each_ip(&mut |addr| {
         let a = t!(TcpListener::bind(&addr));
@@ -670,10 +690,10 @@ fn debug() {
         addr.to_string()
     }
 
+    #[cfg(any(unix, target_os = "wasi"))]
+    use crate::os::fd::AsRawFd;
     #[cfg(target_env = "sgx")]
     use crate::os::fortanix_sgx::io::AsRawFd;
-    #[cfg(unix)]
-    use crate::os::unix::io::AsRawFd;
     #[cfg(not(windows))]
     fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug {
         addr.as_raw_fd()
@@ -714,6 +734,7 @@ fn debug() {
     ignore
 )]
 #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 #[test]
 fn timeouts() {
     let addr = next_test_ip4();
@@ -742,6 +763,7 @@ fn timeouts() {
 
 #[test]
 #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 fn test_read_timeout() {
     let addr = next_test_ip4();
     let listener = t!(TcpListener::bind(&addr));
@@ -763,6 +785,7 @@ fn test_read_timeout() {
 
 #[test]
 #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 fn test_read_with_timeout() {
     let addr = next_test_ip4();
     let listener = t!(TcpListener::bind(&addr));
@@ -810,6 +833,7 @@ fn test_timeout_zero_duration() {
 
 #[test]
 #[cfg_attr(target_env = "sgx", ignore)]
+#[cfg_attr(target_os = "wasi", ignore)] // linger not supported
 fn linger() {
     let addr = next_test_ip4();
     let _listener = t!(TcpListener::bind(&addr));
@@ -879,6 +903,7 @@ fn set_nonblocking() {
 
 #[test]
 #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn peek() {
     each_ip(&mut |addr| {
         let (txdone, rxdone) = channel();
diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs
index 8c9e31f9c15..6df47d7b0e0 100644
--- a/library/std/src/net/udp.rs
+++ b/library/std/src/net/udp.rs
@@ -1,4 +1,12 @@
-#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx", target_os = "xous"))))]
+#[cfg(all(
+    test,
+    not(any(
+        target_os = "emscripten",
+        all(target_os = "wasi", target_env = "p1"),
+        target_env = "sgx",
+        target_os = "xous"
+    ))
+))]
 mod tests;
 
 use crate::fmt;
@@ -764,7 +772,7 @@ impl UdpSocket {
 
     /// Moves this UDP socket into or out of nonblocking mode.
     ///
-    /// This will result in `recv`, `recv_from`, `send`, and `send_to`
+    /// This will result in `recv`, `recv_from`, `send`, and `send_to` system
     /// operations becoming nonblocking, i.e., immediately returning from their
     /// calls. If the IO operation is successful, `Ok` is returned and no
     /// further action is required. If the IO operation could not be completed
diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs
index 0cf99366452..1c8c58d1879 100644
--- a/library/std/src/net/udp/tests.rs
+++ b/library/std/src/net/udp/tests.rs
@@ -27,6 +27,7 @@ fn bind_error() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn socket_smoke_test_ip4() {
     each_ip(&mut |server_ip, client_ip| {
         let (tx1, rx1) = channel();
@@ -69,6 +70,7 @@ fn socket_peer() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn udp_clone_smoke() {
     each_ip(&mut |addr1, addr2| {
         let sock1 = t!(UdpSocket::bind(&addr1));
@@ -98,6 +100,7 @@ fn udp_clone_smoke() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn udp_clone_two_read() {
     each_ip(&mut |addr1, addr2| {
         let sock1 = t!(UdpSocket::bind(&addr1));
@@ -130,6 +133,7 @@ fn udp_clone_two_read() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // no threads
 fn udp_clone_two_write() {
     each_ip(&mut |addr1, addr2| {
         let sock1 = t!(UdpSocket::bind(&addr1));
@@ -183,6 +187,7 @@ fn debug() {
     any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks", target_os = "nto"),
     ignore
 )]
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 #[test]
 fn timeouts() {
     let addr = next_test_ip4();
@@ -208,6 +213,7 @@ fn timeouts() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 fn test_read_timeout() {
     let addr = next_test_ip4();
 
@@ -232,6 +238,7 @@ fn test_read_timeout() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported
 fn test_read_with_timeout() {
     let addr = next_test_ip4();
 
@@ -291,6 +298,7 @@ fn connect_send_recv() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // peek not supported
 fn connect_send_peek_recv() {
     each_ip(&mut |addr, _| {
         let socket = t!(UdpSocket::bind(&addr));
@@ -313,6 +321,7 @@ fn connect_send_peek_recv() {
 }
 
 #[test]
+#[cfg_attr(target_os = "wasi", ignore)] // peek_from not supported
 fn peek_from() {
     each_ip(&mut |addr, _| {
         let socket = t!(UdpSocket::bind(&addr));
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index 015cab89485..d649357a56d 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -288,45 +288,55 @@ pub use core::panic::abort_unwind;
 
 /// Invokes a closure, capturing the cause of an unwinding panic if one occurs.
 ///
-/// This function will return `Ok` with the closure's result if the closure
-/// does not panic, and will return `Err(cause)` if the closure panics. The
-/// `cause` returned is the object with which panic was originally invoked.
+/// This function will return `Ok` with the closure's result if the closure does
+/// not panic, and will return `Err(cause)` if the closure panics. The `cause`
+/// returned is the object with which panic was originally invoked.
 ///
-/// It is currently undefined behavior to unwind from Rust code into foreign
-/// code, so this function is particularly useful when Rust is called from
-/// another language (normally C). This can run arbitrary Rust code, capturing a
-/// panic and allowing a graceful handling of the error.
+/// Rust functions that are expected to be called from foreign code that does
+/// not support unwinding (such as C compiled with `-fno-exceptions`) should be
+/// defined using `extern "C"`, which ensures that if the Rust code panics, it
+/// is automatically caught and the process is aborted. If this is the desired
+/// behavior, it is not necessary to use `catch_unwind` explicitly. This
+/// function should instead be used when more graceful error-handling is needed.
 ///
 /// It is **not** recommended to use this function for a general try/catch
 /// mechanism. The [`Result`] type is more appropriate to use for functions that
 /// can fail on a regular basis. Additionally, this function is not guaranteed
 /// to catch all panics, see the "Notes" section below.
 ///
-/// The closure provided is required to adhere to the [`UnwindSafe`] trait to ensure
-/// that all captured variables are safe to cross this boundary. The purpose of
-/// this bound is to encode the concept of [exception safety][rfc] in the type
-/// system. Most usage of this function should not need to worry about this
-/// bound as programs are naturally unwind safe without `unsafe` code. If it
-/// becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to quickly
-/// assert that the usage here is indeed unwind safe.
+/// The closure provided is required to adhere to the [`UnwindSafe`] trait to
+/// ensure that all captured variables are safe to cross this boundary. The
+/// purpose of this bound is to encode the concept of [exception safety][rfc] in
+/// the type system. Most usage of this function should not need to worry about
+/// this bound as programs are naturally unwind safe without `unsafe` code. If
+/// it becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to
+/// quickly assert that the usage here is indeed unwind safe.
 ///
 /// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
 ///
 /// # Notes
 ///
-/// Note that this function **might not catch all panics** in Rust. A panic in
-/// Rust is not always implemented via unwinding, but can be implemented by
-/// aborting the process as well. This function *only* catches unwinding panics,
-/// not those that abort the process.
+/// This function **might not catch all Rust panics**. A Rust panic is not
+/// always implemented via unwinding, but can be implemented by aborting the
+/// process as well. This function *only* catches unwinding panics, not those
+/// that abort the process.
 ///
-/// Note that if a custom panic hook has been set, it will be invoked before
-/// the panic is caught, before unwinding.
+/// If a custom panic hook has been set, it will be invoked before the panic is
+/// caught, before unwinding.
 ///
-/// Also note that unwinding into Rust code with a foreign exception (e.g.
-/// an exception thrown from C++ code) is undefined behavior.
+/// Although unwinding into Rust code with a foreign exception (e.g. an
+/// exception thrown from C++ code, or a `panic!` in Rust code compiled or
+/// linked with a different runtime) via an appropriate ABI (e.g. `"C-unwind"`)
+/// is permitted, catching such an exception using this function will have one
+/// of two behaviors, and it is unspecified which will occur:
 ///
-/// Finally, be **careful in how you drop the result of this function**.
-/// If it is `Err`, it contains the panic payload, and dropping that may in turn panic!
+/// * The process aborts, after executing all destructors of `f` and the
+///   functions it called.
+/// * The function returns a `Result::Err` containing an opaque type.
+///
+/// Finally, be **careful in how you drop the result of this function**. If it
+/// is `Err`, it contains the panic payload, and dropping that may in turn
+/// panic!
 ///
 /// # Examples
 ///
diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs
index 6436872087d..b75793d2bc9 100644
--- a/library/std/src/path/tests.rs
+++ b/library/std/src/path/tests.rs
@@ -139,7 +139,7 @@ fn test_pathbuf_leak() {
 }
 
 #[test]
-#[cfg(unix)]
+#[cfg(any(unix, target_os = "wasi"))]
 pub fn test_decompositions_unix() {
     t!("",
     iter: [],
@@ -1201,7 +1201,10 @@ pub fn test_push() {
         });
     );
 
-    if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) {
+    if cfg!(unix)
+        || cfg!(target_os = "wasi")
+        || cfg!(all(target_env = "sgx", target_vendor = "fortanix"))
+    {
         tp!("", "foo", "foo");
         tp!("foo", "bar", "foo/bar");
         tp!("foo/", "bar", "foo/bar");
@@ -1358,7 +1361,10 @@ pub fn test_set_file_name() {
     tfn!("foo", "bar", "bar");
     tfn!("foo", "", "");
     tfn!("", "foo", "foo");
-    if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) {
+    if cfg!(unix)
+        || cfg!(target_os = "wasi")
+        || cfg!(all(target_env = "sgx", target_vendor = "fortanix"))
+    {
         tfn!(".", "foo", "./foo");
         tfn!("foo/", "bar", "bar");
         tfn!("foo/.", "bar", "bar");
@@ -1758,7 +1764,7 @@ fn test_components_debug() {
     assert_eq!(expected, actual);
 }
 
-#[cfg(unix)]
+#[cfg(any(unix, target_os = "wasi"))]
 #[test]
 fn test_iter_debug() {
     let path = Path::new("/tmp");
@@ -1859,7 +1865,7 @@ fn test_ord() {
 }
 
 #[test]
-#[cfg(unix)]
+#[cfg(any(unix, target_os = "wasi"))]
 fn test_unix_absolute() {
     use crate::path::absolute;
 
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index c84a5c65263..f24fe353e55 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -148,7 +148,15 @@
 #![stable(feature = "process", since = "1.0.0")]
 #![deny(unsafe_op_in_unsafe_fn)]
 
-#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx", target_os = "xous"))))]
+#[cfg(all(
+    test,
+    not(any(
+        target_os = "emscripten",
+        target_os = "wasi",
+        target_env = "sgx",
+        target_os = "xous"
+    ))
+))]
 mod tests;
 
 use crate::convert::Infallible;
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index b6f36931ec2..0a841f07e3b 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -21,9 +21,10 @@ pub use crate::panicking::{begin_panic, panic_count};
 pub use core::panicking::{panic_display, panic_fmt};
 
 #[rustfmt::skip]
+use crate::any::Any;
 use crate::sync::Once;
-use crate::sys;
 use crate::thread::{self, Thread};
+use crate::{mem, panic, sys};
 
 // Prints to the "panic output", depending on the platform this may be:
 // - the standard error output
@@ -66,6 +67,11 @@ macro_rules! rtunwrap {
     };
 }
 
+fn handle_rt_panic(e: Box<dyn Any + Send>) {
+    mem::forget(e);
+    rtabort!("initialization or cleanup bug");
+}
+
 // One-time runtime initialization.
 // Runs before `main`.
 // SAFETY: must be called only once during runtime initialization.
@@ -101,6 +107,20 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
     thread::set_current(thread);
 }
 
+/// Clean up the thread-local runtime state. This *should* be run after all other
+/// code managed by the Rust runtime, but will not cause UB if that condition is
+/// not fulfilled. Also note that this function is not guaranteed to be run, but
+/// skipping it will cause leaks and therefore is to be avoided.
+pub(crate) fn thread_cleanup() {
+    // This function is run in situations where unwinding leads to an abort
+    // (think `extern "C"` functions). Abort here instead so that we can
+    // print a nice message.
+    panic::catch_unwind(|| {
+        crate::thread::drop_current();
+    })
+    .unwrap_or_else(handle_rt_panic);
+}
+
 // One-time runtime cleanup.
 // Runs after `main` or at program exit.
 // NOTE: this is not guaranteed to run, for example when the program aborts.
@@ -123,11 +143,6 @@ fn lang_start_internal(
     argv: *const *const u8,
     sigpipe: u8,
 ) -> Result<isize, !> {
-    use crate::{mem, panic};
-    let rt_abort = move |e| {
-        mem::forget(e);
-        rtabort!("initialization or cleanup bug");
-    };
     // Guard against the code called by this function from unwinding outside of the Rust-controlled
     // code, which is UB. This is a requirement imposed by a combination of how the
     // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking
@@ -139,16 +154,17 @@ fn lang_start_internal(
     // prevent std from accidentally introducing a panic to these functions. Another is from
     // user code from `main` or, more nefariously, as described in e.g. issue #86030.
     // SAFETY: Only called once during runtime initialization.
-    panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?;
+    panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) })
+        .unwrap_or_else(handle_rt_panic);
     let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)
         .map_err(move |e| {
             mem::forget(e);
             rtabort!("drop of the panic payload panicked");
         });
-    panic::catch_unwind(cleanup).map_err(rt_abort)?;
+    panic::catch_unwind(cleanup).unwrap_or_else(handle_rt_panic);
     // Guard against multiple threads calling `libc::exit` concurrently.
     // See the documentation for `unique_thread_exit` for more information.
-    panic::catch_unwind(|| crate::sys::exit_guard::unique_thread_exit()).map_err(rt_abort)?;
+    panic::catch_unwind(crate::sys::exit_guard::unique_thread_exit).unwrap_or_else(handle_rt_panic);
     ret_code
 }
 
diff --git a/library/std/src/sync/barrier/tests.rs b/library/std/src/sync/barrier/tests.rs
index c5620cd91d8..0fbcd998812 100644
--- a/library/std/src/sync/barrier/tests.rs
+++ b/library/std/src/sync/barrier/tests.rs
@@ -3,7 +3,7 @@ use crate::sync::{Arc, Barrier};
 use crate::thread;
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn test_barrier() {
     const N: usize = 10;
 
diff --git a/library/std/src/sync/condvar/tests.rs b/library/std/src/sync/condvar/tests.rs
index 12d13a6b20b..f9e9066bc92 100644
--- a/library/std/src/sync/condvar/tests.rs
+++ b/library/std/src/sync/condvar/tests.rs
@@ -12,7 +12,7 @@ fn smoke() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn notify_one() {
     let m = Arc::new(Mutex::new(()));
     let m2 = m.clone();
@@ -29,7 +29,7 @@ fn notify_one() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn notify_all() {
     const N: usize = 10;
 
@@ -66,7 +66,7 @@ fn notify_all() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn wait_while() {
     let pair = Arc::new((Mutex::new(false), Condvar::new()));
     let pair2 = pair.clone();
@@ -87,7 +87,7 @@ fn wait_while() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported
 fn wait_timeout_wait() {
     let m = Arc::new(Mutex::new(()));
     let c = Arc::new(Condvar::new());
@@ -106,7 +106,7 @@ fn wait_timeout_wait() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported
 fn wait_timeout_while_wait() {
     let m = Arc::new(Mutex::new(()));
     let c = Arc::new(Condvar::new());
@@ -118,7 +118,7 @@ fn wait_timeout_while_wait() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported
 fn wait_timeout_while_instant_satisfy() {
     let m = Arc::new(Mutex::new(()));
     let c = Arc::new(Condvar::new());
@@ -130,7 +130,7 @@ fn wait_timeout_while_instant_satisfy() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn wait_timeout_while_wake() {
     let pair = Arc::new((Mutex::new(false), Condvar::new()));
     let pair_copy = pair.clone();
@@ -153,7 +153,7 @@ fn wait_timeout_while_wake() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn wait_timeout_wake() {
     let m = Arc::new(Mutex::new(()));
     let c = Arc::new(Condvar::new());
diff --git a/library/std/src/sync/lazy_lock/tests.rs b/library/std/src/sync/lazy_lock/tests.rs
index 94044368305..7d7dde54349 100644
--- a/library/std/src/sync/lazy_lock/tests.rs
+++ b/library/std/src/sync/lazy_lock/tests.rs
@@ -34,6 +34,7 @@ fn lazy_default() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn lazy_poisoning() {
     let x: LazyCell<String> = LazyCell::new(|| panic!("kaboom"));
     for _ in 0..2 {
@@ -43,7 +44,7 @@ fn lazy_poisoning() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn sync_lazy_new() {
     static CALLED: AtomicUsize = AtomicUsize::new(0);
     static SYNC_LAZY: LazyLock<i32> = LazyLock::new(|| {
@@ -90,7 +91,7 @@ fn sync_lazy_default() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn static_sync_lazy() {
     static XS: LazyLock<Vec<i32>> = LazyLock::new(|| {
         let mut xs = Vec::new();
@@ -123,6 +124,7 @@ fn static_sync_lazy_via_fn() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn sync_lazy_poisoning() {
     let x: LazyLock<String> = LazyLock::new(|| panic!("kaboom"));
     for _ in 0..2 {
diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs
index 0fb8e669bf8..0fb77331293 100644
--- a/library/std/src/sync/mod.rs
+++ b/library/std/src/sync/mod.rs
@@ -133,6 +133,11 @@
 //!   inter-thread synchronisation mechanism, at the cost of some
 //!   extra memory.
 //!
+//! - [`mpmc`]: Multi-producer, multi-consumer queues, used for
+//!   message-based communication. Can provide a lightweight
+//!   inter-thread synchronisation mechanism, at the cost of some
+//!   extra memory.
+//!
 //! - [`Mutex`]: Mutual Exclusion mechanism, which ensures that at
 //!   most one thread at a time is able to access some data.
 //!
@@ -153,6 +158,7 @@
 //! [`Arc`]: crate::sync::Arc
 //! [`Barrier`]: crate::sync::Barrier
 //! [`Condvar`]: crate::sync::Condvar
+//! [`mpmc`]: crate::sync::mpmc
 //! [`mpsc`]: crate::sync::mpsc
 //! [`Mutex`]: crate::sync::Mutex
 //! [`Once`]: crate::sync::Once
@@ -193,12 +199,13 @@ pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+pub mod mpmc;
 pub mod mpsc;
 
 mod barrier;
 mod condvar;
 mod lazy_lock;
-mod mpmc;
 mod mutex;
 pub(crate) mod once;
 mod once_lock;
diff --git a/library/std/src/sync/mpmc/error.rs b/library/std/src/sync/mpmc/error.rs
index e3aec7e7623..e34b56d0831 100644
--- a/library/std/src/sync/mpmc/error.rs
+++ b/library/std/src/sync/mpmc/error.rs
@@ -7,6 +7,7 @@ use crate::{error, fmt};
 ///
 /// [`send_timeout`]: super::Sender::send_timeout
 #[derive(PartialEq, Eq, Clone, Copy)]
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 pub enum SendTimeoutError<T> {
     /// The message could not be sent because the channel is full and the operation timed out.
     ///
@@ -18,12 +19,14 @@ pub enum SendTimeoutError<T> {
     Disconnected(T),
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> fmt::Debug for SendTimeoutError<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         "SendTimeoutError(..)".fmt(f)
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> fmt::Display for SendTimeoutError<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
@@ -33,8 +36,10 @@ impl<T> fmt::Display for SendTimeoutError<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> error::Error for SendTimeoutError<T> {}
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> From<SendError<T>> for SendTimeoutError<T> {
     fn from(err: SendError<T>) -> SendTimeoutError<T> {
         match err {
diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs
index c640e07348e..44e146a89ba 100644
--- a/library/std/src/sync/mpmc/mod.rs
+++ b/library/std/src/sync/mpmc/mod.rs
@@ -1,8 +1,114 @@
-//! Multi-producer multi-consumer channels.
+//! Multi-producer, multi-consumer FIFO queue communication primitives.
+//!
+//! This module provides message-based communication over channels, concretely
+//! defined by two types:
+//!
+//! * [`Sender`]
+//! * [`Receiver`]
+//!
+//! [`Sender`]s are used to send data to a set of [`Receiver`]s. Both
+//! sender and receiver are cloneable (multi-producer) such that many threads can send
+//! simultaneously to receivers (multi-consumer).
+//!
+//! These channels come in two flavors:
+//!
+//! 1. An asynchronous, infinitely buffered channel. The [`channel`] function
+//!    will return a `(Sender, Receiver)` tuple where all sends will be
+//!    **asynchronous** (they never block). The channel conceptually has an
+//!    infinite buffer.
+//!
+//! 2. A synchronous, bounded channel. The [`sync_channel`] function will
+//!    return a `(SyncSender, Receiver)` tuple where the storage for pending
+//!    messages is a pre-allocated buffer of a fixed size. All sends will be
+//!    **synchronous** by blocking until there is buffer space available. Note
+//!    that a bound of 0 is allowed, causing the channel to become a "rendezvous"
+//!    channel where each sender atomically hands off a message to a receiver.
+//!
+//! [`send`]: Sender::send
+//!
+//! ## Disconnection
+//!
+//! The send and receive operations on channels will all return a [`Result`]
+//! indicating whether the operation succeeded or not. An unsuccessful operation
+//! is normally indicative of the other half of a channel having "hung up" by
+//! being dropped in its corresponding thread.
+//!
+//! Once half of a channel has been deallocated, most operations can no longer
+//! continue to make progress, so [`Err`] will be returned. Many applications
+//! will continue to [`unwrap`] the results returned from this module,
+//! instigating a propagation of failure among threads if one unexpectedly dies.
+//!
+//! [`unwrap`]: Result::unwrap
+//!
+//! # Examples
+//!
+//! Simple usage:
+//!
+//! ```
+//! #![feature(mpmc_channel)]
+//!
+//! use std::thread;
+//! use std::sync::mpmc::channel;
+//!
+//! // Create a simple streaming channel
+//! let (tx, rx) = channel();
+//! thread::spawn(move || {
+//!     tx.send(10).unwrap();
+//! });
+//! assert_eq!(rx.recv().unwrap(), 10);
+//! ```
+//!
+//! Shared usage:
+//!
+//! ```
+//! #![feature(mpmc_channel)]
+//!
+//! use std::thread;
+//! use std::sync::mpmc::channel;
+//!
+//! thread::scope(|s| {
+//!     // Create a shared channel that can be sent along from many threads
+//!     // where tx is the sending half (tx for transmission), and rx is the receiving
+//!     // half (rx for receiving).
+//!     let (tx, rx) = channel();
+//!     for i in 0..10 {
+//!         let tx = tx.clone();
+//!         s.spawn(move || {
+//!             tx.send(i).unwrap();
+//!         });
+//!     }
+//!
+//!     for _ in 0..5 {
+//!         let rx1 = rx.clone();
+//!         let rx2 = rx.clone();
+//!         s.spawn(move || {
+//!             let j = rx1.recv().unwrap();
+//!             assert!(0 <= j && j < 10);
+//!         });
+//!         s.spawn(move || {
+//!             let j = rx2.recv().unwrap();
+//!             assert!(0 <= j && j < 10);
+//!         });
+//!     }
+//! })
+//! ```
+//!
+//! Propagating panics:
+//!
+//! ```
+//! #![feature(mpmc_channel)]
+//!
+//! use std::sync::mpmc::channel;
+//!
+//! // The call to recv() will return an error because the channel has already
+//! // hung up (or been deallocated)
+//! let (tx, rx) = channel::<i32>();
+//! drop(tx);
+//! assert!(rx.recv().is_err());
+//! ```
 
-// This module is not currently exposed publicly, but is used
-// as the implementation for the channels in `sync::mpsc`. The
-// implementation comes from the crossbeam-channel crate:
+// This module is used as the implementation for the channels in `sync::mpsc`.
+// The implementation comes from the crossbeam-channel crate:
 //
 // Copyright (c) 2019 The Crossbeam Project Developers
 //
@@ -46,9 +152,47 @@ use crate::fmt;
 use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::time::{Duration, Instant};
 
-/// Creates a channel of unbounded capacity.
+/// Creates a new asynchronous channel, returning the sender/receiver halves.
+/// All data sent on the [`Sender`] will become available on the [`Receiver`] in
+/// the same order as it was sent, and no [`send`] will block the calling thread
+/// (this channel has an "infinite buffer", unlike [`sync_channel`], which will
+/// block after its buffer limit is reached). [`recv`] will block until a message
+/// is available while there is at least one [`Sender`] alive (including clones).
 ///
-/// This channel has a growable buffer that can hold any number of messages at a time.
+/// The [`Sender`] can be cloned to [`send`] to the same channel multiple times.
+/// The [`Receiver`] also can be cloned to have multi receivers.
+///
+/// If the [`Receiver`] is disconnected while trying to [`send`] with the
+/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, if the
+/// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will
+/// return a [`RecvError`].
+///
+/// [`send`]: Sender::send
+/// [`recv`]: Receiver::recv
+///
+/// # Examples
+///
+/// ```
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+///
+/// let (sender, receiver) = channel();
+///
+/// // Spawn off an expensive computation
+/// thread::spawn(move || {
+/// #   fn expensive_computation() {}
+///     sender.send(expensive_computation()).unwrap();
+/// });
+///
+/// // Do some useful work for awhile
+///
+/// // Let's see what that answer was
+/// println!("{:?}", receiver.recv().unwrap());
+/// ```
+#[must_use]
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
     let (s, r) = counter::new(list::Channel::new());
     let s = Sender { flavor: SenderFlavor::List(s) };
@@ -56,12 +200,50 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
     (s, r)
 }
 
-/// Creates a channel of bounded capacity.
+/// Creates a new synchronous, bounded channel.
+/// All data sent on the [`Sender`] will become available on the [`Receiver`]
+/// in the same order as it was sent. Like asynchronous [`channel`]s, the
+/// [`Receiver`] will block until a message becomes available. `sync_channel`
+/// differs greatly in the semantics of the sender, however.
+///
+/// This channel has an internal buffer on which messages will be queued.
+/// `bound` specifies the buffer size. When the internal buffer becomes full,
+/// future sends will *block* waiting for the buffer to open up. Note that a
+/// buffer size of 0 is valid, in which case this becomes "rendezvous channel"
+/// where each [`send`] will not return until a [`recv`] is paired with it.
+///
+/// The [`Sender`] can be cloned to [`send`] to the same channel multiple
+/// times. The [`Receiver`] also can be cloned to have multi receivers.
+///
+/// Like asynchronous channels, if the [`Receiver`] is disconnected while trying
+/// to [`send`] with the [`Sender`], the [`send`] method will return a
+/// [`SendError`]. Similarly, If the [`Sender`] is disconnected while trying
+/// to [`recv`], the [`recv`] method will return a [`RecvError`].
+///
+/// [`send`]: Sender::send
+/// [`recv`]: Receiver::recv
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::mpsc::sync_channel;
+/// use std::thread;
+///
+/// let (sender, receiver) = sync_channel(1);
 ///
-/// This channel has a buffer that can hold at most `cap` messages at a time.
+/// // this returns immediately
+/// sender.send(1).unwrap();
 ///
-/// A special case is zero-capacity channel, which cannot hold any messages. Instead, send and
-/// receive operations must appear at the same time in order to pair up and pass the message over.
+/// thread::spawn(move || {
+///     // this will block until the previous message has been received
+///     sender.send(2).unwrap();
+/// });
+///
+/// assert_eq!(receiver.recv().unwrap(), 1);
+/// assert_eq!(receiver.recv().unwrap(), 2);
+/// ```
+#[must_use]
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 pub fn sync_channel<T>(cap: usize) -> (Sender<T>, Receiver<T>) {
     if cap == 0 {
         let (s, r) = counter::new(zero::Channel::new());
@@ -76,7 +258,42 @@ pub fn sync_channel<T>(cap: usize) -> (Sender<T>, Receiver<T>) {
     }
 }
 
-/// The sending side of a channel.
+/// The sending-half of Rust's synchronous [`channel`] type.
+///
+/// Messages can be sent through this channel with [`send`].
+///
+/// Note: all senders (the original and its clones) need to be dropped for the receiver
+/// to stop blocking to receive messages with [`Receiver::recv`].
+///
+/// [`send`]: Sender::send
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+///
+/// let (sender, receiver) = channel();
+/// let sender2 = sender.clone();
+///
+/// // First thread owns sender
+/// thread::spawn(move || {
+///     sender.send(1).unwrap();
+/// });
+///
+/// // Second thread owns sender2
+/// thread::spawn(move || {
+///     sender2.send(2).unwrap();
+/// });
+///
+/// let msg = receiver.recv().unwrap();
+/// let msg2 = receiver.recv().unwrap();
+///
+/// assert_eq!(3, msg + msg2);
+/// ```
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 pub struct Sender<T> {
     flavor: SenderFlavor<T>,
 }
@@ -93,10 +310,14 @@ enum SenderFlavor<T> {
     Zero(counter::Sender<zero::Channel<T>>),
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 unsafe impl<T: Send> Send for Sender<T> {}
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 unsafe impl<T: Send> Sync for Sender<T> {}
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> UnwindSafe for Sender<T> {}
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> RefUnwindSafe for Sender<T> {}
 
 impl<T> Sender<T> {
@@ -107,6 +328,19 @@ impl<T> Sender<T> {
     ///
     /// If called on a zero-capacity channel, this method will send the message only if there
     /// happens to be a receive operation on the other side of the channel at the same time.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::{channel, Receiver, Sender};
+    ///
+    /// let (sender, _receiver): (Sender<i32>, Receiver<i32>) = channel();
+    ///
+    /// assert!(sender.try_send(1).is_ok());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.try_send(msg),
@@ -115,14 +349,36 @@ impl<T> Sender<T> {
         }
     }
 
-    /// Blocks the current thread until a message is sent or the channel is disconnected.
+    /// Attempts to send a value on this channel, returning it back if it could
+    /// not be sent.
     ///
-    /// If the channel is full and not disconnected, this call will block until the send operation
-    /// can proceed. If the channel becomes disconnected, this call will wake up and return an
-    /// error. The returned error contains the original message.
+    /// A successful send occurs when it is determined that the other end of
+    /// the channel has not hung up already. An unsuccessful send would be one
+    /// where the corresponding receiver has already been deallocated. Note
+    /// that a return value of [`Err`] means that the data will never be
+    /// received, but a return value of [`Ok`] does *not* mean that the data
+    /// will be received. It is possible for the corresponding receiver to
+    /// hang up immediately after this function returns [`Ok`].
     ///
-    /// If called on a zero-capacity channel, this method will wait for a receive operation to
-    /// appear on the other side of the channel.
+    /// This method will never block the current thread.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    ///
+    /// let (tx, rx) = channel();
+    ///
+    /// // This send is always successful
+    /// tx.send(1).unwrap();
+    ///
+    /// // This send will fail because the receiver is gone
+    /// drop(rx);
+    /// assert!(tx.send(1).is_err());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn send(&self, msg: T) -> Result<(), SendError<T>> {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.send(msg, None),
@@ -136,10 +392,6 @@ impl<T> Sender<T> {
     }
 }
 
-// The methods below are not used by `sync::mpsc`, but
-// are useful and we'll likely want to expose them
-// eventually
-#[allow(unused)]
 impl<T> Sender<T> {
     /// Waits for a message to be sent into the channel, but only for a limited time.
     ///
@@ -149,6 +401,20 @@ impl<T> Sender<T> {
     ///
     /// If called on a zero-capacity channel, this method will wait for a receive operation to
     /// appear on the other side of the channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    /// use std::time::Duration;
+    ///
+    /// let (tx, rx) = channel();
+    ///
+    /// tx.send_timeout(1, Duration::from_millis(400)).unwrap();
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn send_timeout(&self, msg: T, timeout: Duration) -> Result<(), SendTimeoutError<T>> {
         match Instant::now().checked_add(timeout) {
             Some(deadline) => self.send_deadline(msg, deadline),
@@ -165,6 +431,21 @@ impl<T> Sender<T> {
     ///
     /// If called on a zero-capacity channel, this method will wait for a receive operation to
     /// appear on the other side of the channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    /// use std::time::{Duration, Instant};
+    ///
+    /// let (tx, rx) = channel();
+    ///
+    /// let t = Instant::now() + Duration::from_millis(400);
+    /// tx.send_deadline(1, t).unwrap();
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn send_deadline(&self, msg: T, deadline: Instant) -> Result<(), SendTimeoutError<T>> {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.send(msg, Some(deadline)),
@@ -176,6 +457,31 @@ impl<T> Sender<T> {
     /// Returns `true` if the channel is empty.
     ///
     /// Note: Zero-capacity channels are always empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, _recv) = mpmc::channel();
+    ///
+    /// let tx1 = send.clone();
+    /// let tx2 = send.clone();
+    ///
+    /// assert!(tx1.is_empty());
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     tx2.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert!(!tx1.is_empty());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn is_empty(&self) -> bool {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.is_empty(),
@@ -187,6 +493,29 @@ impl<T> Sender<T> {
     /// Returns `true` if the channel is full.
     ///
     /// Note: Zero-capacity channels are always full.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, _recv) = mpmc::sync_channel(1);
+    ///
+    /// let (tx1, tx2) = (send.clone(), send.clone());
+    /// assert!(!tx1.is_full());
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     tx2.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert!(tx1.is_full());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn is_full(&self) -> bool {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.is_full(),
@@ -196,6 +525,29 @@ impl<T> Sender<T> {
     }
 
     /// Returns the number of messages in the channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, _recv) = mpmc::channel();
+    /// let (tx1, tx2) = (send.clone(), send.clone());
+    ///
+    /// assert_eq!(tx1.len(), 0);
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     tx2.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(tx1.len(), 1);
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn len(&self) -> usize {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.len(),
@@ -205,6 +557,29 @@ impl<T> Sender<T> {
     }
 
     /// If the channel is bounded, returns its capacity.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, _recv) = mpmc::sync_channel(3);
+    /// let (tx1, tx2) = (send.clone(), send.clone());
+    ///
+    /// assert_eq!(tx1.capacity(), Some(3));
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     tx2.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(tx1.capacity(), Some(3));
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn capacity(&self) -> Option<usize> {
         match &self.flavor {
             SenderFlavor::Array(chan) => chan.capacity(),
@@ -214,6 +589,21 @@ impl<T> Sender<T> {
     }
 
     /// Returns `true` if senders belong to the same channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    ///
+    /// let (tx1, _) = mpmc::channel::<i32>();
+    /// let (tx2, _) = mpmc::channel::<i32>();
+    ///
+    /// assert!(tx1.same_channel(&tx1));
+    /// assert!(!tx1.same_channel(&tx2));
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn same_channel(&self, other: &Sender<T>) -> bool {
         match (&self.flavor, &other.flavor) {
             (SenderFlavor::Array(ref a), SenderFlavor::Array(ref b)) => a == b,
@@ -224,6 +614,7 @@ impl<T> Sender<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> Drop for Sender<T> {
     fn drop(&mut self) {
         unsafe {
@@ -236,6 +627,7 @@ impl<T> Drop for Sender<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> Clone for Sender<T> {
     fn clone(&self) -> Self {
         let flavor = match &self.flavor {
@@ -248,17 +640,216 @@ impl<T> Clone for Sender<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> fmt::Debug for Sender<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.pad("Sender { .. }")
     }
 }
 
-/// The receiving side of a channel.
+/// The receiving half of Rust's [`channel`] (or [`sync_channel`]) type.
+/// Different threads can share this [`Sender`] by cloning it.
+///
+/// Messages sent to the channel can be retrieved using [`recv`].
+///
+/// [`recv`]: Receiver::recv
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+/// use std::time::Duration;
+///
+/// let (send, recv) = channel();
+///
+/// let tx_thread = thread::spawn(move || {
+///     send.send("Hello world!").unwrap();
+///     thread::sleep(Duration::from_secs(2)); // block for two seconds
+///     send.send("Delayed for 2 seconds").unwrap();
+/// });
+///
+/// let (rx1, rx2) = (recv.clone(), recv.clone());
+/// let rx_thread_1 = thread::spawn(move || {
+///     println!("{}", rx1.recv().unwrap()); // Received immediately
+/// });
+/// let rx_thread_2 = thread::spawn(move || {
+///     println!("{}", rx2.recv().unwrap()); // Received after 2 seconds
+/// });
+///
+/// tx_thread.join().unwrap();
+/// rx_thread_1.join().unwrap();
+/// rx_thread_2.join().unwrap();
+/// ```
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 pub struct Receiver<T> {
     flavor: ReceiverFlavor<T>,
 }
 
+/// An iterator over messages on a [`Receiver`], created by [`iter`].
+///
+/// This iterator will block whenever [`next`] is called,
+/// waiting for a new message, and [`None`] will be returned
+/// when the corresponding channel has hung up.
+///
+/// [`iter`]: Receiver::iter
+/// [`next`]: Iterator::next
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+///
+/// let (send, recv) = channel();
+///
+/// thread::spawn(move || {
+///     send.send(1u8).unwrap();
+///     send.send(2u8).unwrap();
+///     send.send(3u8).unwrap();
+/// });
+///
+/// for x in recv.iter() {
+///     println!("Got: {x}");
+/// }
+/// ```
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+#[derive(Debug)]
+pub struct Iter<'a, T: 'a> {
+    rx: &'a Receiver<T>,
+}
+
+/// An iterator that attempts to yield all pending values for a [`Receiver`],
+/// created by [`try_iter`].
+///
+/// [`None`] will be returned when there are no pending values remaining or
+/// if the corresponding channel has hung up.
+///
+/// This iterator will never block the caller in order to wait for data to
+/// become available. Instead, it will return [`None`].
+///
+/// [`try_iter`]: Receiver::try_iter
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+/// use std::time::Duration;
+///
+/// let (sender, receiver) = channel();
+///
+/// // Nothing is in the buffer yet
+/// assert!(receiver.try_iter().next().is_none());
+/// println!("Nothing in the buffer...");
+///
+/// thread::spawn(move || {
+///     sender.send(1).unwrap();
+///     sender.send(2).unwrap();
+///     sender.send(3).unwrap();
+/// });
+///
+/// println!("Going to sleep...");
+/// thread::sleep(Duration::from_secs(2)); // block for two seconds
+///
+/// for x in receiver.try_iter() {
+///     println!("Got: {x}");
+/// }
+/// ```
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+#[derive(Debug)]
+pub struct TryIter<'a, T: 'a> {
+    rx: &'a Receiver<T>,
+}
+
+/// An owning iterator over messages on a [`Receiver`],
+/// created by [`into_iter`].
+///
+/// This iterator will block whenever [`next`]
+/// is called, waiting for a new message, and [`None`] will be
+/// returned if the corresponding channel has hung up.
+///
+/// [`into_iter`]: Receiver::into_iter
+/// [`next`]: Iterator::next
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(mpmc_channel)]
+///
+/// use std::sync::mpmc::channel;
+/// use std::thread;
+///
+/// let (send, recv) = channel();
+///
+/// thread::spawn(move || {
+///     send.send(1u8).unwrap();
+///     send.send(2u8).unwrap();
+///     send.send(3u8).unwrap();
+/// });
+///
+/// for x in recv.into_iter() {
+///     println!("Got: {x}");
+/// }
+/// ```
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+#[derive(Debug)]
+pub struct IntoIter<T> {
+    rx: Receiver<T>,
+}
+
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+impl<'a, T> Iterator for Iter<'a, T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> {
+        self.rx.recv().ok()
+    }
+}
+
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+impl<'a, T> Iterator for TryIter<'a, T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> {
+        self.rx.try_recv().ok()
+    }
+}
+
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+impl<'a, T> IntoIterator for &'a Receiver<T> {
+    type Item = T;
+    type IntoIter = Iter<'a, T>;
+
+    fn into_iter(self) -> Iter<'a, T> {
+        self.iter()
+    }
+}
+
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+impl<T> Iterator for IntoIter<T> {
+    type Item = T;
+    fn next(&mut self) -> Option<T> {
+        self.rx.recv().ok()
+    }
+}
+
+#[unstable(feature = "mpmc_channel", issue = "126840")]
+impl<T> IntoIterator for Receiver<T> {
+    type Item = T;
+    type IntoIter = IntoIter<T>;
+
+    fn into_iter(self) -> IntoIter<T> {
+        IntoIter { rx: self }
+    }
+}
+
 /// Receiver flavors.
 enum ReceiverFlavor<T> {
     /// Bounded channel based on a preallocated array.
@@ -271,20 +862,46 @@ enum ReceiverFlavor<T> {
     Zero(counter::Receiver<zero::Channel<T>>),
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 unsafe impl<T: Send> Send for Receiver<T> {}
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 unsafe impl<T: Send> Sync for Receiver<T> {}
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> UnwindSafe for Receiver<T> {}
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> RefUnwindSafe for Receiver<T> {}
 
 impl<T> Receiver<T> {
     /// Attempts to receive a message from the channel without blocking.
     ///
-    /// This method will either receive a message from the channel immediately or return an error
-    /// if the channel is empty.
+    /// This method will never block the caller in order to wait for data to
+    /// become available. Instead, this will always return immediately with a
+    /// possible option of pending data on the channel.
     ///
     /// If called on a zero-capacity channel, this method will receive a message only if there
     /// happens to be a send operation on the other side of the channel at the same time.
+    ///
+    /// This is useful for a flavor of "optimistic check" before deciding to
+    /// block on a receiver.
+    ///
+    /// Compared with [`recv`], this function has two failure cases instead of one
+    /// (one for disconnection, one for an empty buffer).
+    ///
+    /// [`recv`]: Self::recv
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::{Receiver, channel};
+    ///
+    /// let (_, receiver): (_, Receiver<i32>) = channel();
+    ///
+    /// assert!(receiver.try_recv().is_err());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn try_recv(&self) -> Result<T, TryRecvError> {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.try_recv(),
@@ -293,15 +910,64 @@ impl<T> Receiver<T> {
         }
     }
 
-    /// Blocks the current thread until a message is received or the channel is empty and
-    /// disconnected.
+    /// Attempts to wait for a value on this receiver, returning an error if the
+    /// corresponding channel has hung up.
     ///
-    /// If the channel is empty and not disconnected, this call will block until the receive
-    /// operation can proceed. If the channel is empty and becomes disconnected, this call will
-    /// wake up and return an error.
+    /// This function will always block the current thread if there is no data
+    /// available and it's possible for more data to be sent (at least one sender
+    /// still exists). Once a message is sent to the corresponding [`Sender`],
+    /// this receiver will wake up and return that message.
     ///
-    /// If called on a zero-capacity channel, this method will wait for a send operation to appear
-    /// on the other side of the channel.
+    /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+    /// this call is blocking, this call will wake up and return [`Err`] to
+    /// indicate that no more messages can ever be received on this channel.
+    /// However, since channels are buffered, messages sent before the disconnect
+    /// will still be properly received.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(Ok(1), recv.recv());
+    /// ```
+    ///
+    /// Buffering behavior:
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    /// use std::sync::mpmc::RecvError;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    ///     send.send(2).unwrap();
+    ///     send.send(3).unwrap();
+    ///     drop(send);
+    /// });
+    ///
+    /// // wait for the thread to join so we ensure the sender is dropped
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(Ok(1), recv.recv());
+    /// assert_eq!(Ok(2), recv.recv());
+    /// assert_eq!(Ok(3), recv.recv());
+    /// assert_eq!(Err(RecvError), recv.recv());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn recv(&self) -> Result<T, RecvError> {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.recv(None),
@@ -311,14 +977,65 @@ impl<T> Receiver<T> {
         .map_err(|_| RecvError)
     }
 
-    /// Waits for a message to be received from the channel, but only for a limited time.
+    /// Attempts to wait for a value on this receiver, returning an error if the
+    /// corresponding channel has hung up, or if it waits more than `timeout`.
+    ///
+    /// This function will always block the current thread if there is no data
+    /// available and it's possible for more data to be sent (at least one sender
+    /// still exists). Once a message is sent to the corresponding [`Sender`],
+    /// this receiver will wake up and return that message.
+    ///
+    /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+    /// this call is blocking, this call will wake up and return [`Err`] to
+    /// indicate that no more messages can ever be received on this channel.
+    /// However, since channels are buffered, messages sent before the disconnect
+    /// will still be properly received.
+    ///
+    /// # Examples
+    ///
+    /// Successfully receiving value before encountering timeout:
     ///
-    /// If the channel is empty and not disconnected, this call will block until the receive
-    /// operation can proceed or the operation times out. If the channel is empty and becomes
-    /// disconnected, this call will wake up and return an error.
+    /// ```no_run
+    /// #![feature(mpmc_channel)]
     ///
-    /// If called on a zero-capacity channel, this method will wait for a send operation to appear
-    /// on the other side of the channel.
+    /// use std::thread;
+    /// use std::time::Duration;
+    /// use std::sync::mpmc;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    ///
+    /// thread::spawn(move || {
+    ///     send.send('a').unwrap();
+    /// });
+    ///
+    /// assert_eq!(
+    ///     recv.recv_timeout(Duration::from_millis(400)),
+    ///     Ok('a')
+    /// );
+    /// ```
+    ///
+    /// Receiving an error upon reaching timeout:
+    ///
+    /// ```no_run
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::thread;
+    /// use std::time::Duration;
+    /// use std::sync::mpmc;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    ///
+    /// thread::spawn(move || {
+    ///     thread::sleep(Duration::from_millis(800));
+    ///     send.send('a').unwrap();
+    /// });
+    ///
+    /// assert_eq!(
+    ///     recv.recv_timeout(Duration::from_millis(400)),
+    ///     Err(mpmc::RecvTimeoutError::Timeout)
+    /// );
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvTimeoutError> {
         match Instant::now().checked_add(timeout) {
             Some(deadline) => self.recv_deadline(deadline),
@@ -327,14 +1044,65 @@ impl<T> Receiver<T> {
         }
     }
 
-    /// Waits for a message to be received from the channel, but only for a limited time.
+    /// Attempts to wait for a value on this receiver, returning an error if the
+    /// corresponding channel has hung up, or if `deadline` is reached.
+    ///
+    /// This function will always block the current thread if there is no data
+    /// available and it's possible for more data to be sent. Once a message is
+    /// sent to the corresponding [`Sender`], then this receiver will wake up
+    /// and return that message.
+    ///
+    /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+    /// this call is blocking, this call will wake up and return [`Err`] to
+    /// indicate that no more messages can ever be received on this channel.
+    /// However, since channels are buffered, messages sent before the disconnect
+    /// will still be properly received.
+    ///
+    /// # Examples
+    ///
+    /// Successfully receiving value before reaching deadline:
+    ///
+    /// ```no_run
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::thread;
+    /// use std::time::{Duration, Instant};
+    /// use std::sync::mpmc;
     ///
-    /// If the channel is empty and not disconnected, this call will block until the receive
-    /// operation can proceed or the operation times out. If the channel is empty and becomes
-    /// disconnected, this call will wake up and return an error.
+    /// let (send, recv) = mpmc::channel();
     ///
-    /// If called on a zero-capacity channel, this method will wait for a send operation to appear
-    /// on the other side of the channel.
+    /// thread::spawn(move || {
+    ///     send.send('a').unwrap();
+    /// });
+    ///
+    /// assert_eq!(
+    ///     recv.recv_deadline(Instant::now() + Duration::from_millis(400)),
+    ///     Ok('a')
+    /// );
+    /// ```
+    ///
+    /// Receiving an error upon reaching deadline:
+    ///
+    /// ```no_run
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::thread;
+    /// use std::time::{Duration, Instant};
+    /// use std::sync::mpmc;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    ///
+    /// thread::spawn(move || {
+    ///     thread::sleep(Duration::from_millis(800));
+    ///     send.send('a').unwrap();
+    /// });
+    ///
+    /// assert_eq!(
+    ///     recv.recv_deadline(Instant::now() + Duration::from_millis(400)),
+    ///     Err(mpmc::RecvTimeoutError::Timeout)
+    /// );
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn recv_deadline(&self, deadline: Instant) -> Result<T, RecvTimeoutError> {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.recv(Some(deadline)),
@@ -342,16 +1110,77 @@ impl<T> Receiver<T> {
             ReceiverFlavor::Zero(chan) => chan.recv(Some(deadline)),
         }
     }
+
+    /// Returns an iterator that will attempt to yield all pending values.
+    /// It will return `None` if there are no more pending values or if the
+    /// channel has hung up. The iterator will never [`panic!`] or block the
+    /// user by waiting for values.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    /// use std::thread;
+    /// use std::time::Duration;
+    ///
+    /// let (sender, receiver) = channel();
+    ///
+    /// // nothing is in the buffer yet
+    /// assert!(receiver.try_iter().next().is_none());
+    ///
+    /// thread::spawn(move || {
+    ///     thread::sleep(Duration::from_secs(1));
+    ///     sender.send(1).unwrap();
+    ///     sender.send(2).unwrap();
+    ///     sender.send(3).unwrap();
+    /// });
+    ///
+    /// // nothing is in the buffer yet
+    /// assert!(receiver.try_iter().next().is_none());
+    ///
+    /// // block for two seconds
+    /// thread::sleep(Duration::from_secs(2));
+    ///
+    /// let mut iter = receiver.try_iter();
+    /// assert_eq!(iter.next(), Some(1));
+    /// assert_eq!(iter.next(), Some(2));
+    /// assert_eq!(iter.next(), Some(3));
+    /// assert_eq!(iter.next(), None);
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
+    pub fn try_iter(&self) -> TryIter<'_, T> {
+        TryIter { rx: self }
+    }
 }
 
-// The methods below are not used by `sync::mpsc`, but
-// are useful and we'll likely want to expose them
-// eventually
-#[allow(unused)]
 impl<T> Receiver<T> {
     /// Returns `true` if the channel is empty.
     ///
     /// Note: Zero-capacity channels are always empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    ///
+    /// assert!(recv.is_empty());
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert!(!recv.is_empty());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn is_empty(&self) -> bool {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.is_empty(),
@@ -363,6 +1192,28 @@ impl<T> Receiver<T> {
     /// Returns `true` if the channel is full.
     ///
     /// Note: Zero-capacity channels are always full.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = mpmc::sync_channel(1);
+    ///
+    /// assert!(!recv.is_full());
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert!(recv.is_full());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn is_full(&self) -> bool {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.is_full(),
@@ -372,6 +1223,28 @@ impl<T> Receiver<T> {
     }
 
     /// Returns the number of messages in the channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = mpmc::channel();
+    ///
+    /// assert_eq!(recv.len(), 0);
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(recv.len(), 1);
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn len(&self) -> usize {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.len(),
@@ -381,6 +1254,28 @@ impl<T> Receiver<T> {
     }
 
     /// If the channel is bounded, returns its capacity.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = mpmc::sync_channel(3);
+    ///
+    /// assert_eq!(recv.capacity(), Some(3));
+    ///
+    /// let handle = thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    /// });
+    ///
+    /// handle.join().unwrap();
+    ///
+    /// assert_eq!(recv.capacity(), Some(3));
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn capacity(&self) -> Option<usize> {
         match &self.flavor {
             ReceiverFlavor::Array(chan) => chan.capacity(),
@@ -390,6 +1285,21 @@ impl<T> Receiver<T> {
     }
 
     /// Returns `true` if receivers belong to the same channel.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc;
+    ///
+    /// let (_, rx1) = mpmc::channel::<i32>();
+    /// let (_, rx2) = mpmc::channel::<i32>();
+    ///
+    /// assert!(rx1.same_channel(&rx1));
+    /// assert!(!rx1.same_channel(&rx2));
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
     pub fn same_channel(&self, other: &Receiver<T>) -> bool {
         match (&self.flavor, &other.flavor) {
             (ReceiverFlavor::Array(a), ReceiverFlavor::Array(b)) => a == b,
@@ -398,8 +1308,39 @@ impl<T> Receiver<T> {
             _ => false,
         }
     }
+
+    /// Returns an iterator that will block waiting for messages, but never
+    /// [`panic!`]. It will return [`None`] when the channel has hung up.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = channel();
+    ///
+    /// thread::spawn(move || {
+    ///     send.send(1).unwrap();
+    ///     send.send(2).unwrap();
+    ///     send.send(3).unwrap();
+    /// });
+    ///
+    /// let mut iter = recv.iter();
+    /// assert_eq!(iter.next(), Some(1));
+    /// assert_eq!(iter.next(), Some(2));
+    /// assert_eq!(iter.next(), Some(3));
+    /// assert_eq!(iter.next(), None);
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
+    pub fn iter(&self) -> Iter<'_, T> {
+        Iter { rx: self }
+    }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> Drop for Receiver<T> {
     fn drop(&mut self) {
         unsafe {
@@ -412,6 +1353,7 @@ impl<T> Drop for Receiver<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> Clone for Receiver<T> {
     fn clone(&self) -> Self {
         let flavor = match &self.flavor {
@@ -424,6 +1366,7 @@ impl<T> Clone for Receiver<T> {
     }
 }
 
+#[unstable(feature = "mpmc_channel", issue = "126840")]
 impl<T> fmt::Debug for Receiver<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.pad("Receiver { .. }")
diff --git a/library/std/src/sync/mpmc/tests.rs b/library/std/src/sync/mpmc/tests.rs
new file mode 100644
index 00000000000..ab14050df6c
--- /dev/null
+++ b/library/std/src/sync/mpmc/tests.rs
@@ -0,0 +1,728 @@
+use super::*;
+use crate::{env, thread};
+
+pub fn stress_factor() -> usize {
+    match env::var("RUST_TEST_STRESS") {
+        Ok(val) => val.parse().unwrap(),
+        Err(..) => 1,
+    }
+}
+
+#[test]
+fn smoke() {
+    let (tx, rx) = channel::<i32>();
+    tx.send(1).unwrap();
+    assert_eq!(rx.recv().unwrap(), 1);
+}
+
+#[test]
+fn drop_full() {
+    let (tx, _rx) = channel::<Box<isize>>();
+    tx.send(Box::new(1)).unwrap();
+}
+
+#[test]
+fn drop_full_shared() {
+    let (tx, _rx) = channel::<Box<isize>>();
+    drop(tx.clone());
+    drop(tx.clone());
+    tx.send(Box::new(1)).unwrap();
+}
+
+#[test]
+fn smoke_shared() {
+    let (tx, rx) = channel::<i32>();
+    tx.send(1).unwrap();
+    assert_eq!(rx.recv().unwrap(), 1);
+    let tx = tx.clone();
+    tx.send(1).unwrap();
+    assert_eq!(rx.recv().unwrap(), 1);
+}
+
+#[test]
+fn smoke_threads() {
+    let (tx, rx) = channel::<i32>();
+    let t1 = thread::spawn(move || {
+        for i in 0..2 {
+            tx.send(i).unwrap();
+        }
+    });
+    let t2 = thread::spawn(move || {
+        assert_eq!(rx.recv().unwrap(), 0);
+        assert_eq!(rx.recv().unwrap(), 1);
+    });
+    t1.join().unwrap();
+    t2.join().unwrap();
+}
+
+#[test]
+fn smoke_port_gone() {
+    let (tx, rx) = channel::<i32>();
+    drop(rx);
+    assert!(tx.send(1).is_err());
+}
+
+#[test]
+fn smoke_shared_port_gone() {
+    let (tx, rx) = channel::<i32>();
+    drop(rx);
+    assert!(tx.send(1).is_err())
+}
+
+#[test]
+fn smoke_shared_port_gone2() {
+    let (tx, rx) = channel::<i32>();
+    drop(rx);
+    let tx2 = tx.clone();
+    drop(tx);
+    assert!(tx2.send(1).is_err());
+}
+
+#[test]
+fn port_gone_concurrent() {
+    let (tx, rx) = channel::<i32>();
+    let _t = thread::spawn(move || {
+        rx.recv().unwrap();
+    });
+    while tx.send(1).is_ok() {}
+}
+
+#[test]
+fn port_gone_concurrent_shared() {
+    let (tx, rx) = channel::<i32>();
+    let tx2 = tx.clone();
+    let _t = thread::spawn(move || {
+        rx.recv().unwrap();
+    });
+    while tx.send(1).is_ok() && tx2.send(1).is_ok() {}
+}
+
+#[test]
+fn smoke_chan_gone() {
+    let (tx, rx) = channel::<i32>();
+    drop(tx);
+    assert!(rx.recv().is_err());
+}
+
+#[test]
+fn smoke_chan_gone_shared() {
+    let (tx, rx) = channel::<()>();
+    let tx2 = tx.clone();
+    drop(tx);
+    drop(tx2);
+    assert!(rx.recv().is_err());
+}
+
+#[test]
+fn chan_gone_concurrent() {
+    let (tx, rx) = channel::<i32>();
+    let _t = thread::spawn(move || {
+        tx.send(1).unwrap();
+        tx.send(1).unwrap();
+    });
+    while rx.recv().is_ok() {}
+}
+
+#[test]
+fn stress() {
+    let count = if cfg!(miri) { 100 } else { 10000 };
+    let (tx, rx) = channel::<i32>();
+    let t = thread::spawn(move || {
+        for _ in 0..count {
+            tx.send(1).unwrap();
+        }
+    });
+    for _ in 0..count {
+        assert_eq!(rx.recv().unwrap(), 1);
+    }
+    t.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn stress_shared() {
+    const AMT: u32 = if cfg!(miri) { 100 } else { 10000 };
+    const NTHREADS: u32 = 8;
+    let (tx, rx) = channel::<i32>();
+
+    let t = thread::spawn(move || {
+        for _ in 0..AMT * NTHREADS {
+            assert_eq!(rx.recv().unwrap(), 1);
+        }
+        match rx.try_recv() {
+            Ok(..) => panic!(),
+            _ => {}
+        }
+    });
+
+    for _ in 0..NTHREADS {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            for _ in 0..AMT {
+                tx.send(1).unwrap();
+            }
+        });
+    }
+    drop(tx);
+    t.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn send_from_outside_runtime() {
+    let (tx1, rx1) = channel::<()>();
+    let (tx2, rx2) = channel::<i32>();
+    let t1 = thread::spawn(move || {
+        tx1.send(()).unwrap();
+        for _ in 0..40 {
+            assert_eq!(rx2.recv().unwrap(), 1);
+        }
+    });
+    rx1.recv().unwrap();
+    let t2 = thread::spawn(move || {
+        for _ in 0..40 {
+            tx2.send(1).unwrap();
+        }
+    });
+    t1.join().ok().expect("thread panicked");
+    t2.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn recv_from_outside_runtime() {
+    let (tx, rx) = channel::<i32>();
+    let t = thread::spawn(move || {
+        for _ in 0..40 {
+            assert_eq!(rx.recv().unwrap(), 1);
+        }
+    });
+    for _ in 0..40 {
+        tx.send(1).unwrap();
+    }
+    t.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn no_runtime() {
+    let (tx1, rx1) = channel::<i32>();
+    let (tx2, rx2) = channel::<i32>();
+    let t1 = thread::spawn(move || {
+        assert_eq!(rx1.recv().unwrap(), 1);
+        tx2.send(2).unwrap();
+    });
+    let t2 = thread::spawn(move || {
+        tx1.send(1).unwrap();
+        assert_eq!(rx2.recv().unwrap(), 2);
+    });
+    t1.join().ok().expect("thread panicked");
+    t2.join().ok().expect("thread panicked");
+}
+
+#[test]
+fn oneshot_single_thread_close_port_first() {
+    // Simple test of closing without sending
+    let (_tx, rx) = channel::<i32>();
+    drop(rx);
+}
+
+#[test]
+fn oneshot_single_thread_close_chan_first() {
+    // Simple test of closing without sending
+    let (tx, _rx) = channel::<i32>();
+    drop(tx);
+}
+
+#[test]
+fn oneshot_single_thread_send_port_close() {
+    // Testing that the sender cleans up the payload if receiver is closed
+    let (tx, rx) = channel::<Box<i32>>();
+    drop(rx);
+    assert!(tx.send(Box::new(0)).is_err());
+}
+
+#[test]
+fn oneshot_single_thread_recv_chan_close() {
+    // Receiving on a closed chan will panic
+    let res = thread::spawn(move || {
+        let (tx, rx) = channel::<i32>();
+        drop(tx);
+        rx.recv().unwrap();
+    })
+    .join();
+    // What is our res?
+    assert!(res.is_err());
+}
+
+#[test]
+fn oneshot_single_thread_send_then_recv() {
+    let (tx, rx) = channel::<Box<i32>>();
+    tx.send(Box::new(10)).unwrap();
+    assert!(*rx.recv().unwrap() == 10);
+}
+
+#[test]
+fn oneshot_single_thread_try_send_open() {
+    let (tx, rx) = channel::<i32>();
+    assert!(tx.send(10).is_ok());
+    assert!(rx.recv().unwrap() == 10);
+}
+
+#[test]
+fn oneshot_single_thread_try_send_closed() {
+    let (tx, rx) = channel::<i32>();
+    drop(rx);
+    assert!(tx.send(10).is_err());
+}
+
+#[test]
+fn oneshot_single_thread_try_recv_open() {
+    let (tx, rx) = channel::<i32>();
+    tx.send(10).unwrap();
+    assert!(rx.recv() == Ok(10));
+}
+
+#[test]
+fn oneshot_single_thread_try_recv_closed() {
+    let (tx, rx) = channel::<i32>();
+    drop(tx);
+    assert!(rx.recv().is_err());
+}
+
+#[test]
+fn oneshot_single_thread_peek_data() {
+    let (tx, rx) = channel::<i32>();
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
+    tx.send(10).unwrap();
+    assert_eq!(rx.try_recv(), Ok(10));
+}
+
+#[test]
+fn oneshot_single_thread_peek_close() {
+    let (tx, rx) = channel::<i32>();
+    drop(tx);
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+}
+
+#[test]
+fn oneshot_single_thread_peek_open() {
+    let (_tx, rx) = channel::<i32>();
+    assert_eq!(rx.try_recv(), Err(TryRecvError::Empty));
+}
+
+#[test]
+fn oneshot_multi_task_recv_then_send() {
+    let (tx, rx) = channel::<Box<i32>>();
+    let _t = thread::spawn(move || {
+        assert!(*rx.recv().unwrap() == 10);
+    });
+
+    tx.send(Box::new(10)).unwrap();
+}
+
+#[test]
+fn oneshot_multi_task_recv_then_close() {
+    let (tx, rx) = channel::<Box<i32>>();
+    let _t = thread::spawn(move || {
+        drop(tx);
+    });
+    let res = thread::spawn(move || {
+        assert!(*rx.recv().unwrap() == 10);
+    })
+    .join();
+    assert!(res.is_err());
+}
+
+#[test]
+fn oneshot_multi_thread_close_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel::<i32>();
+        let _t = thread::spawn(move || {
+            drop(rx);
+        });
+        drop(tx);
+    }
+}
+
+#[test]
+fn oneshot_multi_thread_send_close_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel::<i32>();
+        let _t = thread::spawn(move || {
+            drop(rx);
+        });
+        let _ = thread::spawn(move || {
+            tx.send(1).unwrap();
+        })
+        .join();
+    }
+}
+
+#[test]
+fn oneshot_multi_thread_recv_close_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel::<i32>();
+        thread::spawn(move || {
+            let res = thread::spawn(move || {
+                rx.recv().unwrap();
+            })
+            .join();
+            assert!(res.is_err());
+        });
+        let _t = thread::spawn(move || {
+            thread::spawn(move || {
+                drop(tx);
+            });
+        });
+    }
+}
+
+#[test]
+fn oneshot_multi_thread_send_recv_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel::<Box<isize>>();
+        let _t = thread::spawn(move || {
+            tx.send(Box::new(10)).unwrap();
+        });
+        assert!(*rx.recv().unwrap() == 10);
+    }
+}
+
+#[test]
+fn stream_send_recv_stress() {
+    for _ in 0..stress_factor() {
+        let (tx, rx) = channel();
+
+        send(tx, 0);
+        recv(rx, 0);
+
+        fn send(tx: Sender<Box<i32>>, i: i32) {
+            if i == 10 {
+                return;
+            }
+
+            thread::spawn(move || {
+                tx.send(Box::new(i)).unwrap();
+                send(tx, i + 1);
+            });
+        }
+
+        fn recv(rx: Receiver<Box<i32>>, i: i32) {
+            if i == 10 {
+                return;
+            }
+
+            thread::spawn(move || {
+                assert!(*rx.recv().unwrap() == i);
+                recv(rx, i + 1);
+            });
+        }
+    }
+}
+
+#[test]
+fn oneshot_single_thread_recv_timeout() {
+    let (tx, rx) = channel();
+    tx.send(()).unwrap();
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
+    tx.send(()).unwrap();
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+}
+
+#[test]
+fn stress_recv_timeout_two_threads() {
+    let (tx, rx) = channel();
+    let stress = stress_factor() + 100;
+    let timeout = Duration::from_millis(100);
+
+    thread::spawn(move || {
+        for i in 0..stress {
+            if i % 2 == 0 {
+                thread::sleep(timeout * 2);
+            }
+            tx.send(1usize).unwrap();
+        }
+    });
+
+    let mut recv_count = 0;
+    loop {
+        match rx.recv_timeout(timeout) {
+            Ok(n) => {
+                assert_eq!(n, 1usize);
+                recv_count += 1;
+            }
+            Err(RecvTimeoutError::Timeout) => continue,
+            Err(RecvTimeoutError::Disconnected) => break,
+        }
+    }
+
+    assert_eq!(recv_count, stress);
+}
+
+#[test]
+fn recv_timeout_upgrade() {
+    let (tx, rx) = channel::<()>();
+    let timeout = Duration::from_millis(1);
+    let _tx_clone = tx.clone();
+
+    let start = Instant::now();
+    assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout));
+    assert!(Instant::now() >= start + timeout);
+}
+
+#[test]
+fn stress_recv_timeout_shared() {
+    let (tx, rx) = channel();
+    let stress = stress_factor() + 100;
+
+    for i in 0..stress {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            thread::sleep(Duration::from_millis(i as u64 * 10));
+            tx.send(1usize).unwrap();
+        });
+    }
+
+    drop(tx);
+
+    let mut recv_count = 0;
+    loop {
+        match rx.recv_timeout(Duration::from_millis(10)) {
+            Ok(n) => {
+                assert_eq!(n, 1usize);
+                recv_count += 1;
+            }
+            Err(RecvTimeoutError::Timeout) => continue,
+            Err(RecvTimeoutError::Disconnected) => break,
+        }
+    }
+
+    assert_eq!(recv_count, stress);
+}
+
+#[test]
+fn very_long_recv_timeout_wont_panic() {
+    let (tx, rx) = channel::<()>();
+    let join_handle = thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::MAX)));
+    thread::sleep(Duration::from_secs(1));
+    assert!(tx.send(()).is_ok());
+    assert_eq!(join_handle.join().unwrap(), Ok(()));
+}
+
+#[test]
+fn recv_a_lot() {
+    let count = if cfg!(miri) { 1000 } else { 10000 };
+    // Regression test that we don't run out of stack in scheduler context
+    let (tx, rx) = channel();
+    for _ in 0..count {
+        tx.send(()).unwrap();
+    }
+    for _ in 0..count {
+        rx.recv().unwrap();
+    }
+}
+
+#[test]
+fn shared_recv_timeout() {
+    let (tx, rx) = channel();
+    let total = 5;
+    for _ in 0..total {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            tx.send(()).unwrap();
+        });
+    }
+
+    for _ in 0..total {
+        rx.recv().unwrap();
+    }
+
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
+    tx.send(()).unwrap();
+    assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+}
+
+#[test]
+fn shared_chan_stress() {
+    let (tx, rx) = channel();
+    let total = stress_factor() + 100;
+    for _ in 0..total {
+        let tx = tx.clone();
+        thread::spawn(move || {
+            tx.send(()).unwrap();
+        });
+    }
+
+    for _ in 0..total {
+        rx.recv().unwrap();
+    }
+}
+
+#[test]
+fn test_nested_recv_iter() {
+    let (tx, rx) = channel::<i32>();
+    let (total_tx, total_rx) = channel::<i32>();
+
+    let _t = thread::spawn(move || {
+        let mut acc = 0;
+        for x in rx.iter() {
+            acc += x;
+        }
+        total_tx.send(acc).unwrap();
+    });
+
+    tx.send(3).unwrap();
+    tx.send(1).unwrap();
+    tx.send(2).unwrap();
+    drop(tx);
+    assert_eq!(total_rx.recv().unwrap(), 6);
+}
+
+#[test]
+fn test_recv_iter_break() {
+    let (tx, rx) = channel::<i32>();
+    let (count_tx, count_rx) = channel();
+
+    let _t = thread::spawn(move || {
+        let mut count = 0;
+        for x in rx.iter() {
+            if count >= 3 {
+                break;
+            } else {
+                count += x;
+            }
+        }
+        count_tx.send(count).unwrap();
+    });
+
+    tx.send(2).unwrap();
+    tx.send(2).unwrap();
+    tx.send(2).unwrap();
+    let _ = tx.send(2);
+    drop(tx);
+    assert_eq!(count_rx.recv().unwrap(), 4);
+}
+
+#[test]
+fn test_recv_try_iter() {
+    let (request_tx, request_rx) = channel();
+    let (response_tx, response_rx) = channel();
+
+    // Request `x`s until we have `6`.
+    let t = thread::spawn(move || {
+        let mut count = 0;
+        loop {
+            for x in response_rx.try_iter() {
+                count += x;
+                if count == 6 {
+                    return count;
+                }
+            }
+            request_tx.send(()).unwrap();
+        }
+    });
+
+    for _ in request_rx.iter() {
+        if response_tx.send(2).is_err() {
+            break;
+        }
+    }
+
+    assert_eq!(t.join().unwrap(), 6);
+}
+
+#[test]
+fn test_recv_into_iter_owned() {
+    let mut iter = {
+        let (tx, rx) = channel::<i32>();
+        tx.send(1).unwrap();
+        tx.send(2).unwrap();
+
+        rx.into_iter()
+    };
+    assert_eq!(iter.next().unwrap(), 1);
+    assert_eq!(iter.next().unwrap(), 2);
+    assert_eq!(iter.next().is_none(), true);
+}
+
+#[test]
+fn test_recv_into_iter_borrowed() {
+    let (tx, rx) = channel::<i32>();
+    tx.send(1).unwrap();
+    tx.send(2).unwrap();
+    drop(tx);
+    let mut iter = (&rx).into_iter();
+    assert_eq!(iter.next().unwrap(), 1);
+    assert_eq!(iter.next().unwrap(), 2);
+    assert_eq!(iter.next().is_none(), true);
+}
+
+#[test]
+fn try_recv_states() {
+    let (tx1, rx1) = channel::<i32>();
+    let (tx2, rx2) = channel::<()>();
+    let (tx3, rx3) = channel::<()>();
+    let _t = thread::spawn(move || {
+        rx2.recv().unwrap();
+        tx1.send(1).unwrap();
+        tx3.send(()).unwrap();
+        rx2.recv().unwrap();
+        drop(tx1);
+        tx3.send(()).unwrap();
+    });
+
+    assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
+    tx2.send(()).unwrap();
+    rx3.recv().unwrap();
+    assert_eq!(rx1.try_recv(), Ok(1));
+    assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
+    tx2.send(()).unwrap();
+    rx3.recv().unwrap();
+    assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected));
+}
+
+// This bug used to end up in a livelock inside of the Receiver destructor
+// because the internal state of the Shared packet was corrupted
+#[test]
+fn destroy_upgraded_shared_port_when_sender_still_active() {
+    let (tx, rx) = channel();
+    let (tx2, rx2) = channel();
+    let _t = thread::spawn(move || {
+        rx.recv().unwrap(); // wait on a oneshot
+        drop(rx); // destroy a shared
+        tx2.send(()).unwrap();
+    });
+    // make sure the other thread has gone to sleep
+    for _ in 0..5000 {
+        thread::yield_now();
+    }
+
+    // upgrade to a shared chan and send a message
+    let t = tx.clone();
+    drop(tx);
+    t.send(()).unwrap();
+
+    // wait for the child thread to exit before we exit
+    rx2.recv().unwrap();
+}
+
+#[test]
+fn issue_32114() {
+    let (tx, _) = channel();
+    let _ = tx.send(123);
+    assert_eq!(tx.send(123), Err(SendError(123)));
+}
+
+#[test]
+fn issue_39364() {
+    let (tx, rx) = channel::<()>();
+    let t = thread::spawn(move || {
+        thread::sleep(Duration::from_millis(300));
+        let _ = tx.clone();
+        // Don't drop; hand back to caller.
+        tx
+    });
+
+    let _ = rx.recv_timeout(Duration::from_millis(500));
+    let _tx = t.join().unwrap(); // delay dropping until end of test
+    let _ = rx.recv_timeout(Duration::from_millis(500));
+}
diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs
index 26d5b9515a2..83a93a06369 100644
--- a/library/std/src/sync/mpsc/mod.rs
+++ b/library/std/src/sync/mpsc/mod.rs
@@ -137,10 +137,10 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod sync_tests;
 
 // MPSC channels are built as a wrapper around MPMC channels, which
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index f3de1f7bf49..fe2aca031a2 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -1,4 +1,4 @@
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 use crate::cell::UnsafeCell;
diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs
index 5a1cd7d0b8b..993df9314fc 100644
--- a/library/std/src/sync/once.rs
+++ b/library/std/src/sync/once.rs
@@ -3,7 +3,7 @@
 //! This primitive is meant to be used to run one-time initialization. An
 //! example use case would be for initializing an FFI library.
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 use crate::fmt;
diff --git a/library/std/src/sync/once_lock/tests.rs b/library/std/src/sync/once_lock/tests.rs
index 1fff3273d20..5113d436c3c 100644
--- a/library/std/src/sync/once_lock/tests.rs
+++ b/library/std/src/sync/once_lock/tests.rs
@@ -9,7 +9,7 @@ fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) ->
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn sync_once_cell() {
     static ONCE_CELL: OnceLock<i32> = OnceLock::new();
 
@@ -43,7 +43,7 @@ fn sync_once_cell_get_unchecked() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn sync_once_cell_drop() {
     static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
     struct Dropper;
@@ -81,6 +81,7 @@ fn clone() {
 }
 
 #[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn get_or_try_init() {
     let cell: OnceLock<String> = OnceLock::new();
     assert!(cell.get().is_none());
@@ -154,7 +155,7 @@ fn eval_once_macro() {
 }
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
     static ONCE_CELL: OnceLock<String> = OnceLock::new();
 
diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs
index 39f23a14441..0140e0d2129 100644
--- a/library/std/src/sync/reentrant_lock.rs
+++ b/library/std/src/sync/reentrant_lock.rs
@@ -1,4 +1,4 @@
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 use cfg_if::cfg_if;
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index 143bdef736d..da2da6f9dfc 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -1,4 +1,4 @@
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 use crate::cell::UnsafeCell;
diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs
index f49ef947174..b62afb40a61 100644
--- a/library/std/src/sys/pal/hermit/mod.rs
+++ b/library/std/src/sys/pal/hermit/mod.rs
@@ -92,7 +92,11 @@ pub unsafe extern "C" fn runtime_entry(
     unsafe {
         crate::sys::thread_local::destructors::run();
     }
-    unsafe { hermit_abi::exit(result) }
+    crate::rt::thread_cleanup();
+
+    unsafe {
+        hermit_abi::exit(result);
+    }
 }
 
 #[inline]
diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs
index 4c0c0919f47..41f2c3e2123 100644
--- a/library/std/src/sys/pal/hermit/thread.rs
+++ b/library/std/src/sys/pal/hermit/thread.rs
@@ -53,6 +53,7 @@ impl Thread {
 
                 // run all destructors
                 crate::sys::thread_local::destructors::run();
+                crate::rt::thread_cleanup();
             }
         }
     }
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index 2f2d6e6add3..04024661836 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -117,13 +117,15 @@ impl Thread {
     pub fn set_name(name: &CStr) {
         const PR_SET_NAME: libc::c_int = 15;
         unsafe {
-            libc::prctl(
+            let res = libc::prctl(
                 PR_SET_NAME,
                 name.as_ptr(),
                 0 as libc::c_ulong,
                 0 as libc::c_ulong,
                 0 as libc::c_ulong,
             );
+            // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
+            debug_assert_eq!(res, 0);
         }
     }
 
diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs
index 17b26543bd7..320712fdcc9 100644
--- a/library/std/src/sys/pal/wasip2/mod.rs
+++ b/library/std/src/sys/pal/wasip2/mod.rs
@@ -20,7 +20,6 @@ pub mod futex;
 #[path = "../wasi/io.rs"]
 pub mod io;
 
-#[path = "../wasi/net.rs"]
 pub mod net;
 #[path = "../wasi/os.rs"]
 pub mod os;
diff --git a/library/std/src/sys/pal/wasip2/net.rs b/library/std/src/sys/pal/wasip2/net.rs
new file mode 100644
index 00000000000..c40eb229ba9
--- /dev/null
+++ b/library/std/src/sys/pal/wasip2/net.rs
@@ -0,0 +1,379 @@
+#![deny(unsafe_op_in_unsafe_fn)]
+
+use libc::{c_int, c_void, size_t};
+
+use super::fd::WasiFd;
+use crate::ffi::CStr;
+use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
+use crate::net::{Shutdown, SocketAddr};
+use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
+use crate::sys::unsupported;
+use crate::sys_common::net::{TcpListener, getsockopt, setsockopt, sockaddr_to_addr};
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::time::{Duration, Instant};
+use crate::{cmp, mem, str};
+
+pub extern crate libc as netc;
+
+#[allow(non_camel_case_types)]
+pub type wrlen_t = size_t;
+
+#[doc(hidden)]
+pub trait IsMinusOne {
+    fn is_minus_one(&self) -> bool;
+}
+
+macro_rules! impl_is_minus_one {
+    ($($t:ident)*) => ($(impl IsMinusOne for $t {
+        fn is_minus_one(&self) -> bool {
+            *self == -1
+        }
+    })*)
+}
+
+impl_is_minus_one! { i8 i16 i32 i64 isize }
+
+pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
+    if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) }
+}
+
+pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
+where
+    T: IsMinusOne,
+    F: FnMut() -> T,
+{
+    loop {
+        match cvt(f()) {
+            Err(ref e) if e.is_interrupted() => {}
+            other => return other,
+        }
+    }
+}
+
+pub fn cvt_gai(err: c_int) -> io::Result<()> {
+    if err == 0 {
+        return Ok(());
+    }
+
+    if err == netc::EAI_SYSTEM {
+        return Err(io::Error::last_os_error());
+    }
+
+    let detail = unsafe {
+        str::from_utf8(CStr::from_ptr(netc::gai_strerror(err)).to_bytes()).unwrap().to_owned()
+    };
+
+    Err(io::Error::new(
+        io::ErrorKind::Uncategorized,
+        &format!("failed to lookup address information: {detail}")[..],
+    ))
+}
+
+pub fn init() {}
+
+pub struct Socket(WasiFd);
+
+impl Socket {
+    pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
+        let fam = match *addr {
+            SocketAddr::V4(..) => netc::AF_INET,
+            SocketAddr::V6(..) => netc::AF_INET6,
+        };
+        Socket::new_raw(fam, ty)
+    }
+
+    pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
+        let fd = cvt(unsafe { netc::socket(fam, ty, 0) })?;
+        Ok(unsafe { Self::from_raw_fd(fd) })
+    }
+
+    pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
+        let (addr, len) = addr.into_inner();
+        cvt_r(|| unsafe { netc::connect(self.as_raw_fd(), addr.as_ptr(), len) })?;
+        Ok(())
+    }
+
+    pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
+        self.set_nonblocking(true)?;
+        let r = self.connect(addr);
+        self.set_nonblocking(false)?;
+
+        match r {
+            Ok(_) => return Ok(()),
+            // there's no ErrorKind for EINPROGRESS
+            Err(ref e) if e.raw_os_error() == Some(netc::EINPROGRESS) => {}
+            Err(e) => return Err(e),
+        }
+
+        let mut pollfd = netc::pollfd { fd: self.as_raw_fd(), events: netc::POLLOUT, revents: 0 };
+
+        if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
+            return Err(io::Error::ZERO_TIMEOUT);
+        }
+
+        let start = Instant::now();
+
+        loop {
+            let elapsed = start.elapsed();
+            if elapsed >= timeout {
+                return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out"));
+            }
+
+            let timeout = timeout - elapsed;
+            let mut timeout = timeout
+                .as_secs()
+                .saturating_mul(1_000)
+                .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
+            if timeout == 0 {
+                timeout = 1;
+            }
+
+            let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int;
+
+            match unsafe { netc::poll(&mut pollfd, 1, timeout) } {
+                -1 => {
+                    let err = io::Error::last_os_error();
+                    if !err.is_interrupted() {
+                        return Err(err);
+                    }
+                }
+                0 => {}
+                _ => {
+                    // WASI poll does not return  POLLHUP or POLLERR in revents. Check if the
+                    // connnection actually succeeded and return ok only when the socket is
+                    // ready and no errors were found.
+                    if let Some(e) = self.take_error()? {
+                        return Err(e);
+                    }
+
+                    return Ok(());
+                }
+            }
+        }
+    }
+
+    pub fn accept(
+        &self,
+        storage: *mut netc::sockaddr,
+        len: *mut netc::socklen_t,
+    ) -> io::Result<Socket> {
+        let fd = cvt_r(|| unsafe { netc::accept(self.as_raw_fd(), storage, len) })?;
+        Ok(unsafe { Self::from_raw_fd(fd) })
+    }
+
+    pub fn duplicate(&self) -> io::Result<Socket> {
+        unsupported()
+    }
+
+    fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> {
+        let ret = cvt(unsafe {
+            netc::recv(
+                self.as_raw_fd(),
+                buf.as_mut().as_mut_ptr() as *mut c_void,
+                buf.capacity(),
+                flags,
+            )
+        })?;
+        unsafe {
+            buf.advance_unchecked(ret as usize);
+        }
+        Ok(())
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        let mut buf = BorrowedBuf::from(buf);
+        self.recv_with_flags(buf.unfilled(), 0)?;
+        Ok(buf.len())
+    }
+
+    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+        let mut buf = BorrowedBuf::from(buf);
+        self.recv_with_flags(buf.unfilled(), netc::MSG_PEEK)?;
+        Ok(buf.len())
+    }
+
+    pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.recv_with_flags(buf, 0)
+    }
+
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        io::default_read_vectored(|b| self.read(b), bufs)
+    }
+
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        false
+    }
+
+    fn recv_from_with_flags(
+        &self,
+        buf: &mut [u8],
+        flags: c_int,
+    ) -> io::Result<(usize, SocketAddr)> {
+        let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() };
+        let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
+
+        let n = cvt(unsafe {
+            netc::recvfrom(
+                self.as_raw_fd(),
+                buf.as_mut_ptr() as *mut c_void,
+                buf.len(),
+                flags,
+                core::ptr::addr_of_mut!(storage) as *mut _,
+                &mut addrlen,
+            )
+        })?;
+        Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
+    }
+
+    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.recv_from_with_flags(buf, 0)
+    }
+
+    pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.recv_from_with_flags(buf, netc::MSG_PEEK)
+    }
+
+    fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
+        let ret = cvt(unsafe {
+            netc::send(self.as_raw(), buf.as_ptr() as *const c_void, len, netc::MSG_NOSIGNAL)
+        })?;
+        Ok(ret as usize)
+    }
+
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        io::default_write_vectored(|b| self.write(b), bufs)
+    }
+
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        false
+    }
+
+    pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()> {
+        let timeout = match dur {
+            Some(dur) => {
+                if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
+                    return Err(io::Error::ZERO_TIMEOUT);
+                }
+
+                let secs = dur.as_secs().try_into().unwrap_or(netc::time_t::MAX);
+                let mut timeout = netc::timeval {
+                    tv_sec: secs,
+                    tv_usec: dur.subsec_micros() as netc::suseconds_t,
+                };
+                if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+                    timeout.tv_usec = 1;
+                }
+                timeout
+            }
+            None => netc::timeval { tv_sec: 0, tv_usec: 0 },
+        };
+        setsockopt(self, netc::SOL_SOCKET, kind, timeout)
+    }
+
+    pub fn timeout(&self, kind: c_int) -> io::Result<Option<Duration>> {
+        let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?;
+        if raw.tv_sec == 0 && raw.tv_usec == 0 {
+            Ok(None)
+        } else {
+            let sec = raw.tv_sec as u64;
+            let nsec = (raw.tv_usec as u32) * 1000;
+            Ok(Some(Duration::new(sec, nsec)))
+        }
+    }
+
+    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+        let how = match how {
+            Shutdown::Write => netc::SHUT_WR,
+            Shutdown::Read => netc::SHUT_RD,
+            Shutdown::Both => netc::SHUT_RDWR,
+        };
+        cvt(unsafe { netc::shutdown(self.as_raw_fd(), how) })?;
+        Ok(())
+    }
+
+    pub fn set_linger(&self, _linger: Option<Duration>) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        unsupported()
+    }
+
+    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+        setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int)
+    }
+
+    pub fn nodelay(&self) -> io::Result<bool> {
+        let raw: c_int = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?;
+        Ok(raw != 0)
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        let mut nonblocking = nonblocking as c_int;
+        cvt(unsafe { netc::ioctl(self.as_raw_fd(), netc::FIONBIO, &mut nonblocking) }).map(drop)
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        let raw: c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)?;
+        if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
+    }
+
+    // This is used by sys_common code to abstract over Windows and Unix.
+    pub fn as_raw(&self) -> RawFd {
+        self.as_raw_fd()
+    }
+}
+
+impl AsInner<WasiFd> for Socket {
+    #[inline]
+    fn as_inner(&self) -> &WasiFd {
+        &self.0
+    }
+}
+
+impl IntoInner<WasiFd> for Socket {
+    fn into_inner(self) -> WasiFd {
+        self.0
+    }
+}
+
+impl FromInner<WasiFd> for Socket {
+    fn from_inner(inner: WasiFd) -> Socket {
+        Socket(inner)
+    }
+}
+
+impl AsFd for Socket {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+
+impl AsRawFd for Socket {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+
+impl IntoRawFd for Socket {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+
+impl FromRawFd for Socket {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) }
+    }
+}
+
+impl AsInner<Socket> for TcpListener {
+    #[inline]
+    fn as_inner(&self) -> &Socket {
+        &self.socket()
+    }
+}
diff --git a/library/std/src/sys/sync/condvar/mod.rs b/library/std/src/sys/sync/condvar/mod.rs
index 6849cacf88e..d0c998a5597 100644
--- a/library/std/src/sys/sync/condvar/mod.rs
+++ b/library/std/src/sys/sync/condvar/mod.rs
@@ -12,7 +12,10 @@ cfg_if::cfg_if! {
     ))] {
         mod futex;
         pub use futex::Condvar;
-    } else if #[cfg(target_family = "unix")] {
+    } else if #[cfg(any(
+        target_family = "unix",
+        target_os = "teeos",
+    ))] {
         mod pthread;
         pub use pthread::Condvar;
     } else if #[cfg(all(target_os = "windows", target_vendor = "win7"))] {
@@ -24,9 +27,6 @@ cfg_if::cfg_if! {
     } else if #[cfg(target_os = "solid_asp3")] {
         mod itron;
         pub use itron::Condvar;
-    } else if #[cfg(target_os = "teeos")] {
-        mod teeos;
-        pub use teeos::Condvar;
     } else if #[cfg(target_os = "xous")] {
         mod xous;
         pub use xous::Condvar;
diff --git a/library/std/src/sys/sync/condvar/pthread.rs b/library/std/src/sys/sync/condvar/pthread.rs
index 5b5e7770b06..986cd0cb7d1 100644
--- a/library/std/src/sys/sync/condvar/pthread.rs
+++ b/library/std/src/sys/sync/condvar/pthread.rs
@@ -2,31 +2,25 @@ use crate::cell::UnsafeCell;
 use crate::ptr;
 use crate::sync::atomic::AtomicPtr;
 use crate::sync::atomic::Ordering::Relaxed;
-use crate::sys::sync::{Mutex, mutex};
+use crate::sys::sync::{Mutex, OnceBox};
 #[cfg(not(target_os = "nto"))]
 use crate::sys::time::TIMESPEC_MAX;
 #[cfg(target_os = "nto")]
 use crate::sys::time::TIMESPEC_MAX_CAPPED;
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 use crate::time::Duration;
 
 struct AllocatedCondvar(UnsafeCell<libc::pthread_cond_t>);
 
 pub struct Condvar {
-    inner: LazyBox<AllocatedCondvar>,
+    inner: OnceBox<AllocatedCondvar>,
     mutex: AtomicPtr<libc::pthread_mutex_t>,
 }
 
-#[inline]
-fn raw(c: &Condvar) -> *mut libc::pthread_cond_t {
-    c.inner.0.get()
-}
-
 unsafe impl Send for AllocatedCondvar {}
 unsafe impl Sync for AllocatedCondvar {}
 
-impl LazyInit for AllocatedCondvar {
-    fn init() -> Box<Self> {
+impl AllocatedCondvar {
+    fn new() -> Box<Self> {
         let condvar = Box::new(AllocatedCondvar(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)));
 
         cfg_if::cfg_if! {
@@ -37,7 +31,7 @@ impl LazyInit for AllocatedCondvar {
                 target_vendor = "apple",
             ))] {
                 // `pthread_condattr_setclock` is unfortunately not supported on these platforms.
-            } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] {
+            } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "teeos"))] {
                 // NOTE: ESP-IDF's PTHREAD_COND_INITIALIZER support is not released yet
                 // So on that platform, init() should always be called
                 // Moreover, that platform does not have pthread_condattr_setclock support,
@@ -82,7 +76,11 @@ impl Drop for AllocatedCondvar {
 
 impl Condvar {
     pub const fn new() -> Condvar {
-        Condvar { inner: LazyBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) }
+        Condvar { inner: OnceBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) }
+    }
+
+    fn get(&self) -> *mut libc::pthread_cond_t {
+        self.inner.get_or_init(AllocatedCondvar::new).0.get()
     }
 
     #[inline]
@@ -98,21 +96,21 @@ impl Condvar {
 
     #[inline]
     pub fn notify_one(&self) {
-        let r = unsafe { libc::pthread_cond_signal(raw(self)) };
+        let r = unsafe { libc::pthread_cond_signal(self.get()) };
         debug_assert_eq!(r, 0);
     }
 
     #[inline]
     pub fn notify_all(&self) {
-        let r = unsafe { libc::pthread_cond_broadcast(raw(self)) };
+        let r = unsafe { libc::pthread_cond_broadcast(self.get()) };
         debug_assert_eq!(r, 0);
     }
 
     #[inline]
     pub unsafe fn wait(&self, mutex: &Mutex) {
-        let mutex = mutex::raw(mutex);
+        let mutex = mutex.get_assert_locked();
         self.verify(mutex);
-        let r = libc::pthread_cond_wait(raw(self), mutex);
+        let r = libc::pthread_cond_wait(self.get(), mutex);
         debug_assert_eq!(r, 0);
     }
 
@@ -129,7 +127,7 @@ impl Condvar {
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
         use crate::sys::time::Timespec;
 
-        let mutex = mutex::raw(mutex);
+        let mutex = mutex.get_assert_locked();
         self.verify(mutex);
 
         #[cfg(not(target_os = "nto"))]
@@ -144,7 +142,7 @@ impl Condvar {
             .and_then(|t| t.to_timespec_capped())
             .unwrap_or(TIMESPEC_MAX_CAPPED);
 
-        let r = libc::pthread_cond_timedwait(raw(self), mutex, &timeout);
+        let r = libc::pthread_cond_timedwait(self.get(), mutex, &timeout);
         assert!(r == libc::ETIMEDOUT || r == 0);
         r == 0
     }
@@ -162,7 +160,7 @@ impl Condvar {
         use crate::sys::time::SystemTime;
         use crate::time::Instant;
 
-        let mutex = mutex::raw(mutex);
+        let mutex = mutex.get_assert_locked();
         self.verify(mutex);
 
         // OSX implementation of `pthread_cond_timedwait` is buggy
@@ -188,7 +186,7 @@ impl Condvar {
             .and_then(|t| t.to_timespec())
             .unwrap_or(TIMESPEC_MAX);
 
-        let r = libc::pthread_cond_timedwait(raw(self), mutex, &timeout);
+        let r = libc::pthread_cond_timedwait(self.get(), mutex, &timeout);
         debug_assert!(r == libc::ETIMEDOUT || r == 0);
 
         // ETIMEDOUT is not a totally reliable method of determining timeout due
diff --git a/library/std/src/sys/sync/condvar/sgx.rs b/library/std/src/sys/sync/condvar/sgx.rs
index ecb5872f60d..e60715e4b59 100644
--- a/library/std/src/sys/sync/condvar/sgx.rs
+++ b/library/std/src/sys/sync/condvar/sgx.rs
@@ -1,44 +1,39 @@
 use crate::sys::pal::waitqueue::{SpinMutex, WaitQueue, WaitVariable};
-use crate::sys::sync::Mutex;
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
+use crate::sys::sync::{Mutex, OnceBox};
 use crate::time::Duration;
 
-/// FIXME: `UnsafeList` is not movable.
-struct AllocatedCondvar(SpinMutex<WaitVariable<()>>);
-
 pub struct Condvar {
-    inner: LazyBox<AllocatedCondvar>,
-}
-
-impl LazyInit for AllocatedCondvar {
-    fn init() -> Box<Self> {
-        Box::new(AllocatedCondvar(SpinMutex::new(WaitVariable::new(()))))
-    }
+    // FIXME: `UnsafeList` is not movable.
+    inner: OnceBox<SpinMutex<WaitVariable<()>>>,
 }
 
 impl Condvar {
     pub const fn new() -> Condvar {
-        Condvar { inner: LazyBox::new() }
+        Condvar { inner: OnceBox::new() }
+    }
+
+    fn get(&self) -> &SpinMutex<WaitVariable<()>> {
+        self.inner.get_or_init(|| Box::new(SpinMutex::new(WaitVariable::new(()))))
     }
 
     #[inline]
     pub fn notify_one(&self) {
-        let _ = WaitQueue::notify_one(self.inner.0.lock());
+        let _ = WaitQueue::notify_one(self.get().lock());
     }
 
     #[inline]
     pub fn notify_all(&self) {
-        let _ = WaitQueue::notify_all(self.inner.0.lock());
+        let _ = WaitQueue::notify_all(self.get().lock());
     }
 
     pub unsafe fn wait(&self, mutex: &Mutex) {
-        let guard = self.inner.0.lock();
+        let guard = self.get().lock();
         WaitQueue::wait(guard, || unsafe { mutex.unlock() });
         mutex.lock()
     }
 
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        let success = WaitQueue::wait_timeout(&self.inner.0, dur, || unsafe { mutex.unlock() });
+        let success = WaitQueue::wait_timeout(self.get(), dur, || unsafe { mutex.unlock() });
         mutex.lock();
         success
     }
diff --git a/library/std/src/sys/sync/condvar/teeos.rs b/library/std/src/sys/sync/condvar/teeos.rs
deleted file mode 100644
index 943867cd761..00000000000
--- a/library/std/src/sys/sync/condvar/teeos.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-use crate::cell::UnsafeCell;
-use crate::ptr;
-use crate::sync::atomic::AtomicPtr;
-use crate::sync::atomic::Ordering::Relaxed;
-use crate::sys::sync::mutex::{self, Mutex};
-use crate::sys::time::TIMESPEC_MAX;
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
-use crate::time::Duration;
-
-extern "C" {
-    pub fn pthread_cond_timedwait(
-        cond: *mut libc::pthread_cond_t,
-        lock: *mut libc::pthread_mutex_t,
-        adstime: *const libc::timespec,
-    ) -> libc::c_int;
-}
-
-struct AllocatedCondvar(UnsafeCell<libc::pthread_cond_t>);
-
-pub struct Condvar {
-    inner: LazyBox<AllocatedCondvar>,
-    mutex: AtomicPtr<libc::pthread_mutex_t>,
-}
-
-#[inline]
-fn raw(c: &Condvar) -> *mut libc::pthread_cond_t {
-    c.inner.0.get()
-}
-
-unsafe impl Send for AllocatedCondvar {}
-unsafe impl Sync for AllocatedCondvar {}
-
-impl LazyInit for AllocatedCondvar {
-    fn init() -> Box<Self> {
-        let condvar = Box::new(AllocatedCondvar(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)));
-
-        let r = unsafe { libc::pthread_cond_init(condvar.0.get(), crate::ptr::null()) };
-        assert_eq!(r, 0);
-
-        condvar
-    }
-}
-
-impl Drop for AllocatedCondvar {
-    #[inline]
-    fn drop(&mut self) {
-        let r = unsafe { libc::pthread_cond_destroy(self.0.get()) };
-        debug_assert_eq!(r, 0);
-    }
-}
-
-impl Condvar {
-    pub const fn new() -> Condvar {
-        Condvar { inner: LazyBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) }
-    }
-
-    #[inline]
-    fn verify(&self, mutex: *mut libc::pthread_mutex_t) {
-        match self.mutex.compare_exchange(ptr::null_mut(), mutex, Relaxed, Relaxed) {
-            Ok(_) => {}                // Stored the address
-            Err(n) if n == mutex => {} // Lost a race to store the same address
-            _ => panic!("attempted to use a condition variable with two mutexes"),
-        }
-    }
-
-    #[inline]
-    pub fn notify_one(&self) {
-        let r = unsafe { libc::pthread_cond_signal(raw(self)) };
-        debug_assert_eq!(r, 0);
-    }
-
-    #[inline]
-    pub fn notify_all(&self) {
-        let r = unsafe { libc::pthread_cond_broadcast(raw(self)) };
-        debug_assert_eq!(r, 0);
-    }
-
-    #[inline]
-    pub unsafe fn wait(&self, mutex: &Mutex) {
-        let mutex = unsafe { mutex::raw(mutex) };
-        self.verify(mutex);
-        let r = unsafe { libc::pthread_cond_wait(raw(self), mutex) };
-        debug_assert_eq!(r, 0);
-    }
-
-    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        use crate::sys::time::Timespec;
-
-        let mutex = unsafe { mutex::raw(mutex) };
-        self.verify(mutex);
-
-        let timeout = Timespec::now(libc::CLOCK_MONOTONIC)
-            .checked_add_duration(&dur)
-            .and_then(|t| t.to_timespec())
-            .unwrap_or(TIMESPEC_MAX);
-
-        let r = unsafe { pthread_cond_timedwait(raw(self), mutex, &timeout) };
-        assert!(r == libc::ETIMEDOUT || r == 0);
-        r == 0
-    }
-}
diff --git a/library/std/src/sys/sync/mod.rs b/library/std/src/sys/sync/mod.rs
index 52fac5902a2..0691e967851 100644
--- a/library/std/src/sys/sync/mod.rs
+++ b/library/std/src/sys/sync/mod.rs
@@ -1,11 +1,14 @@
 mod condvar;
 mod mutex;
 mod once;
+mod once_box;
 mod rwlock;
 mod thread_parking;
 
 pub use condvar::Condvar;
 pub use mutex::Mutex;
 pub use once::{Once, OnceState};
+#[allow(unused)] // Only used on some platforms.
+use once_box::OnceBox;
 pub use rwlock::RwLock;
 pub use thread_parking::Parker;
diff --git a/library/std/src/sys/sync/mutex/mod.rs b/library/std/src/sys/sync/mutex/mod.rs
index 73d9bd273de..360df3fc4b5 100644
--- a/library/std/src/sys/sync/mutex/mod.rs
+++ b/library/std/src/sys/sync/mutex/mod.rs
@@ -19,7 +19,7 @@ cfg_if::cfg_if! {
         target_os = "teeos",
     ))] {
         mod pthread;
-        pub use pthread::{Mutex, raw};
+        pub use pthread::Mutex;
     } else if #[cfg(all(target_os = "windows", target_vendor = "win7"))] {
         mod windows7;
         pub use windows7::{Mutex, raw};
diff --git a/library/std/src/sys/sync/mutex/pthread.rs b/library/std/src/sys/sync/mutex/pthread.rs
index 1c407bc2537..87c95f45f96 100644
--- a/library/std/src/sys/sync/mutex/pthread.rs
+++ b/library/std/src/sys/sync/mutex/pthread.rs
@@ -2,24 +2,19 @@ use crate::cell::UnsafeCell;
 use crate::io::Error;
 use crate::mem::{MaybeUninit, forget};
 use crate::sys::cvt_nz;
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
+use crate::sys::sync::OnceBox;
 
 struct AllocatedMutex(UnsafeCell<libc::pthread_mutex_t>);
 
 pub struct Mutex {
-    inner: LazyBox<AllocatedMutex>,
-}
-
-#[inline]
-pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t {
-    m.inner.0.get()
+    inner: OnceBox<AllocatedMutex>,
 }
 
 unsafe impl Send for AllocatedMutex {}
 unsafe impl Sync for AllocatedMutex {}
 
-impl LazyInit for AllocatedMutex {
-    fn init() -> Box<Self> {
+impl AllocatedMutex {
+    fn new() -> Box<Self> {
         let mutex = Box::new(AllocatedMutex(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)));
 
         // Issue #33770
@@ -60,24 +55,6 @@ impl LazyInit for AllocatedMutex {
 
         mutex
     }
-
-    fn destroy(mutex: Box<Self>) {
-        // We're not allowed to pthread_mutex_destroy a locked mutex,
-        // so check first if it's unlocked.
-        if unsafe { libc::pthread_mutex_trylock(mutex.0.get()) == 0 } {
-            unsafe { libc::pthread_mutex_unlock(mutex.0.get()) };
-            drop(mutex);
-        } else {
-            // The mutex is locked. This happens if a MutexGuard is leaked.
-            // In this case, we just leak the Mutex too.
-            forget(mutex);
-        }
-    }
-
-    fn cancel_init(_: Box<Self>) {
-        // In this case, we can just drop it without any checks,
-        // since it cannot have been locked yet.
-    }
 }
 
 impl Drop for AllocatedMutex {
@@ -99,11 +76,33 @@ impl Drop for AllocatedMutex {
 impl Mutex {
     #[inline]
     pub const fn new() -> Mutex {
-        Mutex { inner: LazyBox::new() }
+        Mutex { inner: OnceBox::new() }
+    }
+
+    /// Gets access to the pthread mutex under the assumption that the mutex is
+    /// locked.
+    ///
+    /// This allows skipping the initialization check, as the mutex can only be
+    /// locked if it is already initialized, and allows relaxing the ordering
+    /// on the pointer load, since the allocation cannot have been modified
+    /// since the `lock` and the lock must have occurred on the current thread.
+    ///
+    /// # Safety
+    /// Causes undefined behaviour if the mutex is not locked.
+    #[inline]
+    pub(crate) unsafe fn get_assert_locked(&self) -> *mut libc::pthread_mutex_t {
+        unsafe { self.inner.get_unchecked().0.get() }
     }
 
     #[inline]
-    pub unsafe fn lock(&self) {
+    fn get(&self) -> *mut libc::pthread_mutex_t {
+        // If initialization fails, the mutex is destroyed. This is always sound,
+        // however, as the mutex cannot have been locked yet.
+        self.inner.get_or_init(AllocatedMutex::new).0.get()
+    }
+
+    #[inline]
+    pub fn lock(&self) {
         #[cold]
         #[inline(never)]
         fn fail(r: i32) -> ! {
@@ -111,7 +110,7 @@ impl Mutex {
             panic!("failed to lock mutex: {error}");
         }
 
-        let r = libc::pthread_mutex_lock(raw(self));
+        let r = unsafe { libc::pthread_mutex_lock(self.get()) };
         // As we set the mutex type to `PTHREAD_MUTEX_NORMAL` above, we expect
         // the lock call to never fail. Unfortunately however, some platforms
         // (Solaris) do not conform to the standard, and instead always provide
@@ -126,13 +125,29 @@ impl Mutex {
 
     #[inline]
     pub unsafe fn unlock(&self) {
-        let r = libc::pthread_mutex_unlock(raw(self));
+        let r = libc::pthread_mutex_unlock(self.get_assert_locked());
         debug_assert_eq!(r, 0);
     }
 
     #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        libc::pthread_mutex_trylock(raw(self)) == 0
+    pub fn try_lock(&self) -> bool {
+        unsafe { libc::pthread_mutex_trylock(self.get()) == 0 }
+    }
+}
+
+impl Drop for Mutex {
+    fn drop(&mut self) {
+        let Some(mutex) = self.inner.take() else { return };
+        // We're not allowed to pthread_mutex_destroy a locked mutex,
+        // so check first if it's unlocked.
+        if unsafe { libc::pthread_mutex_trylock(mutex.0.get()) == 0 } {
+            unsafe { libc::pthread_mutex_unlock(mutex.0.get()) };
+            drop(mutex);
+        } else {
+            // The mutex is locked. This happens if a MutexGuard is leaked.
+            // In this case, we just leak the Mutex too.
+            forget(mutex);
+        }
     }
 }
 
diff --git a/library/std/src/sys/sync/mutex/sgx.rs b/library/std/src/sys/sync/mutex/sgx.rs
index 65d1e880f7b..8529e857970 100644
--- a/library/std/src/sys/sync/mutex/sgx.rs
+++ b/library/std/src/sys/sync/mutex/sgx.rs
@@ -1,28 +1,24 @@
 use crate::sys::pal::waitqueue::{SpinMutex, WaitQueue, WaitVariable, try_lock_or_false};
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
-
-/// FIXME: `UnsafeList` is not movable.
-struct AllocatedMutex(SpinMutex<WaitVariable<bool>>);
+use crate::sys::sync::OnceBox;
 
 pub struct Mutex {
-    inner: LazyBox<AllocatedMutex>,
-}
-
-impl LazyInit for AllocatedMutex {
-    fn init() -> Box<Self> {
-        Box::new(AllocatedMutex(SpinMutex::new(WaitVariable::new(false))))
-    }
+    // FIXME: `UnsafeList` is not movable.
+    inner: OnceBox<SpinMutex<WaitVariable<bool>>>,
 }
 
 // Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28
 impl Mutex {
     pub const fn new() -> Mutex {
-        Mutex { inner: LazyBox::new() }
+        Mutex { inner: OnceBox::new() }
+    }
+
+    fn get(&self) -> &SpinMutex<WaitVariable<bool>> {
+        self.inner.get_or_init(|| Box::new(SpinMutex::new(WaitVariable::new(false))))
     }
 
     #[inline]
     pub fn lock(&self) {
-        let mut guard = self.inner.0.lock();
+        let mut guard = self.get().lock();
         if *guard.lock_var() {
             // Another thread has the lock, wait
             WaitQueue::wait(guard, || {})
@@ -35,7 +31,9 @@ impl Mutex {
 
     #[inline]
     pub unsafe fn unlock(&self) {
-        let guard = self.inner.0.lock();
+        // SAFETY: the mutex was locked by the current thread, so it has been
+        // initialized already.
+        let guard = unsafe { self.inner.get_unchecked().lock() };
         if let Err(mut guard) = WaitQueue::notify_one(guard) {
             // No other waiters, unlock
             *guard.lock_var_mut() = false;
@@ -46,7 +44,7 @@ impl Mutex {
 
     #[inline]
     pub fn try_lock(&self) -> bool {
-        let mut guard = try_lock_or_false!(self.inner.0);
+        let mut guard = try_lock_or_false!(self.get());
         if *guard.lock_var() {
             // Another thread has the lock
             false
diff --git a/library/std/src/sys/sync/once_box.rs b/library/std/src/sys/sync/once_box.rs
new file mode 100644
index 00000000000..1422b5a1721
--- /dev/null
+++ b/library/std/src/sys/sync/once_box.rs
@@ -0,0 +1,82 @@
+//! A racily-initialized alternative to `OnceLock<Box<T>>`.
+//!
+//! This is used to implement synchronization primitives that need allocation,
+//! like the pthread versions.
+
+#![allow(dead_code)] // Only used on some platforms.
+
+use crate::mem::replace;
+use crate::ptr::null_mut;
+use crate::sync::atomic::AtomicPtr;
+use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed};
+
+pub(crate) struct OnceBox<T> {
+    ptr: AtomicPtr<T>,
+}
+
+impl<T> OnceBox<T> {
+    #[inline]
+    pub const fn new() -> Self {
+        Self { ptr: AtomicPtr::new(null_mut()) }
+    }
+
+    /// Gets access to the value, assuming it is already initialized and this
+    /// initialization has been observed by the current thread.
+    ///
+    /// Since all modifications to the pointer have already been observed, the
+    /// pointer load in this function can be performed with relaxed ordering,
+    /// potentially allowing the optimizer to turn code like this:
+    /// ```rust, ignore
+    /// once_box.get_or_init(|| Box::new(42));
+    /// unsafe { once_box.get_unchecked() }
+    /// ```
+    /// into
+    /// ```rust, ignore
+    /// once_box.get_or_init(|| Box::new(42))
+    /// ```
+    ///
+    /// # Safety
+    /// This causes undefined behaviour if the assumption above is violated.
+    #[inline]
+    pub unsafe fn get_unchecked(&self) -> &T {
+        unsafe { &*self.ptr.load(Relaxed) }
+    }
+
+    #[inline]
+    pub fn get_or_init(&self, f: impl FnOnce() -> Box<T>) -> &T {
+        let ptr = self.ptr.load(Acquire);
+        match unsafe { ptr.as_ref() } {
+            Some(val) => val,
+            None => self.initialize(f),
+        }
+    }
+
+    #[inline]
+    pub fn take(&mut self) -> Option<Box<T>> {
+        let ptr = replace(self.ptr.get_mut(), null_mut());
+        if !ptr.is_null() { Some(unsafe { Box::from_raw(ptr) }) } else { None }
+    }
+
+    #[cold]
+    fn initialize(&self, f: impl FnOnce() -> Box<T>) -> &T {
+        let new_ptr = Box::into_raw(f());
+        match self.ptr.compare_exchange(null_mut(), new_ptr, AcqRel, Acquire) {
+            Ok(_) => unsafe { &*new_ptr },
+            Err(ptr) => {
+                // Lost the race to another thread.
+                // Drop the value we created, and use the one from the other thread instead.
+                drop(unsafe { Box::from_raw(new_ptr) });
+                unsafe { &*ptr }
+            }
+        }
+    }
+}
+
+unsafe impl<T: Send> Send for OnceBox<T> {}
+unsafe impl<T: Send + Sync> Sync for OnceBox<T> {}
+
+impl<T> Drop for OnceBox<T> {
+    fn drop(&mut self) {
+        self.take();
+    }
+}
diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs
index 0e658328c2e..733f51cae8c 100644
--- a/library/std/src/sys/sync/rwlock/queue.rs
+++ b/library/std/src/sys/sync/rwlock/queue.rs
@@ -113,7 +113,7 @@ use crate::mem;
 use crate::ptr::{self, NonNull, null_mut, without_provenance_mut};
 use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release};
 use crate::sync::atomic::{AtomicBool, AtomicPtr};
-use crate::thread::{self, Thread};
+use crate::thread::{self, Thread, ThreadId};
 
 // Locking uses exponential backoff. `SPIN_COUNT` indicates how many times the
 // locking operation will be retried.
@@ -200,7 +200,9 @@ impl Node {
     fn prepare(&mut self) {
         // Fall back to creating an unnamed `Thread` handle to allow locking in
         // TLS destructors.
-        self.thread.get_or_init(|| thread::try_current().unwrap_or_else(Thread::new_unnamed));
+        self.thread.get_or_init(|| {
+            thread::try_current().unwrap_or_else(|| Thread::new_unnamed(ThreadId::new()))
+        });
         self.completed = AtomicBool::new(false);
     }
 
diff --git a/library/std/src/sys/sync/rwlock/teeos.rs b/library/std/src/sys/sync/rwlock/teeos.rs
index ef9b1ab5154..76343022383 100644
--- a/library/std/src/sys/sync/rwlock/teeos.rs
+++ b/library/std/src/sys/sync/rwlock/teeos.rs
@@ -14,22 +14,22 @@ impl RwLock {
 
     #[inline]
     pub fn read(&self) {
-        unsafe { self.inner.lock() };
+        self.inner.lock()
     }
 
     #[inline]
     pub fn try_read(&self) -> bool {
-        unsafe { self.inner.try_lock() }
+        self.inner.try_lock()
     }
 
     #[inline]
     pub fn write(&self) {
-        unsafe { self.inner.lock() };
+        self.inner.lock()
     }
 
     #[inline]
     pub unsafe fn try_write(&self) -> bool {
-        unsafe { self.inner.try_lock() }
+        self.inner.try_lock()
     }
 
     #[inline]
diff --git a/library/std/src/sys/thread_local/guard/apple.rs b/library/std/src/sys/thread_local/guard/apple.rs
index 6c27f7ae35c..fa25b116622 100644
--- a/library/std/src/sys/thread_local/guard/apple.rs
+++ b/library/std/src/sys/thread_local/guard/apple.rs
@@ -26,6 +26,7 @@ pub fn enable() {
     unsafe extern "C" fn run_dtors(_: *mut u8) {
         unsafe {
             destructors::run();
+            crate::rt::thread_cleanup();
         }
     }
 }
diff --git a/library/std/src/sys/thread_local/guard/key.rs b/library/std/src/sys/thread_local/guard/key.rs
index 77575547c14..59581e6f281 100644
--- a/library/std/src/sys/thread_local/guard/key.rs
+++ b/library/std/src/sys/thread_local/guard/key.rs
@@ -3,10 +3,12 @@
 //! that will run all native TLS destructors in the destructor list.
 
 use crate::ptr;
-use crate::sys::thread_local::destructors;
 use crate::sys::thread_local::key::{LazyKey, set};
 
+#[cfg(target_thread_local)]
 pub fn enable() {
+    use crate::sys::thread_local::destructors;
+
     static DTORS: LazyKey = LazyKey::new(Some(run));
 
     // Setting the key value to something other than NULL will result in the
@@ -18,6 +20,41 @@ pub fn enable() {
     unsafe extern "C" fn run(_: *mut u8) {
         unsafe {
             destructors::run();
+            // On platforms with `__cxa_thread_atexit_impl`, `destructors::run`
+            // does nothing on newer systems as the TLS destructors are
+            // registered with the system. But because all of those platforms
+            // call the destructors of TLS keys after the registered ones, this
+            // function will still be run last (at the time of writing).
+            crate::rt::thread_cleanup();
+        }
+    }
+}
+
+/// On platforms with key-based TLS, the system runs the destructors for us.
+/// We still have to make sure that [`crate::rt::thread_cleanup`] is called,
+/// however. This is done by defering the execution of a TLS destructor to
+/// the next round of destruction inside the TLS destructors.
+#[cfg(not(target_thread_local))]
+pub fn enable() {
+    const DEFER: *mut u8 = ptr::without_provenance_mut(1);
+    const RUN: *mut u8 = ptr::without_provenance_mut(2);
+
+    static CLEANUP: LazyKey = LazyKey::new(Some(run));
+
+    unsafe { set(CLEANUP.force(), DEFER) }
+
+    unsafe extern "C" fn run(state: *mut u8) {
+        if state == DEFER {
+            // Make sure that this function is run again in the next round of
+            // TLS destruction. If there is no futher round, there will be leaks,
+            // but that's okay, `thread_cleanup` is not guaranteed to be called.
+            unsafe { set(CLEANUP.force(), RUN) }
+        } else {
+            debug_assert_eq!(state, RUN);
+            // If the state is still RUN in the next round of TLS destruction,
+            // it means that no other TLS destructors defined by this runtime
+            // have been run, as they would have set the state to DEFER.
+            crate::rt::thread_cleanup();
         }
     }
 }
diff --git a/library/std/src/sys/thread_local/guard/solid.rs b/library/std/src/sys/thread_local/guard/solid.rs
index 054b2d561c8..3bcd46c481d 100644
--- a/library/std/src/sys/thread_local/guard/solid.rs
+++ b/library/std/src/sys/thread_local/guard/solid.rs
@@ -19,6 +19,9 @@ pub fn enable() {
     }
 
     unsafe extern "C" fn tls_dtor(_unused: *mut u8) {
-        unsafe { destructors::run() };
+        unsafe {
+            destructors::run();
+            crate::rt::thread_cleanup();
+        }
     }
 }
diff --git a/library/std/src/sys/thread_local/guard/windows.rs b/library/std/src/sys/thread_local/guard/windows.rs
index bf94f7d6e3d..7ee8e695c75 100644
--- a/library/std/src/sys/thread_local/guard/windows.rs
+++ b/library/std/src/sys/thread_local/guard/windows.rs
@@ -80,13 +80,13 @@ pub static CALLBACK: unsafe extern "system" fn(*mut c_void, u32, *mut c_void) =
 
 unsafe extern "system" fn tls_callback(_h: *mut c_void, dw_reason: u32, _pv: *mut c_void) {
     if dw_reason == c::DLL_THREAD_DETACH || dw_reason == c::DLL_PROCESS_DETACH {
-        #[cfg(target_thread_local)]
         unsafe {
+            #[cfg(target_thread_local)]
             super::super::destructors::run();
-        }
-        #[cfg(not(target_thread_local))]
-        unsafe {
+            #[cfg(not(target_thread_local))]
             super::super::key::run_dtors();
+
+            crate::rt::thread_cleanup();
         }
     }
 }
diff --git a/library/std/src/sys/thread_local/key/xous.rs b/library/std/src/sys/thread_local/key/xous.rs
index 295fb848b30..2ab4bba7d8e 100644
--- a/library/std/src/sys/thread_local/key/xous.rs
+++ b/library/std/src/sys/thread_local/key/xous.rs
@@ -212,4 +212,6 @@ unsafe fn run_dtors() {
             unsafe { cur = (*cur).next };
         }
     }
+
+    crate::rt::thread_cleanup();
 }
diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs
index 3d1b91a7ea0..31d3b439060 100644
--- a/library/std/src/sys/thread_local/mod.rs
+++ b/library/std/src/sys/thread_local/mod.rs
@@ -31,12 +31,15 @@ cfg_if::cfg_if! {
     ))] {
         mod statik;
         pub use statik::{EagerStorage, LazyStorage, thread_local_inner};
+        pub(crate) use statik::{LocalPointer, local_pointer};
     } else if #[cfg(target_thread_local)] {
         mod native;
         pub use native::{EagerStorage, LazyStorage, thread_local_inner};
+        pub(crate) use native::{LocalPointer, local_pointer};
     } else {
         mod os;
         pub use os::{Storage, thread_local_inner};
+        pub(crate) use os::{LocalPointer, local_pointer};
     }
 }
 
@@ -72,36 +75,47 @@ pub(crate) mod destructors {
 }
 
 /// This module provides a way to schedule the execution of the destructor list
-/// on systems without a per-variable destructor system.
-mod guard {
+/// and the [runtime cleanup](crate::rt::thread_cleanup) function. Calling `enable`
+/// should ensure that these functions are called at the right times.
+pub(crate) mod guard {
     cfg_if::cfg_if! {
         if #[cfg(all(target_thread_local, target_vendor = "apple"))] {
             mod apple;
-            pub(super) use apple::enable;
+            pub(crate) use apple::enable;
         } else if #[cfg(target_os = "windows")] {
             mod windows;
-            pub(super) use windows::enable;
+            pub(crate) use windows::enable;
         } else if #[cfg(any(
-            all(target_family = "wasm", target_feature = "atomics"),
+            target_family = "wasm",
+            target_os = "uefi",
+            target_os = "zkvm",
         ))] {
-            pub(super) fn enable() {
-                // FIXME: Right now there is no concept of "thread exit", but
-                // this is likely going to show up at some point in the form of
-                // an exported symbol that the wasm runtime is going to be
-                // expected to call. For now we just leak everything, but if
-                // such a function starts to exist it will probably need to
-                // iterate the destructor list with this function:
+            pub(crate) fn enable() {
+                // FIXME: Right now there is no concept of "thread exit" on
+                // wasm, but this is likely going to show up at some point in
+                // the form of an exported symbol that the wasm runtime is going
+                // to be expected to call. For now we just leak everything, but
+                // if such a function starts to exist it will probably need to
+                // iterate the destructor list with these functions:
+                #[cfg(all(target_family = "wasm", target_feature = "atomics"))]
                 #[allow(unused)]
                 use super::destructors::run;
+                #[allow(unused)]
+                use crate::rt::thread_cleanup;
             }
-        } else if #[cfg(target_os = "hermit")] {
-            pub(super) fn enable() {}
+        } else if #[cfg(any(
+            target_os = "hermit",
+            target_os = "xous",
+        ))] {
+            // `std` is the only runtime, so it just calls the destructor functions
+            // itself when the time comes.
+            pub(crate) fn enable() {}
         } else if #[cfg(target_os = "solid_asp3")] {
             mod solid;
-            pub(super) use solid::enable;
-        } else if #[cfg(all(target_thread_local, not(target_family = "wasm")))] {
+            pub(crate) use solid::enable;
+        } else {
             mod key;
-            pub(super) use key::enable;
+            pub(crate) use key::enable;
         }
     }
 }
diff --git a/library/std/src/sys/thread_local/native/mod.rs b/library/std/src/sys/thread_local/native/mod.rs
index 1cc45fe892d..f498dee0899 100644
--- a/library/std/src/sys/thread_local/native/mod.rs
+++ b/library/std/src/sys/thread_local/native/mod.rs
@@ -29,6 +29,9 @@
 //! eliminates the `Destroyed` state for these values, which can allow more niche
 //! optimizations to occur for the `State` enum. For `Drop` types, `()` is used.
 
+use crate::cell::Cell;
+use crate::ptr;
+
 mod eager;
 mod lazy;
 
@@ -107,3 +110,31 @@ pub macro thread_local_inner {
             $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
     },
 }
+
+#[rustc_macro_transparency = "semitransparent"]
+pub(crate) macro local_pointer {
+    () => {},
+    ($vis:vis static $name:ident; $($rest:tt)*) => {
+        #[thread_local]
+        $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
+        $crate::sys::thread_local::local_pointer! { $($rest)* }
+    },
+}
+
+pub(crate) struct LocalPointer {
+    p: Cell<*mut ()>,
+}
+
+impl LocalPointer {
+    pub const fn __new() -> LocalPointer {
+        LocalPointer { p: Cell::new(ptr::null_mut()) }
+    }
+
+    pub fn get(&self) -> *mut () {
+        self.p.get()
+    }
+
+    pub fn set(&self, p: *mut ()) {
+        self.p.set(p)
+    }
+}
diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs
index f09c396ef0f..26ce3322a16 100644
--- a/library/std/src/sys/thread_local/os.rs
+++ b/library/std/src/sys/thread_local/os.rs
@@ -1,8 +1,8 @@
-use super::abort_on_dtor_unwind;
+use super::key::{Key, LazyKey, get, set};
+use super::{abort_on_dtor_unwind, guard};
 use crate::cell::Cell;
 use crate::marker::PhantomData;
 use crate::ptr;
-use crate::sys::thread_local::key::{Key, LazyKey, get, set};
 
 #[doc(hidden)]
 #[allow_internal_unstable(thread_local_internals)]
@@ -138,5 +138,35 @@ unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
         drop(ptr);
         // SAFETY: `key` is the TLS key `ptr` was stored under.
         unsafe { set(key, ptr::null_mut()) };
+        // Make sure that the runtime cleanup will be performed
+        // after the next round of TLS destruction.
+        guard::enable();
     });
 }
+
+#[rustc_macro_transparency = "semitransparent"]
+pub(crate) macro local_pointer {
+    () => {},
+    ($vis:vis static $name:ident; $($rest:tt)*) => {
+        $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
+        $crate::sys::thread_local::local_pointer! { $($rest)* }
+    },
+}
+
+pub(crate) struct LocalPointer {
+    key: LazyKey,
+}
+
+impl LocalPointer {
+    pub const fn __new() -> LocalPointer {
+        LocalPointer { key: LazyKey::new(None) }
+    }
+
+    pub fn get(&'static self) -> *mut () {
+        unsafe { get(self.key.force()) as *mut () }
+    }
+
+    pub fn set(&'static self, p: *mut ()) {
+        unsafe { set(self.key.force(), p as *mut u8) }
+    }
+}
diff --git a/library/std/src/sys/thread_local/statik.rs b/library/std/src/sys/thread_local/statik.rs
index a3451ab74e0..ba94caa6690 100644
--- a/library/std/src/sys/thread_local/statik.rs
+++ b/library/std/src/sys/thread_local/statik.rs
@@ -1,7 +1,8 @@
 //! On some targets like wasm there's no threads, so no need to generate
 //! thread locals and we can instead just use plain statics!
 
-use crate::cell::UnsafeCell;
+use crate::cell::{Cell, UnsafeCell};
+use crate::ptr;
 
 #[doc(hidden)]
 #[allow_internal_unstable(thread_local_internals)]
@@ -93,3 +94,33 @@ impl<T> LazyStorage<T> {
 
 // SAFETY: the target doesn't have threads.
 unsafe impl<T> Sync for LazyStorage<T> {}
+
+#[rustc_macro_transparency = "semitransparent"]
+pub(crate) macro local_pointer {
+    () => {},
+    ($vis:vis static $name:ident; $($rest:tt)*) => {
+        $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
+        $crate::sys::thread_local::local_pointer! { $($rest)* }
+    },
+}
+
+pub(crate) struct LocalPointer {
+    p: Cell<*mut ()>,
+}
+
+impl LocalPointer {
+    pub const fn __new() -> LocalPointer {
+        LocalPointer { p: Cell::new(ptr::null_mut()) }
+    }
+
+    pub fn get(&self) -> *mut () {
+        self.p.get()
+    }
+
+    pub fn set(&self, p: *mut ()) {
+        self.p.set(p)
+    }
+}
+
+// SAFETY: the target doesn't have threads.
+unsafe impl Sync for LocalPointer {}
diff --git a/library/std/src/sys_common/io.rs b/library/std/src/sys_common/io.rs
index e386c955f37..6f6f282d432 100644
--- a/library/std/src/sys_common/io.rs
+++ b/library/std/src/sys_common/io.rs
@@ -3,7 +3,7 @@
 pub const DEFAULT_BUF_SIZE: usize = if cfg!(target_os = "espidf") { 512 } else { 8 * 1024 };
 
 #[cfg(test)]
-#[allow(dead_code)] // not used on emscripten
+#[allow(dead_code)] // not used on emscripten and wasi
 pub mod test {
     use rand::RngCore;
 
diff --git a/library/std/src/sys_common/lazy_box.rs b/library/std/src/sys_common/lazy_box.rs
deleted file mode 100644
index b45b05f63ba..00000000000
--- a/library/std/src/sys_common/lazy_box.rs
+++ /dev/null
@@ -1,88 +0,0 @@
-#![allow(dead_code)] // Only used on some platforms.
-
-// This is used to wrap pthread {Mutex, Condvar, RwLock} in.
-
-use crate::marker::PhantomData;
-use crate::ops::{Deref, DerefMut};
-use crate::ptr::null_mut;
-use crate::sync::atomic::AtomicPtr;
-use crate::sync::atomic::Ordering::{AcqRel, Acquire};
-
-pub(crate) struct LazyBox<T: LazyInit> {
-    ptr: AtomicPtr<T>,
-    _phantom: PhantomData<T>,
-}
-
-pub(crate) trait LazyInit {
-    /// This is called before the box is allocated, to provide the value to
-    /// move into the new box.
-    ///
-    /// It might be called more than once per LazyBox, as multiple threads
-    /// might race to initialize it concurrently, each constructing and initializing
-    /// their own box. All but one of them will be passed to `cancel_init` right after.
-    fn init() -> Box<Self>;
-
-    /// Any surplus boxes from `init()` that lost the initialization race
-    /// are passed to this function for disposal.
-    ///
-    /// The default implementation calls destroy().
-    fn cancel_init(x: Box<Self>) {
-        Self::destroy(x);
-    }
-
-    /// This is called to destroy a used box.
-    ///
-    /// The default implementation just drops it.
-    fn destroy(_: Box<Self>) {}
-}
-
-impl<T: LazyInit> LazyBox<T> {
-    #[inline]
-    pub const fn new() -> Self {
-        Self { ptr: AtomicPtr::new(null_mut()), _phantom: PhantomData }
-    }
-
-    #[inline]
-    fn get_pointer(&self) -> *mut T {
-        let ptr = self.ptr.load(Acquire);
-        if ptr.is_null() { self.initialize() } else { ptr }
-    }
-
-    #[cold]
-    fn initialize(&self) -> *mut T {
-        let new_ptr = Box::into_raw(T::init());
-        match self.ptr.compare_exchange(null_mut(), new_ptr, AcqRel, Acquire) {
-            Ok(_) => new_ptr,
-            Err(ptr) => {
-                // Lost the race to another thread.
-                // Drop the box we created, and use the one from the other thread instead.
-                T::cancel_init(unsafe { Box::from_raw(new_ptr) });
-                ptr
-            }
-        }
-    }
-}
-
-impl<T: LazyInit> Deref for LazyBox<T> {
-    type Target = T;
-    #[inline]
-    fn deref(&self) -> &T {
-        unsafe { &*self.get_pointer() }
-    }
-}
-
-impl<T: LazyInit> DerefMut for LazyBox<T> {
-    #[inline]
-    fn deref_mut(&mut self) -> &mut T {
-        unsafe { &mut *self.get_pointer() }
-    }
-}
-
-impl<T: LazyInit> Drop for LazyBox<T> {
-    fn drop(&mut self) {
-        let ptr = *self.ptr.get_mut();
-        if !ptr.is_null() {
-            T::destroy(unsafe { Box::from_raw(ptr) });
-        }
-    }
-}
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 1c884f107be..4f7a131f6bb 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -22,7 +22,6 @@ mod tests;
 
 pub mod fs;
 pub mod io;
-pub mod lazy_box;
 pub mod process;
 pub mod wstr;
 pub mod wtf8;
@@ -32,7 +31,8 @@ cfg_if::cfg_if! {
         all(unix, not(target_os = "l4re")),
         windows,
         target_os = "hermit",
-        target_os = "solid_asp3"
+        target_os = "solid_asp3",
+        all(target_os = "wasi", target_env = "p2")
     ))] {
         pub mod net;
     } else {
diff --git a/library/std/src/thread/current.rs b/library/std/src/thread/current.rs
new file mode 100644
index 00000000000..b38149a0da7
--- /dev/null
+++ b/library/std/src/thread/current.rs
@@ -0,0 +1,252 @@
+use super::{Thread, ThreadId};
+use crate::mem::ManuallyDrop;
+use crate::ptr;
+use crate::sys::thread_local::local_pointer;
+
+const NONE: *mut () = ptr::null_mut();
+const BUSY: *mut () = ptr::without_provenance_mut(1);
+const DESTROYED: *mut () = ptr::without_provenance_mut(2);
+
+local_pointer! {
+    static CURRENT;
+}
+
+/// Persistent storage for the thread ID.
+///
+/// We store the thread ID so that it never gets destroyed during the lifetime
+/// of a thread, either using `#[thread_local]` or multiple `local_pointer!`s.
+mod id {
+    use super::*;
+
+    cfg_if::cfg_if! {
+        if #[cfg(target_thread_local)] {
+            use crate::cell::Cell;
+
+            #[thread_local]
+            static ID: Cell<Option<ThreadId>> = Cell::new(None);
+
+            pub(super) const CHEAP: bool = true;
+
+            pub(super) fn get() -> Option<ThreadId> {
+                ID.get()
+            }
+
+            pub(super) fn set(id: ThreadId) {
+                ID.set(Some(id))
+            }
+        } else if #[cfg(target_pointer_width = "16")] {
+            local_pointer! {
+                static ID0;
+                static ID16;
+                static ID32;
+                static ID48;
+            }
+
+            pub(super) const CHEAP: bool = false;
+
+            pub(super) fn get() -> Option<ThreadId> {
+                let id0 = ID0.get().addr() as u64;
+                let id16 = ID16.get().addr() as u64;
+                let id32 = ID32.get().addr() as u64;
+                let id48 = ID48.get().addr() as u64;
+                ThreadId::from_u64((id48 << 48) + (id32 << 32) + (id16 << 16) + id0)
+            }
+
+            pub(super) fn set(id: ThreadId) {
+                let val = id.as_u64().get();
+                ID0.set(ptr::without_provenance_mut(val as usize));
+                ID16.set(ptr::without_provenance_mut((val >> 16) as usize));
+                ID32.set(ptr::without_provenance_mut((val >> 32) as usize));
+                ID48.set(ptr::without_provenance_mut((val >> 48) as usize));
+            }
+        } else if #[cfg(target_pointer_width = "32")] {
+            local_pointer! {
+                static ID0;
+                static ID32;
+            }
+
+            pub(super) const CHEAP: bool = false;
+
+            pub(super) fn get() -> Option<ThreadId> {
+                let id0 = ID0.get().addr() as u64;
+                let id32 = ID32.get().addr() as u64;
+                ThreadId::from_u64((id32 << 32) + id0)
+            }
+
+            pub(super) fn set(id: ThreadId) {
+                let val = id.as_u64().get();
+                ID0.set(ptr::without_provenance_mut(val as usize));
+                ID32.set(ptr::without_provenance_mut((val >> 32) as usize));
+            }
+        } else {
+            local_pointer! {
+                static ID;
+            }
+
+            pub(super) const CHEAP: bool = true;
+
+            pub(super) fn get() -> Option<ThreadId> {
+                let id = ID.get().addr() as u64;
+                ThreadId::from_u64(id)
+            }
+
+            pub(super) fn set(id: ThreadId) {
+                let val = id.as_u64().get();
+                ID.set(ptr::without_provenance_mut(val as usize));
+            }
+        }
+    }
+
+    #[inline]
+    pub(super) fn get_or_init() -> ThreadId {
+        get().unwrap_or_else(
+            #[cold]
+            || {
+                let id = ThreadId::new();
+                id::set(id);
+                id
+            },
+        )
+    }
+}
+
+/// Sets the thread handle for the current thread.
+///
+/// Aborts if the handle or the ID has been set already.
+pub(crate) fn set_current(thread: Thread) {
+    if CURRENT.get() != NONE || id::get().is_some() {
+        // Using `panic` here can add ~3kB to the binary size. We have complete
+        // control over where this is called, so just abort if there is a bug.
+        rtabort!("thread::set_current should only be called once per thread");
+    }
+
+    id::set(thread.id());
+
+    // Make sure that `crate::rt::thread_cleanup` will be run, which will
+    // call `drop_current`.
+    crate::sys::thread_local::guard::enable();
+    CURRENT.set(thread.into_raw().cast_mut());
+}
+
+/// Gets the id of the thread that invokes it.
+///
+/// This function will always succeed, will always return the same value for
+/// one thread and is guaranteed not to call the global allocator.
+#[inline]
+pub(crate) fn current_id() -> ThreadId {
+    // If accessing the persistant thread ID takes multiple TLS accesses, try
+    // to retrieve it from the current thread handle, which will only take one
+    // TLS access.
+    if !id::CHEAP {
+        let current = CURRENT.get();
+        if current > DESTROYED {
+            unsafe {
+                let current = ManuallyDrop::new(Thread::from_raw(current));
+                return current.id();
+            }
+        }
+    }
+
+    id::get_or_init()
+}
+
+/// Gets a handle to the thread that invokes it, if the handle has been initialized.
+pub(crate) fn try_current() -> Option<Thread> {
+    let current = CURRENT.get();
+    if current > DESTROYED {
+        unsafe {
+            let current = ManuallyDrop::new(Thread::from_raw(current));
+            Some((*current).clone())
+        }
+    } else {
+        None
+    }
+}
+
+/// Gets a handle to the thread that invokes it.
+///
+/// # Examples
+///
+/// Getting a handle to the current thread with `thread::current()`:
+///
+/// ```
+/// use std::thread;
+///
+/// let handler = thread::Builder::new()
+///     .name("named thread".into())
+///     .spawn(|| {
+///         let handle = thread::current();
+///         assert_eq!(handle.name(), Some("named thread"));
+///     })
+///     .unwrap();
+///
+/// handler.join().unwrap();
+/// ```
+#[must_use]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn current() -> Thread {
+    let current = CURRENT.get();
+    if current > DESTROYED {
+        unsafe {
+            let current = ManuallyDrop::new(Thread::from_raw(current));
+            (*current).clone()
+        }
+    } else {
+        init_current(current)
+    }
+}
+
+#[cold]
+fn init_current(current: *mut ()) -> Thread {
+    if current == NONE {
+        CURRENT.set(BUSY);
+        // If the thread ID was initialized already, use it.
+        let id = id::get_or_init();
+        let thread = Thread::new_unnamed(id);
+
+        // Make sure that `crate::rt::thread_cleanup` will be run, which will
+        // call `drop_current`.
+        crate::sys::thread_local::guard::enable();
+        CURRENT.set(thread.clone().into_raw().cast_mut());
+        thread
+    } else if current == BUSY {
+        // BUSY exists solely for this check, but as it is in the slow path, the
+        // extra TLS write above shouldn't matter. The alternative is nearly always
+        // a stack overflow.
+
+        // If you came across this message, contact the author of your allocator.
+        // If you are said author: A surprising amount of functions inside the
+        // standard library (e.g. `Mutex`, `thread_local!`, `File` when using long
+        // paths, even `panic!` when using unwinding), need memory allocation, so
+        // you'll get circular dependencies all over the place when using them.
+        // I (joboet) highly recommend using only APIs from core in your allocator
+        // and implementing your own system abstractions. Still, if you feel that
+        // a particular API should be entirely allocation-free, feel free to open
+        // an issue on the Rust repository, we'll see what we can do.
+        rtabort!(
+            "\n
+            Attempted to access thread-local data while allocating said data.\n
+            Do not access functions that allocate in the global allocator!\n
+            This is a bug in the global allocator.\n
+        "
+        )
+    } else {
+        debug_assert_eq!(current, DESTROYED);
+        panic!(
+            "use of std::thread::current() is not possible after the thread's
+         local data has been destroyed"
+        )
+    }
+}
+
+/// This should be run in [`crate::rt::thread_cleanup`] to reset the thread
+/// handle.
+pub(crate) fn drop_current() {
+    let current = CURRENT.get();
+    if current > DESTROYED {
+        unsafe {
+            CURRENT.set(DESTROYED);
+            drop(Thread::from_raw(current));
+        }
+    }
+}
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index f147c5fdcd1..88bf186700f 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -2,7 +2,7 @@
 
 #![unstable(feature = "thread_local_internals", issue = "none")]
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 #[cfg(test)]
diff --git a/library/std/src/thread/local/tests.rs b/library/std/src/thread/local/tests.rs
index 6abb9b85a2e..9d4f52a0921 100644
--- a/library/std/src/thread/local/tests.rs
+++ b/library/std/src/thread/local/tests.rs
@@ -1,7 +1,7 @@
 use crate::cell::{Cell, UnsafeCell};
 use crate::sync::atomic::{AtomicU8, Ordering};
 use crate::sync::{Arc, Condvar, Mutex};
-use crate::thread::{self, LocalKey};
+use crate::thread::{self, Builder, LocalKey};
 use crate::thread_local;
 
 #[derive(Clone, Default)]
@@ -343,3 +343,34 @@ fn join_orders_after_tls_destructors() {
         jh2.join().unwrap();
     }
 }
+
+// Test that thread::current is still available in TLS destructors.
+#[test]
+fn thread_current_in_dtor() {
+    // Go through one round of TLS destruction first.
+    struct Defer;
+    impl Drop for Defer {
+        fn drop(&mut self) {
+            RETRIEVE.with(|_| {});
+        }
+    }
+
+    struct RetrieveName;
+    impl Drop for RetrieveName {
+        fn drop(&mut self) {
+            *NAME.lock().unwrap() = Some(thread::current().name().unwrap().to_owned());
+        }
+    }
+
+    static NAME: Mutex<Option<String>> = Mutex::new(None);
+
+    thread_local! {
+        static DEFER: Defer = const { Defer };
+        static RETRIEVE: RetrieveName = const { RetrieveName };
+    }
+
+    Builder::new().name("test".to_owned()).spawn(|| DEFER.with(|_| {})).unwrap().join().unwrap();
+    let name = NAME.lock().unwrap();
+    let name = name.as_ref().unwrap();
+    assert_eq!(name, "test");
+}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 41f02af9366..d1d4eabb9bd 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -141,7 +141,7 @@
 //! [`Result`]: crate::result::Result
 //! [`Ok`]: crate::result::Result::Ok
 //! [`Err`]: crate::result::Result::Err
-//! [`thread::current`]: current
+//! [`thread::current`]: current::current
 //! [`thread::Result`]: Result
 //! [`unpark`]: Thread::unpark
 //! [`thread::park_timeout`]: park_timeout
@@ -155,11 +155,11 @@
 // Under `test`, `__FastLocalKeyInner` seems unused.
 #![cfg_attr(test, allow(dead_code))]
 
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
 mod tests;
 
 use crate::any::Any;
-use crate::cell::{Cell, OnceCell, UnsafeCell};
+use crate::cell::UnsafeCell;
 use crate::ffi::CStr;
 use crate::marker::PhantomData;
 use crate::mem::{self, ManuallyDrop, forget};
@@ -179,6 +179,12 @@ mod scoped;
 #[stable(feature = "scoped_threads", since = "1.63.0")]
 pub use scoped::{Scope, ScopedJoinHandle, scope};
 
+mod current;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use current::current;
+pub(crate) use current::{current_id, drop_current, set_current, try_current};
+
 ////////////////////////////////////////////////////////////////////////////////
 // Thread-local storage
 ////////////////////////////////////////////////////////////////////////////////
@@ -471,7 +477,11 @@ impl Builder {
             amt
         });
 
-        let my_thread = name.map_or_else(Thread::new_unnamed, Thread::new);
+        let id = ThreadId::new();
+        let my_thread = match name {
+            Some(name) => Thread::new(id, name.into()),
+            None => Thread::new_unnamed(id),
+        };
         let their_thread = my_thread.clone();
 
         let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet {
@@ -509,6 +519,9 @@ impl Builder {
 
         let f = MaybeDangling::new(f);
         let main = move || {
+            // Immediately store the thread handle to avoid setting it or its ID
+            // twice, which would cause an abort.
+            set_current(their_thread.clone());
             if let Some(name) = their_thread.cname() {
                 imp::Thread::set_name(name);
             }
@@ -516,7 +529,6 @@ impl Builder {
             crate::io::set_output_capture(output_capture);
 
             let f = f.into_inner();
-            set_current(their_thread);
             let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
                 crate::sys::backtrace::__rust_begin_short_backtrace(f)
             }));
@@ -664,6 +676,19 @@ impl Builder {
 /// println!("{result}");
 /// ```
 ///
+/// # Notes
+///
+/// This function has the same minimal guarantee regarding "foreign" unwinding operations (e.g.
+/// an exception thrown from C++ code, or a `panic!` in Rust code compiled or linked with a
+/// different runtime) as [`catch_unwind`]; namely, if the thread created with `thread::spawn`
+/// unwinds all the way to the root with such an exception, one of two behaviors are possible,
+/// and it is unspecified which will occur:
+///
+/// * The process aborts.
+/// * The process does not abort, and [`join`] will return a `Result::Err`
+///   containing an opaque type.
+///
+/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html
 /// [`channels`]: crate::sync::mpsc
 /// [`join`]: JoinHandle::join
 /// [`Err`]: crate::result::Result::Err
@@ -677,84 +702,6 @@ where
     Builder::new().spawn(f).expect("failed to spawn thread")
 }
 
-thread_local! {
-    // Invariant: `CURRENT` and `CURRENT_ID` will always be initialized together.
-    // If `CURRENT` is initialized, then `CURRENT_ID` will hold the same value
-    // as `CURRENT.id()`.
-    static CURRENT: OnceCell<Thread> = const { OnceCell::new() };
-    static CURRENT_ID: Cell<Option<ThreadId>> = const { Cell::new(None) };
-}
-
-/// Sets the thread handle for the current thread.
-///
-/// Aborts if the handle has been set already to reduce code size.
-pub(crate) fn set_current(thread: Thread) {
-    let tid = thread.id();
-    // Using `unwrap` here can add ~3kB to the binary size. We have complete
-    // control over where this is called, so just abort if there is a bug.
-    CURRENT.with(|current| match current.set(thread) {
-        Ok(()) => CURRENT_ID.set(Some(tid)),
-        Err(_) => rtabort!("thread::set_current should only be called once per thread"),
-    });
-}
-
-/// Gets a handle to the thread that invokes it.
-///
-/// In contrast to the public `current` function, this will not panic if called
-/// from inside a TLS destructor.
-pub(crate) fn try_current() -> Option<Thread> {
-    CURRENT
-        .try_with(|current| {
-            current
-                .get_or_init(|| {
-                    let thread = Thread::new_unnamed();
-                    CURRENT_ID.set(Some(thread.id()));
-                    thread
-                })
-                .clone()
-        })
-        .ok()
-}
-
-/// Gets the id of the thread that invokes it.
-#[inline]
-pub(crate) fn current_id() -> ThreadId {
-    CURRENT_ID.get().unwrap_or_else(|| {
-        // If `CURRENT_ID` isn't initialized yet, then `CURRENT` must also not be initialized.
-        // `current()` will initialize both `CURRENT` and `CURRENT_ID` so subsequent calls to
-        // `current_id()` will succeed immediately.
-        current().id()
-    })
-}
-
-/// Gets a handle to the thread that invokes it.
-///
-/// # Examples
-///
-/// Getting a handle to the current thread with `thread::current()`:
-///
-/// ```
-/// use std::thread;
-///
-/// let handler = thread::Builder::new()
-///     .name("named thread".into())
-///     .spawn(|| {
-///         let handle = thread::current();
-///         assert_eq!(handle.name(), Some("named thread"));
-///     })
-///     .unwrap();
-///
-/// handler.join().unwrap();
-/// ```
-#[must_use]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn current() -> Thread {
-    try_current().expect(
-        "use of std::thread::current() is not possible \
-         after the thread's local data has been destroyed",
-    )
-}
-
 /// Cooperatively gives up a timeslice to the OS scheduler.
 ///
 /// This calls the underlying OS scheduler's yield primitive, signaling
@@ -1212,8 +1159,11 @@ pub fn park_timeout(dur: Duration) {
 pub struct ThreadId(NonZero<u64>);
 
 impl ThreadId {
+    // DO NOT rely on this value.
+    const MAIN_THREAD: ThreadId = ThreadId(unsafe { NonZero::new_unchecked(1) });
+
     // Generate a new unique thread ID.
-    fn new() -> ThreadId {
+    pub(crate) fn new() -> ThreadId {
         #[cold]
         fn exhausted() -> ! {
             panic!("failed to generate unique thread ID: bitspace exhausted")
@@ -1223,7 +1173,7 @@ impl ThreadId {
             if #[cfg(target_has_atomic = "64")] {
                 use crate::sync::atomic::AtomicU64;
 
-                static COUNTER: AtomicU64 = AtomicU64::new(0);
+                static COUNTER: AtomicU64 = AtomicU64::new(1);
 
                 let mut last = COUNTER.load(Ordering::Relaxed);
                 loop {
@@ -1239,7 +1189,7 @@ impl ThreadId {
             } else {
                 use crate::sync::{Mutex, PoisonError};
 
-                static COUNTER: Mutex<u64> = Mutex::new(0);
+                static COUNTER: Mutex<u64> = Mutex::new(1);
 
                 let mut counter = COUNTER.lock().unwrap_or_else(PoisonError::into_inner);
                 let Some(id) = counter.checked_add(1) else {
@@ -1256,6 +1206,11 @@ impl ThreadId {
         }
     }
 
+    #[cfg(not(target_thread_local))]
+    fn from_u64(v: u64) -> Option<ThreadId> {
+        NonZero::new(v).map(ThreadId)
+    }
+
     /// This returns a numeric identifier for the thread identified by this
     /// `ThreadId`.
     ///
@@ -1356,27 +1311,27 @@ impl Inner {
 /// should instead use a function like `spawn` to create new threads, see the
 /// docs of [`Builder`] and [`spawn`] for more details.
 ///
-/// [`thread::current`]: current
+/// [`thread::current`]: current::current
 pub struct Thread {
     inner: Pin<Arc<Inner>>,
 }
 
 impl Thread {
     /// Used only internally to construct a thread object without spawning.
-    pub(crate) fn new(name: String) -> Thread {
-        Self::new_inner(ThreadName::Other(name.into()))
+    pub(crate) fn new(id: ThreadId, name: String) -> Thread {
+        Self::new_inner(id, ThreadName::Other(name.into()))
     }
 
-    pub(crate) fn new_unnamed() -> Thread {
-        Self::new_inner(ThreadName::Unnamed)
+    pub(crate) fn new_unnamed(id: ThreadId) -> Thread {
+        Self::new_inner(id, ThreadName::Unnamed)
     }
 
     // Used in runtime to construct main thread
     pub(crate) fn new_main() -> Thread {
-        Self::new_inner(ThreadName::Main)
+        Self::new_inner(ThreadId::MAIN_THREAD, ThreadName::Main)
     }
 
-    fn new_inner(name: ThreadName) -> Thread {
+    fn new_inner(id: ThreadId, name: ThreadName) -> Thread {
         // We have to use `unsafe` here to construct the `Parker` in-place,
         // which is required for the UNIX implementation.
         //
@@ -1386,7 +1341,7 @@ impl Thread {
             let mut arc = Arc::<Inner>::new_uninit();
             let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr();
             (&raw mut (*ptr).name).write(name);
-            (&raw mut (*ptr).id).write(ThreadId::new());
+            (&raw mut (*ptr).id).write(id);
             Parker::new_in_place(&raw mut (*ptr).parker);
             Pin::new_unchecked(arc.assume_init())
         };
@@ -1784,7 +1739,7 @@ impl<T> JoinHandle<T> {
     /// operations that happen after `join` returns.
     ///
     /// If the associated thread panics, [`Err`] is returned with the parameter given
-    /// to [`panic!`].
+    /// to [`panic!`] (though see the Notes below).
     ///
     /// [`Err`]: crate::result::Result::Err
     /// [atomic memory orderings]: crate::sync::atomic
@@ -1806,6 +1761,18 @@ impl<T> JoinHandle<T> {
     /// }).unwrap();
     /// join_handle.join().expect("Couldn't join on the associated thread");
     /// ```
+    ///
+    /// # Notes
+    ///
+    /// If a "foreign" unwinding operation (e.g. an exception thrown from C++
+    /// code, or a `panic!` in Rust code compiled or linked with a different
+    /// runtime) unwinds all the way to the thread root, the process may be
+    /// aborted; see the Notes on [`thread::spawn`]. If the process is not
+    /// aborted, this function will return a `Result::Err` containing an opaque
+    /// type.
+    ///
+    /// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html
+    /// [`thread::spawn`]: spawn
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn join(self) -> Result<T> {
         self.0.join()
diff --git a/library/std/tests/create_dir_all_bare.rs b/library/std/tests/create_dir_all_bare.rs
index 8becf713205..30f800c5aa2 100644
--- a/library/std/tests/create_dir_all_bare.rs
+++ b/library/std/tests/create_dir_all_bare.rs
@@ -1,4 +1,4 @@
-#![cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx"))))]
+#![cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi", target_env = "sgx"))))]
 
 //! Note that this test changes the current directory so
 //! should not be in the same process as other tests.
diff --git a/library/std/tests/process_spawning.rs b/library/std/tests/process_spawning.rs
index d249eb7d50a..3e72e371ade 100644
--- a/library/std/tests/process_spawning.rs
+++ b/library/std/tests/process_spawning.rs
@@ -5,7 +5,7 @@ use std::{env, fs, process, str};
 mod common;
 
 #[test]
-#[cfg_attr(miri, ignore)] // Process spawning not supported by Miri
+#[cfg_attr(any(miri, target_os = "wasi"), ignore)] // Process spawning not supported by Miri and wasi
 fn issue_15149() {
     // If we're the parent, copy our own binary to a new directory.
     let my_path = env::current_exe().unwrap();
diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs
index fc9917178b2..83574176186 100644
--- a/library/std/tests/thread.rs
+++ b/library/std/tests/thread.rs
@@ -4,7 +4,7 @@ use std::thread;
 use std::time::Duration;
 
 #[test]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
 #[cfg_attr(miri, ignore)] // Miri does not like the thread leak
 fn sleep_very_long() {
     let finished = Arc::new(Mutex::new(false));
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 952db063636..efcac4f0953 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -84,9 +84,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.1.19"
+version = "1.1.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800"
+checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
 dependencies = [
  "shlex",
 ]
@@ -99,9 +99,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "clap"
-version = "4.5.16"
+version = "4.5.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019"
+checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -109,9 +109,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.15"
+version = "4.5.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6"
+checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b"
 dependencies = [
  "anstyle",
  "clap_lex",
@@ -119,18 +119,18 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.5.18"
+version = "4.5.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ee158892bd7ce77aa15c208abbdb73e155d191c287a659b57abd5adb92feb03"
+checksum = "8937760c3f4c60871870b8c3ee5f9b30771f792a7045c48bcbba999d7d6b3b8e"
 dependencies = [
  "clap",
 ]
 
 [[package]]
 name = "clap_derive"
-version = "4.5.13"
+version = "4.5.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
+checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -161,9 +161,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.13"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad"
+checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
 dependencies = [
  "libc",
 ]
@@ -242,9 +242,9 @@ dependencies = [
 
 [[package]]
 name = "filetime"
-version = "0.2.24"
+version = "0.2.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550"
+checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
 dependencies = [
  "cfg-if",
  "libc",
@@ -264,9 +264,9 @@ dependencies = [
 
 [[package]]
 name = "globset"
-version = "0.4.14"
+version = "0.4.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
+checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19"
 dependencies = [
  "aho-corasick",
  "bstr",
@@ -292,9 +292,9 @@ dependencies = [
 
 [[package]]
 name = "ignore"
-version = "0.4.22"
+version = "0.4.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1"
+checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b"
 dependencies = [
  "crossbeam-deque",
  "globset",
@@ -314,9 +314,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
 
 [[package]]
 name = "junction"
-version = "1.1.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c9c415a9b7b1e86cd5738f39d34c9e78c765da7fb1756dbd7d31b3b0d2e7afa"
+checksum = "72bbdfd737a243da3dfc1f99ee8d6e166480f17ab4ac84d7c34aacd73fc7bd16"
 dependencies = [
  "scopeguard",
  "windows-sys 0.52.0",
@@ -324,9 +324,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.157"
+version = "0.2.159"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "374af5f94e54fa97cf75e945cce8a6b201e88a1a07e688b47dfd2a59c66dbd86"
+checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
 
 [[package]]
 name = "libredox"
@@ -379,9 +379,9 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.36.3"
+version = "0.36.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9"
+checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
 dependencies = [
  "memchr",
 ]
@@ -398,15 +398,15 @@ dependencies = [
 
 [[package]]
 name = "pkg-config"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
 
 [[package]]
 name = "pretty_assertions"
-version = "1.4.0"
+version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66"
+checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
 dependencies = [
  "diff",
  "yansi",
@@ -423,18 +423,18 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.36"
+version = "1.0.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.3"
+version = "0.5.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
+checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b"
 dependencies = [
  "bitflags",
 ]
@@ -458,9 +458,9 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
 
 [[package]]
 name = "rustix"
-version = "0.38.34"
+version = "0.38.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
+checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
 dependencies = [
  "bitflags",
  "errno",
@@ -498,18 +498,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
 
 [[package]]
 name = "serde"
-version = "1.0.208"
+version = "1.0.210"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2"
+checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.208"
+version = "1.0.210"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf"
+checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -518,9 +518,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.125"
+version = "1.0.128"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed"
+checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
 dependencies = [
  "itoa",
  "memchr",
@@ -547,9 +547,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
 [[package]]
 name = "syn"
-version = "2.0.75"
+version = "2.0.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9"
+checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -558,9 +558,9 @@ dependencies = [
 
 [[package]]
 name = "sysinfo"
-version = "0.31.2"
+version = "0.31.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4115055da5f572fff541dd0c4e61b0262977f453cc9fe04be83aba25a89bdab"
+checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be"
 dependencies = [
  "core-foundation-sys",
  "libc",
@@ -571,9 +571,9 @@ dependencies = [
 
 [[package]]
 name = "tar"
-version = "0.4.41"
+version = "0.4.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909"
+checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020"
 dependencies = [
  "filetime",
  "libc",
@@ -606,9 +606,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.12"
+version = "1.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
 
 [[package]]
 name = "version_check"
@@ -833,6 +833,6 @@ dependencies = [
 
 [[package]]
 name = "yansi"
-version = "0.5.1"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
+checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 1959d0a9662..ba505089a00 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -37,7 +37,7 @@ test = false
 # Most of the time updating these dependencies requires modifications to the
 # bootstrap codebase(e.g., https://github.com/rust-lang/rust/issues/124565);
 # otherwise, some targets will fail. That's why these dependencies are explicitly pinned.
-cc = "=1.1.19"
+cc = "=1.1.22"
 cmake = "=0.1.48"
 
 build_helper = { path = "../tools/build_helper" }
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md
index 0ac58645d2d..f036603ee70 100644
--- a/src/bootstrap/README.md
+++ b/src/bootstrap/README.md
@@ -182,10 +182,8 @@ Some general areas that you may be interested in modifying are:
   `Config` struct.
 * Adding a sanity check? Take a look at `bootstrap/src/core/sanity.rs`.
 
-If you make a major change on bootstrap configuration, please remember to:
-
-+ Update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/utils/change_tracker.rs`.
-* Update `change-id = {pull-request-id}` in `config.example.toml`.
+If you make a major change on bootstrap configuration, please add a new entry to
+`CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/utils/change_tracker.rs`.
 
 A 'major change' includes
 
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 49d564642bd..a555a26367d 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -193,7 +193,7 @@ if '--help' in sys.argv or '-h' in sys.argv:
         if option.value:
             print('\t{:30} {}'.format('--{}=VAL'.format(option.name), option.desc))
         else:
-            print('\t{:30} {}'.format('--enable-{}'.format(option.name), option.desc))
+            print('\t{:30} {}'.format('--enable-{}  OR  --disable-{}'.format(option.name, option.name), option.desc))
     print('')
     print('This configure script is a thin configuration shim over the true')
     print('configuration system, `config.toml`. You can explore the comments')
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index d04e2fbeb78..780979ed981 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -95,7 +95,6 @@ fn main() {
     // 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)
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 0e596f0da0e..b5be7d841dd 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -1205,7 +1205,8 @@ pub fn rustc_cargo_env(
     // busting caches (e.g. like #71152).
     if builder.config.llvm_enabled(target) {
         let building_is_expensive =
-            crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target).should_build();
+            crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target, false)
+                .should_build();
         // `top_stage == stage` might be false for `check --stage 1`, if we are building the stage 1 compiler
         let can_skip_build = builder.kind == Kind::Check && builder.top_stage == stage;
         let should_skip_build = building_is_expensive && can_skip_build;
@@ -1922,8 +1923,24 @@ impl Step for Assemble {
         let src_libdir = builder.sysroot_libdir(build_compiler, host);
         for f in builder.read_dir(&src_libdir) {
             let filename = f.file_name().into_string().unwrap();
-            if (is_dylib(&filename) || is_debug_info(&filename)) && !proc_macros.contains(&filename)
+
+            let is_proc_macro = proc_macros.contains(&filename);
+            let is_dylib_or_debug = is_dylib(&filename) || is_debug_info(&filename);
+
+            // If we link statically to stdlib, do not copy the libstd dynamic library file
+            // FIXME: Also do this for Windows once incremental post-optimization stage0 tests
+            // work without std.dll (see https://github.com/rust-lang/rust/pull/131188).
+            let can_be_rustc_dynamic_dep = if builder
+                .link_std_into_rustc_driver(target_compiler.host)
+                && !target_compiler.host.is_windows()
             {
+                let is_std = filename.starts_with("std-") || filename.starts_with("libstd-");
+                !is_std
+            } else {
+                true
+            };
+
+            if is_dylib_or_debug && can_be_rustc_dynamic_dep && !is_proc_macro {
                 builder.copy_link(&f.path(), &rustc_libdir.join(&filename));
             }
         }
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 4c557366297..90e6a10d9d6 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -2036,7 +2036,7 @@ fn maybe_install_llvm(
         }
         !builder.config.dry_run()
     } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult { llvm_config, .. }) =
-        llvm::prebuilt_llvm_config(builder, target)
+        llvm::prebuilt_llvm_config(builder, target, true)
     {
         let mut cmd = command(llvm_config);
         cmd.arg("--libfiles");
diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index 952d8d73328..5ca4321d855 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -93,6 +93,7 @@ fn get_modified_rs_files(build: &Builder<'_>) -> Result<Option<Vec<String>>, Str
     if !verify_rustfmt_version(build) {
         return Ok(None);
     }
+
     get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &["rs"])
 }
 
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index b3bc6df1f87..30213584157 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -87,10 +87,14 @@ impl LdFlags {
 ///
 /// This will return the llvm-config if it can get it (but it will not build it
 /// if not).
-pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> LlvmBuildStatus {
-    // If we have llvm submodule initialized already, sync it.
-    builder.update_existing_submodule("src/llvm-project");
-
+pub fn prebuilt_llvm_config(
+    builder: &Builder<'_>,
+    target: TargetSelection,
+    // Certain commands (like `x test mir-opt --bless`) may call this function with different targets,
+    // which could bypass the CI LLVM early-return even if `builder.config.llvm_from_ci` is true.
+    // This flag should be `true` only if the caller needs the LLVM sources (e.g., if it will build LLVM).
+    handle_submodule_when_needed: bool,
+) -> LlvmBuildStatus {
     builder.config.maybe_download_ci_llvm();
 
     // If we're using a custom LLVM bail out here, but we can only use a
@@ -109,9 +113,10 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L
         }
     }
 
-    // Initialize the llvm submodule if not initialized already.
-    // If submodules are disabled, this does nothing.
-    builder.config.update_submodule("src/llvm-project");
+    if handle_submodule_when_needed {
+        // If submodules are disabled, this does nothing.
+        builder.config.update_submodule("src/llvm-project");
+    }
 
     let root = "src/llvm-project/llvm";
     let out_dir = builder.llvm_out(target);
@@ -237,7 +242,7 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool {
 
 /// Returns true if we're running in CI with modified LLVM (and thus can't download it)
 pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool {
-    CiEnv::is_ci() && config.rust_info.is_managed_git_subrepository() && {
+    CiEnv::is_rust_lang_managed_ci_job() && config.rust_info.is_managed_git_subrepository() && {
         // We assume we have access to git, so it's okay to unconditionally pass
         // `true` here.
         let llvm_sha = detect_llvm_sha(config, true);
@@ -284,7 +289,7 @@ impl Step for Llvm {
         };
 
         // If LLVM has already been built or been downloaded through download-ci-llvm, we avoid building it again.
-        let Meta { stamp, res, out_dir, root } = match prebuilt_llvm_config(builder, target) {
+        let Meta { stamp, res, out_dir, root } = match prebuilt_llvm_config(builder, target, true) {
             LlvmBuildStatus::AlreadyBuilt(p) => return p,
             LlvmBuildStatus::ShouldBuild(m) => m,
         };
@@ -339,6 +344,7 @@ impl Step for Llvm {
             .define("LLVM_INCLUDE_DOCS", "OFF")
             .define("LLVM_INCLUDE_BENCHMARKS", "OFF")
             .define("LLVM_INCLUDE_TESTS", enable_tests)
+            // FIXME: remove this when minimal llvm is 19
             .define("LLVM_ENABLE_TERMINFO", "OFF")
             .define("LLVM_ENABLE_LIBEDIT", "OFF")
             .define("LLVM_ENABLE_BINDINGS", "OFF")
diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index 0ee2cb451f3..51964977933 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -35,21 +35,6 @@ pub enum Profile {
 
 static PROFILE_DIR: &str = "src/bootstrap/defaults";
 
-/// A list of historical hashes of `src/etc/rust_analyzer_settings.json`.
-/// New entries should be appended whenever this is updated so we can detect
-/// outdated vs. user-modified settings files.
-static SETTINGS_HASHES: &[&str] = &[
-    "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8",
-    "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922",
-    "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0",
-    "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541",
-    "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923",
-    "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a",
-    "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000",
-    "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d",
-];
-static RUST_ANALYZER_SETTINGS: &str = include_str!("../../../../etc/rust_analyzer_settings.json");
-
 impl Profile {
     fn include_path(&self, src_path: &Path) -> PathBuf {
         PathBuf::from(format!("{}/{PROFILE_DIR}/config.{}.toml", src_path.display(), self))
@@ -533,46 +518,162 @@ undesirable, simply delete the `pre-push` file from .git/hooks."
     Ok(())
 }
 
-/// Sets up or displays `src/etc/rust_analyzer_settings.json`
+/// Handles editor-specific setup differences
+#[derive(Clone, Debug, Eq, PartialEq)]
+enum EditorKind {
+    Vscode,
+    Vim,
+    Emacs,
+    Helix,
+}
+
+impl EditorKind {
+    fn prompt_user() -> io::Result<Option<EditorKind>> {
+        let prompt_str = "Available editors:
+1. vscode
+2. vim
+3. emacs
+4. helix
+
+Select which editor you would like to set up [default: None]: ";
+
+        let mut input = String::new();
+        loop {
+            print!("{}", prompt_str);
+            io::stdout().flush()?;
+            input.clear();
+            io::stdin().read_line(&mut input)?;
+            match input.trim().to_lowercase().as_str() {
+                "1" | "vscode" => return Ok(Some(EditorKind::Vscode)),
+                "2" | "vim" => return Ok(Some(EditorKind::Vim)),
+                "3" | "emacs" => return Ok(Some(EditorKind::Emacs)),
+                "4" | "helix" => return Ok(Some(EditorKind::Helix)),
+                "" => return Ok(None),
+                _ => {
+                    eprintln!("ERROR: unrecognized option '{}'", input.trim());
+                    eprintln!("NOTE: press Ctrl+C to exit");
+                }
+            };
+        }
+    }
+
+    /// A list of historical hashes of each LSP settings file
+    /// New entries should be appended whenever this is updated so we can detect
+    /// outdated vs. user-modified settings files.
+    fn hashes(&self) -> Vec<&str> {
+        match self {
+            EditorKind::Vscode | EditorKind::Vim => vec![
+                "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8",
+                "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922",
+                "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0",
+                "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541",
+                "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923",
+                "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a",
+                "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000",
+                "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d",
+            ],
+            EditorKind::Emacs => vec![
+                "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0",
+                "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45",
+            ],
+            EditorKind::Helix => {
+                vec!["2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233"]
+            }
+        }
+    }
+
+    fn settings_path(&self, config: &Config) -> PathBuf {
+        config.src.join(self.settings_short_path())
+    }
+
+    fn settings_short_path(&self) -> PathBuf {
+        self.settings_folder().join(match self {
+            EditorKind::Vscode => "settings.json",
+            EditorKind::Vim => "coc-settings.json",
+            EditorKind::Emacs => ".dir-locals.el",
+            EditorKind::Helix => "languages.toml",
+        })
+    }
+
+    fn settings_folder(&self) -> PathBuf {
+        match self {
+            EditorKind::Vscode => PathBuf::from(".vscode"),
+            EditorKind::Vim => PathBuf::from(".vim"),
+            EditorKind::Emacs => PathBuf::new(),
+            EditorKind::Helix => PathBuf::from(".helix"),
+        }
+    }
+
+    fn settings_template(&self) -> &str {
+        match self {
+            EditorKind::Vscode | EditorKind::Vim => {
+                include_str!("../../../../etc/rust_analyzer_settings.json")
+            }
+            EditorKind::Emacs => include_str!("../../../../etc/rust_analyzer_eglot.el"),
+            EditorKind::Helix => include_str!("../../../../etc/rust_analyzer_helix.toml"),
+        }
+    }
+
+    fn backup_extension(&self) -> String {
+        format!("{}.bak", self.settings_short_path().extension().unwrap().to_str().unwrap())
+    }
+}
+
+/// Sets up or displays the LSP config for one of the supported editors
 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
-pub struct Vscode;
+pub struct Editor;
 
-impl Step for Vscode {
+impl Step for Editor {
     type Output = ();
     const DEFAULT: bool = true;
+
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.alias("vscode")
+        run.alias("editor")
     }
+
     fn make_run(run: RunConfig<'_>) {
         if run.builder.config.dry_run() {
             return;
         }
         if let [cmd] = &run.paths[..] {
-            if cmd.assert_single_path().path.as_path().as_os_str() == "vscode" {
-                run.builder.ensure(Vscode);
+            if cmd.assert_single_path().path.as_path().as_os_str() == "editor" {
+                run.builder.ensure(Editor);
             }
         }
     }
+
     fn run(self, builder: &Builder<'_>) -> Self::Output {
         let config = &builder.config;
         if config.dry_run() {
             return;
         }
-        while !t!(create_vscode_settings_maybe(config)) {}
+        match EditorKind::prompt_user() {
+            Ok(editor_kind) => {
+                if let Some(editor_kind) = editor_kind {
+                    while !t!(create_editor_settings_maybe(config, editor_kind.clone())) {}
+                } else {
+                    println!("Ok, skipping editor setup!");
+                }
+            }
+            Err(e) => eprintln!("Could not determine the editor: {e}"),
+        }
     }
 }
 
-/// Create a `.vscode/settings.json` file for rustc development, or just print it
+/// Create the recommended editor LSP config file for rustc development, or just print it
 /// If this method should be re-called, it returns `false`.
-fn create_vscode_settings_maybe(config: &Config) -> io::Result<bool> {
-    let (current_hash, historical_hashes) = SETTINGS_HASHES.split_last().unwrap();
-    let vscode_settings = config.src.join(".vscode").join("settings.json");
-    // If None, no settings.json exists
+fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Result<bool> {
+    let hashes = editor.hashes();
+    let (current_hash, historical_hashes) = hashes.split_last().unwrap();
+    let settings_path = editor.settings_path(config);
+    let settings_short_path = editor.settings_short_path();
+    let settings_filename = settings_short_path.to_str().unwrap();
+    // If None, no settings file exists
     // If Some(true), is a previous version of settings.json
     // If Some(false), is not a previous version (i.e. user modified)
     // If it's up to date we can just skip this
     let mut mismatched_settings = None;
-    if let Ok(current) = fs::read_to_string(&vscode_settings) {
+    if let Ok(current) = fs::read_to_string(&settings_path) {
         let mut hasher = sha2::Sha256::new();
         hasher.update(&current);
         let hash = hex_encode(hasher.finalize().as_slice());
@@ -585,20 +686,21 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result<bool> {
         }
     }
     println!(
-        "\nx.py can automatically install the recommended `.vscode/settings.json` file for rustc development"
+        "\nx.py can automatically install the recommended `{settings_filename}` file for rustc development"
     );
+
     match mismatched_settings {
-        Some(true) => eprintln!(
-            "WARNING: existing `.vscode/settings.json` is out of date, x.py will update it"
-        ),
+        Some(true) => {
+            eprintln!("WARNING: existing `{settings_filename}` is out of date, x.py will update it")
+        }
         Some(false) => eprintln!(
-            "WARNING: existing `.vscode/settings.json` has been modified by user, x.py will back it up and replace it"
+            "WARNING: existing `{settings_filename}` has been modified by user, x.py will back it up and replace it"
         ),
         _ => (),
     }
-    let should_create = match prompt_user(
-        "Would you like to create/update settings.json? (Press 'p' to preview values): [y/N]",
-    )? {
+    let should_create = match prompt_user(&format!(
+        "Would you like to create/update `{settings_filename}`? (Press 'p' to preview values): [y/N]"
+    ))? {
         Some(PromptResult::Yes) => true,
         Some(PromptResult::Print) => false,
         _ => {
@@ -607,9 +709,9 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result<bool> {
         }
     };
     if should_create {
-        let path = config.src.join(".vscode");
-        if !path.exists() {
-            fs::create_dir(&path)?;
+        let settings_folder_path = config.src.join(editor.settings_folder());
+        if !settings_folder_path.exists() {
+            fs::create_dir(settings_folder_path)?;
         }
         let verb = match mismatched_settings {
             // exists but outdated, we can replace this
@@ -617,18 +719,21 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result<bool> {
             // exists but user modified, back it up
             Some(false) => {
                 // exists and is not current version or outdated, so back it up
-                let mut backup = vscode_settings.clone();
-                backup.set_extension("json.bak");
-                eprintln!("WARNING: copying `settings.json` to `settings.json.bak`");
-                fs::copy(&vscode_settings, &backup)?;
+                let backup = settings_path.clone().with_extension(editor.backup_extension());
+                eprintln!(
+                    "WARNING: copying `{}` to `{}`",
+                    settings_path.file_name().unwrap().to_str().unwrap(),
+                    backup.file_name().unwrap().to_str().unwrap(),
+                );
+                fs::copy(&settings_path, &backup)?;
                 "Updated"
             }
             _ => "Created",
         };
-        fs::write(&vscode_settings, RUST_ANALYZER_SETTINGS)?;
-        println!("{verb} `.vscode/settings.json`");
+        fs::write(&settings_path, editor.settings_template())?;
+        println!("{verb} `{}`", settings_filename);
     } else {
-        println!("\n{RUST_ANALYZER_SETTINGS}");
+        println!("\n{}", editor.settings_template());
     }
     Ok(should_create)
 }
diff --git a/src/bootstrap/src/core/build_steps/setup/tests.rs b/src/bootstrap/src/core/build_steps/setup/tests.rs
index 3552224f33b..f3d4b6aa4db 100644
--- a/src/bootstrap/src/core/build_steps/setup/tests.rs
+++ b/src/bootstrap/src/core/build_steps/setup/tests.rs
@@ -1,16 +1,17 @@
 use sha2::Digest;
 
-use super::{RUST_ANALYZER_SETTINGS, SETTINGS_HASHES};
+use super::EditorKind;
 use crate::utils::helpers::hex_encode;
 
 #[test]
 fn check_matching_settings_hash() {
+    let editor = EditorKind::Vscode;
     let mut hasher = sha2::Sha256::new();
-    hasher.update(&RUST_ANALYZER_SETTINGS);
+    hasher.update(&editor.settings_template());
     let hash = hex_encode(hasher.finalize().as_slice());
     assert_eq!(
         &hash,
-        SETTINGS_HASHES.last().unwrap(),
-        "Update `SETTINGS_HASHES` with the new hash of `src/etc/rust_analyzer_settings.json`"
+        editor.hashes().last().unwrap(),
+        "Update `EditorKind::hashes()` with the new hash of `src/etc/rust_analyzer_settings.json`"
     );
 }
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 870fe6a9f16..7283b0e9574 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -1792,6 +1792,10 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         cmd.arg("--host").arg(&*compiler.host.triple);
         cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build));
 
+        if builder.build.config.llvm_enzyme {
+            cmd.arg("--has-enzyme");
+        }
+
         if builder.config.cmd.bless() {
             cmd.arg("--bless");
         }
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index 47420f8fe72..e7a19d0bcc0 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -1000,7 +1000,9 @@ impl<'a> Builder<'a> {
                 run::GenerateWindowsSys,
                 run::GenerateCompletions,
             ),
-            Kind::Setup => describe!(setup::Profile, setup::Hook, setup::Link, setup::Vscode),
+            Kind::Setup => {
+                describe!(setup::Profile, setup::Hook, setup::Link, setup::Editor)
+            }
             Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std),
             Kind::Vendor => describe!(vendor::Vendor),
             // special-cased in Build::build()
@@ -1537,7 +1539,9 @@ impl<'a> Builder<'a> {
             // rustc_llvm. But if LLVM is stale, that'll be a tiny amount
             // of work comparatively, and we'd likely need to rebuild it anyway,
             // so that's okay.
-            if crate::core::build_steps::llvm::prebuilt_llvm_config(self, target).should_build() {
+            if crate::core::build_steps::llvm::prebuilt_llvm_config(self, target, false)
+                .should_build()
+            {
                 cargo.env("RUST_CHECK", "1");
             }
         }
@@ -1562,8 +1566,8 @@ impl<'a> Builder<'a> {
         let libdir = self.rustc_libdir(compiler);
 
         let sysroot_str = sysroot.as_os_str().to_str().expect("sysroot should be UTF-8");
-        if !matches!(self.config.dry_run, DryRun::SelfCheck) {
-            self.verbose_than(0, || println!("using sysroot {sysroot_str}"));
+        if self.is_verbose() && !matches!(self.config.dry_run, DryRun::SelfCheck) {
+            println!("using sysroot {sysroot_str}");
         }
 
         let mut rustflags = Rustflags::new(target);
@@ -2012,6 +2016,11 @@ impl<'a> Builder<'a> {
             cargo.env("RUSTC_BACKTRACE_ON_ICE", "1");
         }
 
+        if self.is_verbose() {
+            // This provides very useful logs especially when debugging build cache-related stuff.
+            cargo.env("CARGO_LOG", "cargo::core::compiler::fingerprint=info");
+        }
+
         cargo.env("RUSTC_VERBOSE", self.verbosity.to_string());
 
         // Downstream forks of the Rust compiler might want to use a custom libc to add support for
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 77e0ece3104..7dc3b7b081a 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -4,7 +4,7 @@
 //! how the build runs.
 
 use std::cell::{Cell, RefCell};
-use std::collections::{HashMap, HashSet};
+use std::collections::{BTreeSet, HashMap, HashSet};
 use std::fmt::{self, Display};
 use std::io::IsTerminal;
 use std::path::{Path, PathBuf, absolute};
@@ -287,6 +287,7 @@ pub struct Config {
     pub rust_profile_generate: Option<String>,
     pub rust_lto: RustcLto,
     pub rust_validate_mir_opts: Option<u32>,
+    pub rust_std_features: BTreeSet<String>,
     pub llvm_profile_use: Option<String>,
     pub llvm_profile_generate: bool,
     pub llvm_libunwind_default: Option<LlvmLibunwind>,
@@ -343,6 +344,15 @@ pub struct Config {
     pub out: PathBuf,
     pub rust_info: channel::GitInfo,
 
+    pub cargo_info: channel::GitInfo,
+    pub rust_analyzer_info: channel::GitInfo,
+    pub clippy_info: channel::GitInfo,
+    pub miri_info: channel::GitInfo,
+    pub rustfmt_info: channel::GitInfo,
+    pub enzyme_info: channel::GitInfo,
+    pub in_tree_llvm_info: channel::GitInfo,
+    pub in_tree_gcc_info: channel::GitInfo,
+
     // These are either the stage0 downloaded binaries or the locally installed ones.
     pub initial_cargo: PathBuf,
     pub initial_rustc: PathBuf,
@@ -1143,6 +1153,7 @@ define_config! {
         download_rustc: Option<StringOrBool> = "download-rustc",
         lto: Option<String> = "lto",
         validate_mir_opts: Option<u32> = "validate-mir-opts",
+        std_features: Option<BTreeSet<String>> = "std-features",
     }
 }
 
@@ -1636,6 +1647,7 @@ impl Config {
         let mut optimize = None;
         let mut omit_git_hash = None;
         let mut lld_enabled = None;
+        let mut std_features = None;
 
         let mut is_user_configured_rust_channel = false;
 
@@ -1694,6 +1706,7 @@ impl Config {
                 stack_protector,
                 strip,
                 lld_mode,
+                std_features: std_features_toml,
             } = rust;
 
             is_user_configured_rust_channel = channel.is_some();
@@ -1713,6 +1726,7 @@ impl Config {
             debuginfo_level_tools = debuginfo_level_tools_toml;
             debuginfo_level_tests = debuginfo_level_tests_toml;
             lld_enabled = lld_enabled_toml;
+            std_features = std_features_toml;
 
             optimize = optimize_toml;
             omit_git_hash = omit_git_hash_toml;
@@ -1796,6 +1810,19 @@ impl Config {
         config.omit_git_hash = omit_git_hash.unwrap_or(default);
         config.rust_info = GitInfo::new(config.omit_git_hash, &config.src);
 
+        config.cargo_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/cargo"));
+        config.rust_analyzer_info =
+            GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rust-analyzer"));
+        config.clippy_info =
+            GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/clippy"));
+        config.miri_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/miri"));
+        config.rustfmt_info =
+            GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rustfmt"));
+        config.enzyme_info =
+            GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/enzyme"));
+        config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project"));
+        config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc"));
+
         // We need to override `rust.channel` if it's manually specified when using the CI rustc.
         // This is because if the compiler uses a different channel than the one specified in config.toml,
         // tests may fail due to using a different channel than the one used by the compiler during tests.
@@ -2096,6 +2123,9 @@ impl Config {
             );
         }
 
+        let default_std_features = BTreeSet::from([String::from("panic-unwind")]);
+        config.rust_std_features = std_features.unwrap_or(default_std_features);
+
         let default = debug == Some(true);
         config.rust_debug_assertions = debug_assertions.unwrap_or(default);
         config.rust_debug_assertions_std =
@@ -2428,7 +2458,7 @@ impl Config {
 
     /// Runs a function if verbosity is greater than 0
     pub fn verbose(&self, f: impl Fn()) {
-        if self.verbose > 0 {
+        if self.is_verbose() {
             f()
         }
     }
@@ -2713,7 +2743,7 @@ impl Config {
         .success();
         if has_changes {
             if if_unchanged {
-                if self.verbose > 0 {
+                if self.is_verbose() {
                     println!(
                         "WARNING: saw changes to compiler/ or library/ since {commit}; \
                             ignoring `download-rustc`"
@@ -2810,7 +2840,7 @@ impl Config {
         let has_changes = !t!(git.as_command_mut().status()).success();
         if has_changes {
             if if_unchanged {
-                if self.verbose > 0 {
+                if self.is_verbose() {
                     println!(
                         "warning: saw changes to one of {modified_paths:?} since {commit}; \
                             ignoring `{option_name}`"
@@ -2994,6 +3024,7 @@ fn check_incompatible_options_for_ci_rustc(
         description,
         incremental,
         default_linker,
+        std_features,
 
         // Rest of the options can simply be ignored.
         debug: _,
@@ -3055,6 +3086,7 @@ fn check_incompatible_options_for_ci_rustc(
     err!(current_rust_config.default_linker, default_linker);
     err!(current_rust_config.stack_protector, stack_protector);
     err!(current_rust_config.lto, lto);
+    err!(current_rust_config.std_features, std_features);
 
     warn!(current_rust_config.channel, channel);
     warn!(current_rust_config.description, description);
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index 87db5f93fb0..3aefe517a5b 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -447,14 +447,14 @@ Arguments:
     The profile is optional and you will be prompted interactively if it is not given.
     The following profiles are available:
 {}
-    To only set up the git hook, VS Code config or toolchain link, you may use
+    To only set up the git hook, editor config or toolchain link, you may use
         ./x.py setup hook
-        ./x.py setup vscode
+        ./x.py setup editor
         ./x.py setup link", Profile::all_for_help("        ").trim_end()))]
     Setup {
         /// Either the profile for `config.toml` or another setup action.
         /// May be omitted to set up interactively
-        #[arg(value_name = "<PROFILE>|hook|vscode|link")]
+        #[arg(value_name = "<PROFILE>|hook|editor|link")]
         profile: Option<PathBuf>,
     },
     /// Suggest a subset of tests to run, based on modified files
diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs
index e38d4eac051..278becdcbc7 100644
--- a/src/bootstrap/src/core/config/tests.rs
+++ b/src/bootstrap/src/core/config/tests.rs
@@ -1,3 +1,4 @@
+use std::collections::BTreeSet;
 use std::env;
 use std::fs::{File, remove_file};
 use std::io::Write;
@@ -326,3 +327,24 @@ fn verbose_tests_default_value() {
     let config = Config::parse(Flags::parse(&["build".into(), "compiler".into(), "-v".into()]));
     assert_eq!(config.verbose_tests, true);
 }
+
+#[test]
+fn parse_rust_std_features() {
+    let config = parse("rust.std-features = [\"panic-unwind\", \"backtrace\"]");
+    let expected_features: BTreeSet<String> =
+        ["panic-unwind", "backtrace"].into_iter().map(|s| s.to_string()).collect();
+    assert_eq!(config.rust_std_features, expected_features);
+}
+
+#[test]
+fn parse_rust_std_features_empty() {
+    let config = parse("rust.std-features = []");
+    let expected_features: BTreeSet<String> = BTreeSet::new();
+    assert_eq!(config.rust_std_features, expected_features);
+}
+
+#[test]
+#[should_panic]
+fn parse_rust_std_features_invalid() {
+    parse("rust.std-features = \"backtrace\"");
+}
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 888ba8e2a3f..6fbdd76ed5b 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -13,8 +13,6 @@ use std::ffi::{OsStr, OsString};
 use std::path::PathBuf;
 use std::{env, fs};
 
-use build_helper::git::warn_old_master_branch;
-
 use crate::Build;
 #[cfg(not(feature = "bootstrap-self-test"))]
 use crate::builder::Builder;
@@ -37,6 +35,9 @@ pub struct Finder {
 const STAGE0_MISSING_TARGETS: &[&str] = &[
     // just a dummy comment so the list doesn't get onelined
     "armv7-rtems-eabihf",
+    "riscv32e-unknown-none-elf",
+    "riscv32em-unknown-none-elf",
+    "riscv32emc-unknown-none-elf",
 ];
 
 /// Minimum version threshold for libstdc++ required when using prebuilt LLVM
@@ -379,6 +380,4 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
     if let Some(ref s) = build.config.ccache {
         cmd_finder.must_have(s);
     }
-
-    warn_old_master_branch(&build.config.git_config(), &build.config.src);
 }
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 7bf5b4e23d2..ecb219ea33f 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -17,7 +17,7 @@
 //! also check out the `src/bootstrap/README.md` file for more information.
 
 use std::cell::{Cell, RefCell};
-use std::collections::{HashMap, HashSet};
+use std::collections::{BTreeSet, HashMap, HashSet};
 use std::fmt::Display;
 use std::fs::{self, File};
 use std::path::{Path, PathBuf};
@@ -305,18 +305,15 @@ impl Build {
         #[cfg(not(unix))]
         let is_sudo = false;
 
-        let omit_git_hash = config.omit_git_hash;
-        let rust_info = GitInfo::new(omit_git_hash, &src);
-        let cargo_info = GitInfo::new(omit_git_hash, &src.join("src/tools/cargo"));
-        let rust_analyzer_info = GitInfo::new(omit_git_hash, &src.join("src/tools/rust-analyzer"));
-        let clippy_info = GitInfo::new(omit_git_hash, &src.join("src/tools/clippy"));
-        let miri_info = GitInfo::new(omit_git_hash, &src.join("src/tools/miri"));
-        let rustfmt_info = GitInfo::new(omit_git_hash, &src.join("src/tools/rustfmt"));
-        let enzyme_info = GitInfo::new(omit_git_hash, &src.join("src/tools/enzyme"));
-
-        // we always try to use git for LLVM builds
-        let in_tree_llvm_info = GitInfo::new(false, &src.join("src/llvm-project"));
-        let in_tree_gcc_info = GitInfo::new(false, &src.join("src/gcc"));
+        let rust_info = config.rust_info.clone();
+        let cargo_info = config.cargo_info.clone();
+        let rust_analyzer_info = config.rust_analyzer_info.clone();
+        let clippy_info = config.clippy_info.clone();
+        let miri_info = config.miri_info.clone();
+        let rustfmt_info = config.rustfmt_info.clone();
+        let enzyme_info = config.enzyme_info.clone();
+        let in_tree_llvm_info = config.in_tree_llvm_info.clone();
+        let in_tree_gcc_info = config.in_tree_gcc_info.clone();
 
         let initial_target_libdir_str = if config.dry_run() {
             "/dummy/lib/path/to/lib/".to_string()
@@ -473,7 +470,7 @@ impl Build {
             crate::core::metadata::build(&mut build);
         }
 
-        // Make a symbolic link so we can use a consistent directory in the documentation.
+        // Create symbolic link to use host sysroot from a consistent path (e.g., in the rust-analyzer config file).
         let build_triple = build.out.join(build.build);
         t!(fs::create_dir_all(&build_triple));
         let host = build.out.join("host");
@@ -648,28 +645,31 @@ impl Build {
         &self.config.rust_info
     }
 
-    /// Gets the space-separated set of activated features for the standard
-    /// library.
+    /// Gets the space-separated set of activated features for the standard library.
+    /// This can be configured with the `std-features` key in config.toml.
     fn std_features(&self, target: TargetSelection) -> String {
-        let mut features = " panic-unwind".to_string();
+        let mut features: BTreeSet<&str> =
+            self.config.rust_std_features.iter().map(|s| s.as_str()).collect();
 
         match self.config.llvm_libunwind(target) {
-            LlvmLibunwind::InTree => features.push_str(" llvm-libunwind"),
-            LlvmLibunwind::System => features.push_str(" system-llvm-libunwind"),
-            LlvmLibunwind::No => {}
-        }
+            LlvmLibunwind::InTree => features.insert("llvm-libunwind"),
+            LlvmLibunwind::System => features.insert("system-llvm-libunwind"),
+            LlvmLibunwind::No => false,
+        };
+
         if self.config.backtrace {
-            features.push_str(" backtrace");
+            features.insert("backtrace");
         }
         if self.config.profiler_enabled(target) {
-            features.push_str(" profiler");
+            features.insert("profiler");
         }
         // Generate memcpy, etc.  FIXME: Remove this once compiler-builtins
         // automatically detects this target.
         if target.contains("zkvm") {
-            features.push_str(" compiler-builtins-mem");
+            features.insert("compiler-builtins-mem");
         }
-        features
+
+        features.into_iter().collect::<Vec<_>>().join(" ")
     }
 
     /// Gets the space-separated set of activated features for the compiler.
@@ -1373,7 +1373,7 @@ Executed at: {executed_at}"#,
         }
 
         if target.starts_with("wasm") && target.contains("wasi") {
-            self.default_wasi_runner()
+            self.default_wasi_runner(target)
         } else {
             None
         }
@@ -1382,7 +1382,7 @@ Executed at: {executed_at}"#,
     /// When a `runner` configuration is not provided and a WASI-looking target
     /// is being tested this is consulted to prove the environment to see if
     /// there's a runtime already lying around that seems reasonable to use.
-    fn default_wasi_runner(&self) -> Option<String> {
+    fn default_wasi_runner(&self, target: TargetSelection) -> Option<String> {
         let mut finder = crate::core::sanity::Finder::new();
 
         // Look for Wasmtime, and for its default options be sure to disable
@@ -1398,6 +1398,11 @@ Executed at: {executed_at}"#,
                 // inherit the entire environment rather than just this single
                 // environment variable.
                 path.push_str(" --env RUSTC_BOOTSTRAP");
+
+                if target.contains("wasip2") {
+                    path.push_str(" --wasi inherit-network --wasi allow-ip-name-lookup");
+                }
+
                 return Some(path);
             }
         }
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index e6f7f105fa2..b37786496cb 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -270,4 +270,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "If `llvm.download-ci-llvm` is not defined, it defaults to `true`.",
     },
+    ChangeInfo {
+        change_id: 131075,
+        severity: ChangeSeverity::Info,
+        summary: "New option `./x setup editor` added, replacing `./x setup vscode` and adding support for vim, emacs and helix.",
+    },
 ];
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
index 6a09ab3065f..145f41f21e1 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
@@ -100,4 +100,4 @@ RUN /scripts/build-gccjit.sh /scripts
 # the local version of the package is different than the one used by the CI.
 ENV SCRIPT /tmp/checktools.sh ../x.py && \
   npm install browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true && \
-  python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--no-sandbox --jobs 1'"
+  python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'"
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
index 47d04a52883..6b2d58c8ef3 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
@@ -1 +1 @@
-0.18.0
\ No newline at end of file
+0.18.1
\ No newline at end of file
diff --git a/src/ci/scripts/upload-build-metrics.py b/src/ci/scripts/upload-build-metrics.py
new file mode 100644
index 00000000000..a95e0949d70
--- /dev/null
+++ b/src/ci/scripts/upload-build-metrics.py
@@ -0,0 +1,81 @@
+"""
+This script postprocesses data gathered during a CI run, computes certain metrics
+from them, and uploads these metrics to DataDog.
+
+This script is expected to be executed from within a GitHub Actions job.
+
+It expects the following environment variables:
+- DATADOG_SITE: path to the DataDog API endpoint
+- DATADOG_API_KEY: DataDog API token
+- DD_GITHUB_JOB_NAME: Name of the current GitHub Actions job
+
+And it also expects the presence of a binary called `datadog-ci` to be in PATH.
+It can be installed with `npm install -g @datadog/datadog-ci`.
+
+Usage:
+```bash
+$ python3 upload-build-metrics.py <path-to-CPU-usage-CSV>
+```
+
+`path-to-CPU-usage-CSV` is a path to a CSV generated by the `src/ci/cpu-usage-over-time.py` script.
+"""
+import argparse
+import csv
+import os
+import subprocess
+import sys
+from pathlib import Path
+from typing import List
+
+
+def load_cpu_usage(path: Path) -> List[float]:
+    usage = []
+    with open(path) as f:
+        reader = csv.reader(f, delimiter=',')
+        for row in reader:
+            # The log might contain incomplete rows or some Python exception
+            if len(row) == 2:
+                try:
+                    idle = float(row[1])
+                    usage.append(100.0 - idle)
+                except ValueError:
+                    pass
+    return usage
+
+
+def upload_datadog_measure(name: str, value: float):
+    """
+    Uploads a single numeric metric for the current GitHub Actions job to DataDog.
+    """
+    print(f"Metric {name}: {value:.4f}")
+
+    datadog_cmd = "datadog-ci"
+    if os.getenv("GITHUB_ACTIONS") is not None and sys.platform.lower().startswith("win"):
+        # Due to weird interaction of MSYS2 and Python, we need to use an absolute path,
+        # and also specify the ".cmd" at the end. See https://github.com/rust-lang/rust/pull/125771.
+        datadog_cmd = "C:\\npm\\prefix\\datadog-ci.cmd"
+
+    subprocess.run([
+        datadog_cmd,
+        "measure",
+        "--level", "job",
+        "--measures", f"{name}:{value}"
+    ],
+        check=False
+    )
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(
+        prog="DataDog metric uploader"
+    )
+    parser.add_argument("cpu-usage-history-csv")
+    args = parser.parse_args()
+
+    build_usage_csv = vars(args)["cpu-usage-history-csv"]
+    usage_timeseries = load_cpu_usage(Path(build_usage_csv))
+    if len(usage_timeseries) > 0:
+        avg_cpu_usage = sum(usage_timeseries) / len(usage_timeseries)
+    else:
+        avg_cpu_usage = 0
+    upload_datadog_measure("avg-cpu-usage", avg_cpu_usage)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 207eb5d6d4f..0ef95ba64a1 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -388,6 +388,7 @@ target | std | host | notes
 [`x86_64-unknown-hermit`](platform-support/hermit.md) | ✓ |  | x86_64 Hermit
 `x86_64-unknown-l4re-uclibc` | ? |  |
 [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD
+[`x86_64-unknown-trusty`](platform-support/trusty.md) | ? |  |
 `x86_64-uwp-windows-gnu` | ✓ |  |
 `x86_64-uwp-windows-msvc` | ✓ |  |
 [`x86_64-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ |   | 64-bit Windows 7 support
@@ -412,5 +413,8 @@ target | std | host | notes
 [`riscv32imafc-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 32bit with NuttX
 [`riscv64imac-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 64bit with NuttX
 [`riscv64gc-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 64bit with NuttX
+[`riscv32e-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * |  | Bare RISC-V (RV32E ISA)
+[`riscv32em-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * |  | Bare RISC-V (RV32EM ISA)
+[`riscv32emc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * |  | Bare RISC-V (RV32EMC ISA)
 
 [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets
diff --git a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md
index e72bfb8bae7..32e4f855313 100644
--- a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md
+++ b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md
@@ -80,7 +80,7 @@ cd hello_world
 ```sh
 CARGO_TARGET_CSKY_UNKNOWN_LINUX_GNUABIV2_RUNNER=${QEMU_PATH}/bin/qemu-cskyv2 -L ${TOOLCHAIN_PATH}/csky-linux-gnuabiv2/libc \
 CARGO_TARGET_CSKY_UNKNOWN_LINUX_GNUABIV2_LINKER=${TOOLCHAIN_PATH}/bin/csky-linux-gnuabiv2-gcc \
-RUSTFLAGS="-C target-features=+crt-static" \
+RUSTFLAGS="-C target-feature=+crt-static" \
 cargo +stage2 run --target csky-unknown-linux-gnuabiv2
 ```
 
diff --git a/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md
index 9a27a568b57..38742143c4b 100644
--- a/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md
+++ b/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md
@@ -35,4 +35,4 @@ Rust test-suite on this target.
 ## Cross-compilation toolchains and C code
 
 This target supports C code. If interlinking with C or C++, you may need to use
-`riscv64-unknown-elf-gcc` as a linker instead of `rust-lld`.
+`riscv32-unknown-elf-gcc` as a linker instead of `rust-lld`.
diff --git a/src/doc/rustc/src/platform-support/riscv32e-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32e-unknown-none-elf.md
new file mode 100644
index 00000000000..69f08774f83
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/riscv32e-unknown-none-elf.md
@@ -0,0 +1,30 @@
+# `riscv32{e,em,emc}-unknown-none-elf`
+
+**Tier: 3**
+
+Bare-metal target for RISC-V CPUs with the RV32E, RV32EM and RV32EMC ISAs.
+
+## Target maintainers
+
+* Henri Lunnikivi, <henri.lunnikivi@gmail.com>, [@hegza](https://github.com/hegza)
+
+## Requirements
+
+The target is cross-compiled, and uses static linking. No external toolchain is
+required and the default `rust-lld` linker works, but you must specify a linker
+script.
+
+## Building the target
+
+This target is included in Rust and can be installed via `rustup`.
+
+## Testing
+
+This is a cross-compiled `no-std` target, which must be run either in a
+simulator or by programming them onto suitable hardware. It is not possible to
+run the Rust test-suite on this target.
+
+## Cross-compilation toolchains and C code
+
+This target supports C code. If interlinking with C or C++, you may need to use
+`riscv32-unknown-elf-gcc` as a linker instead of `rust-lld`.
diff --git a/src/doc/rustdoc/src/write-documentation/documentation-tests.md b/src/doc/rustdoc/src/write-documentation/documentation-tests.md
index 7ed2e9720fe..c93893b5ada 100644
--- a/src/doc/rustdoc/src/write-documentation/documentation-tests.md
+++ b/src/doc/rustdoc/src/write-documentation/documentation-tests.md
@@ -414,11 +414,11 @@ In some cases, doctests cannot be merged. For example, if you have:
 The problem with this code is that, if you change any other doctests, it'll likely break when
 runing `rustdoc --test`, making it tricky to maintain.
 
-This is where the `standalone` attribute comes in: it tells `rustdoc` that a doctest
+This is where the `standalone_crate` attribute comes in: it tells `rustdoc` that a doctest
 should not be merged with the others. So the previous code should use it:
 
 ```rust
-//! ```standalone
+//! ```standalone_crate
 //! let location = std::panic::Location::caller();
 //! assert_eq!(location.line(), 4);
 //! ```
diff --git a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md
index 1a367b8274b..5e785483402 100644
--- a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md
+++ b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md
@@ -89,8 +89,8 @@ fn Foo() {}
 
 These prefixes will be stripped when displayed in the documentation, so `[struct@Foo]` will be
 rendered as `Foo`. The following prefixes are available: `struct`, `enum`, `trait`, `union`,
-`mod`, `module`, `const`, `constant`, `fn`, `function`, `method`, `derive`, `type`, `value`,
-`macro`, `prim` or `primitive`.
+`mod`, `module`, `const`, `constant`, `fn`, `function`, `field`, `variant`, `method`, `derive`,
+`type`, `value`, `macro`, `prim` or `primitive`.
 
 You can also disambiguate for functions by adding `()` after the function name,
 or for macros by adding `!` after the macro name. The macro `!` can be followed by `()`, `{}`,
diff --git a/src/doc/unstable-book/src/compiler-flags/default-hidden-visibility.md b/src/doc/unstable-book/src/compiler-flags/default-hidden-visibility.md
deleted file mode 100644
index 579add4a9d9..00000000000
--- a/src/doc/unstable-book/src/compiler-flags/default-hidden-visibility.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# `default-hidden-visibility`
-
-The tracking issue for this feature is: https://github.com/rust-lang/compiler-team/issues/656
-
-------------------------
-
-This flag can be used to override the target's
-[`default_hidden_visibility`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_target/spec/struct.TargetOptions.html#structfield.default_hidden_visibility)
-setting.
-Using `-Zdefault_hidden_visibility=yes` is roughly equivalent to Clang's
-[`-fvisibility=hidden`](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fvisibility)
-cmdline flag.
diff --git a/src/doc/unstable-book/src/compiler-flags/default-visibility.md b/src/doc/unstable-book/src/compiler-flags/default-visibility.md
new file mode 100644
index 00000000000..ad9e5d84bba
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/default-visibility.md
@@ -0,0 +1,44 @@
+# `default-visibility`
+
+The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/131090
+
+------------------------
+
+This flag can be used to override the target's
+[`default_visibility`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_target/spec/struct.TargetOptions.html#structfield.default_visibility)
+setting.
+
+This option only affects building of shared objects and should have no effect on executables.
+
+Visibility an be set to one of three options:
+
+* protected
+* hidden
+* interposable
+
+## Hidden visibility
+
+Using `-Zdefault-visibility=hidden` is roughly equivalent to Clang's
+[`-fvisibility=hidden`](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fvisibility)
+cmdline flag. Hidden symbols will not be exported from the created shared object, so cannot be
+referenced from other shared objects or from executables.
+
+## Protected visibility
+
+Using `-Zdefault-visibility=protected` will cause rust-mangled symbols to be emitted with
+"protected" visibility. This signals the compiler, the linker and the runtime linker that these
+symbols cannot be overridden by the executable or by other shared objects earlier in the load order.
+
+This will allow the compiler to emit direct references to symbols, which may improve performance. It
+also removes the need for these symbols to be resolved when a shared object built with this option
+is loaded.
+
+Using protected visibility when linking with GNU ld prior to 2.40 will result in linker errors when
+building for Linux. Other linkers such as LLD are not affected.
+
+## Interposable
+
+Using `-Zdefault-visibility=interposable` will cause symbols to be emitted with "default"
+visibility. On platforms that support it, this makes it so that symbols can be interposed, which
+means that they can be overridden by symbols with the same name from the executable or by other
+shared objects earier in the load order.
diff --git a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md
index ab63c986e85..8d314aa62d4 100644
--- a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md
+++ b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md
@@ -4,23 +4,28 @@ The tracking issue for this feature is: [#125704](https://github.com/rust-lang/r
 
 ------------------------
 
-This option of the `--print` flag print the list of expected cfgs.
+This option of the `--print` flag print the list of all the expected cfgs.
 
-This is related to the `--check-cfg` flag which allows specifying arbitrary expected
+This is related to the [`--check-cfg` flag][check-cfg] which allows specifying arbitrary expected
 names and values.
 
-This print option works similarly to `--print=cfg` (modulo check-cfg specifics):
- - *check_cfg syntax*: *output of --print=check-cfg*
- - `cfg(windows)`: `windows`
- - `cfg(feature, values("foo", "bar"))`: `feature="foo"` and `feature="bar"`
- - `cfg(feature, values(none(), ""))`: `feature` and `feature=""`
- - `cfg(feature, values(any()))`: `feature=any()`
- - `cfg(feature, values())`: `feature=`
- - `cfg(any())`: `any()`
- - *nothing*: `any()=any()`
+This print option works similarly to `--print=cfg` (modulo check-cfg specifics).
+
+| `--check-cfg`                     | `--print=check-cfg`         |
+|-----------------------------------|-----------------------------|
+| `cfg(foo)`                        | `foo`                       |
+| `cfg(foo, values("bar"))`         | `foo="bar"`                 |
+| `cfg(foo, values(none(), "bar"))` | `foo` & `foo="bar"`         |
+|                                   | *check-cfg specific syntax* |
+| `cfg(foo, values(any())`          | `foo=any()`                 |
+| `cfg(foo, values())`              | `foo=`                      |
+| `cfg(any())`                      | `any()`                     |
+| *none*                            | `any()=any()`               |
 
 To be used like this:
 
 ```bash
 rustc --print=check-cfg -Zunstable-options lib.rs
 ```
+
+[check-cfg]: https://doc.rust-lang.org/nightly/rustc/check-cfg.html
diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
index 43e11b6d57d..b1c429c7676 100644
--- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
+++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
@@ -51,7 +51,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `reg`          | `r[0-31]`                          | `r`                  |
 | CSKY         | `freg`         | `f[0-31]`                          | `f`                  |
 | s390x        | `reg`          | `r[0-10]`, `r[12-14]`              | `r`                  |
+| s390x        | `reg_addr`     | `r[1-10]`, `r[12-14]`              | `a`                  |
 | s390x        | `freg`         | `f[0-15]`                          | `f`                  |
+| s390x        | `vreg`         | `v[0-31]`                          | Only clobbers        |
+| s390x        | `areg`         | `a[2-15]`                          | Only clobbers        |
 | Arm64EC      | `reg`          | `x[0-12]`, `x[15-22]`, `x[25-27]`, `x30` | `r`            |
 | Arm64EC      | `vreg`         | `v[0-15]`                          | `w`                  |
 | Arm64EC      | `vreg_low16`   | `v[0-15]`                          | `x`                  |
@@ -90,6 +93,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `freg`                          | None           | `f32`,                                  |
 | s390x        | `reg`, `reg_addr`               | None           | `i8`, `i16`, `i32`, `i64`               |
 | s390x        | `freg`                          | None           | `f32`, `f64`                            |
+| s390x        | `vreg`                          | N/A            | Only clobbers                           |
+| s390x        | `areg`                          | N/A            | Only clobbers                           |
 | Arm64EC      | `reg`                           | None           | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
 | Arm64EC      | `vreg`                          | None           | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`, <br> `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
 
@@ -157,6 +162,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `r15`                                   | This is the link register. |
 | CSKY         | `r[26-30]`                              | Reserved by its ABI.       |
 | CSKY         | `r31`                                   | This is the TLS register.  |
+| s390x        | `c[0-15]`                               | Reserved by the kernel. |
+| s390x        | `a[0-1]`                                | Reserved for system use. |
 | Arm64EC      | `xzr`                                   | This is a constant zero register which can't be modified. |
 | Arm64EC      | `x18`                                   | This is an OS-reserved register. |
 | Arm64EC      | `x13`, `x14`, `x23`, `x24`, `x28`, `v[16-31]` | These are AArch64 registers that are not supported for Arm64EC. |
diff --git a/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md b/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md
new file mode 100644
index 00000000000..ad795ff9d9b
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md
@@ -0,0 +1,22 @@
+# `cfg_boolean_literals`
+
+The tracking issue for this feature is: [#131204]
+
+[#131204]: https://github.com/rust-lang/rust/issues/131204
+
+------------------------
+
+The `cfg_boolean_literals` feature makes it possible to use the `true`/`false`
+literal as cfg predicate. They always evaluate to true/false respectively.
+
+## Examples
+
+```rust
+#![feature(cfg_boolean_literals)]
+
+#[cfg(true)]
+const A: i32 = 5;
+
+#[cfg(all(false))]
+const A: i32 = 58 * 89;
+```
diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh
index 2aa0d9f69cc..ba7f2c9fb5d 100644
--- a/src/etc/completions/x.py.sh
+++ b/src/etc/completions/x.py.sh
@@ -2741,7 +2741,7 @@ _x.py() {
             return 0
             ;;
         x.py__setup)
-            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [<PROFILE>|hook|vscode|link] [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [<PROFILE>|hook|editor|link] [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
diff --git a/src/etc/rust_analyzer_eglot.el b/src/etc/rust_analyzer_eglot.el
index e55d80d98de..7b4309f8e18 100644
--- a/src/etc/rust_analyzer_eglot.el
+++ b/src/etc/rust_analyzer_eglot.el
@@ -2,28 +2,28 @@
   .((eglot-workspace-configuration
      . (:rust-analyzer
         ( :check ( :invocationLocation "root"
-                   :invocationStrategy "once"
-                   :overrideCommand ["python3"
-                                     "x.py"
-                                     "check"
-                                     "--json-output"])
-          :linkedProjects ["Cargo.toml"
-                           "src/tools/x/Cargo.toml"
-                           "src/bootstrap/Cargo.toml"
-                           "src/tools/rust-analyzer/Cargo.toml"
-                           "compiler/rustc_codegen_cranelift/Cargo.toml"
-                           "compiler/rustc_codegen_gcc/Cargo.toml"]
-          :rustfmt ( :overrideCommand ["build/host/rustfmt/bin/rustfmt"
-                                       "--edition=2021"])
-          :procMacro ( :server "build/host/stage0/libexec/rust-analyzer-proc-macro-srv"
-                       :enable t)
-          :cargo ( :buildScripts ( :enable t
-                                   :invocationLocation "root"
-                                   :invocationStrategy "once"
-                                   :overrideCommand ["python3"
-                                                     "x.py"
-                                                     "check"
-                                                     "--json-output"])
-                   :sysrootSrc "./library"
-                   :extraEnv (:RUSTC_BOOTSTRAP "1"))
-          :rustc ( :source "./Cargo.toml" )))))))
+                                       :invocationStrategy "once"
+                                       :overrideCommand ["python3"
+                                                         "x.py"
+                                                         "check"
+                                                         "--json-output"])
+                 :linkedProjects ["Cargo.toml"
+                                  "src/tools/x/Cargo.toml"
+                                  "src/bootstrap/Cargo.toml"
+                                  "src/tools/rust-analyzer/Cargo.toml"
+                                  "compiler/rustc_codegen_cranelift/Cargo.toml"
+                                  "compiler/rustc_codegen_gcc/Cargo.toml"]
+                 :rustfmt ( :overrideCommand ["build/host/rustfmt/bin/rustfmt"
+                                              "--edition=2021"])
+                 :procMacro ( :server "build/host/stage0/libexec/rust-analyzer-proc-macro-srv"
+                                      :enable t)
+                 :cargo ( :buildScripts ( :enable t
+                                                  :invocationLocation "root"
+                                                  :invocationStrategy "once"
+                                                  :overrideCommand ["python3"
+                                                                    "x.py"
+                                                                    "check"
+                                                                    "--json-output"])
+                                        :sysrootSrc "./library"
+                                        :extraEnv (:RUSTC_BOOTSTRAP "1"))
+                 :rustc ( :source "./Cargo.toml" )))))))
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 08c88fc950d..d966f993104 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -117,6 +117,7 @@ fn synthesize_auto_trait_impl<'tcx>(
         name: None,
         inner: Box::new(clean::ItemInner {
             attrs: Default::default(),
+            stability: None,
             kind: clean::ImplItem(Box::new(clean::Impl {
                 safety: hir::Safety::Safe,
                 generics,
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 36821294885..1f3cb4a61b8 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -87,6 +87,7 @@ pub(crate) fn synthesize_blanket_impls(
                 item_id: clean::ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
                 inner: Box::new(clean::ItemInner {
                     attrs: Default::default(),
+                    stability: None,
                     kind: clean::ImplItem(Box::new(clean::Impl {
                         safety: hir::Safety::Safe,
                         generics: clean_ty_generics(
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index 26739219085..53830016a80 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -6,7 +6,7 @@
 use std::fmt::{self, Write};
 use std::{mem, ops};
 
-use rustc_ast::{LitKind, MetaItem, MetaItemKind, NestedMetaItem};
+use rustc_ast::{LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_feature::Features;
 use rustc_session::parse::ParseSess;
@@ -48,6 +48,10 @@ impl Cfg {
     ) -> Result<Option<Cfg>, InvalidCfgError> {
         match nested_cfg {
             NestedMetaItem::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude),
+            NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => match *b {
+                true => Ok(Some(Cfg::True)),
+                false => Ok(Some(Cfg::False)),
+            },
             NestedMetaItem::Lit(ref lit) => {
                 Err(InvalidCfgError { msg: "unexpected literal", span: lit.span })
             }
@@ -120,8 +124,8 @@ impl Cfg {
     ///
     /// If the content is not properly formatted, it will return an error indicating what and where
     /// the error is.
-    pub(crate) fn parse(cfg: &MetaItem) -> Result<Cfg, InvalidCfgError> {
-        Self::parse_without(cfg, &FxHashSet::default()).map(|ret| ret.unwrap())
+    pub(crate) fn parse(cfg: &NestedMetaItem) -> Result<Cfg, InvalidCfgError> {
+        Self::parse_nested(cfg, &FxHashSet::default()).map(|ret| ret.unwrap())
     }
 
     /// Checks whether the given configuration can be matched in the current session.
diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs
index 0ab655103e2..d4b11451c89 100644
--- a/src/librustdoc/clean/cfg/tests.rs
+++ b/src/librustdoc/clean/cfg/tests.rs
@@ -1,4 +1,5 @@
-use rustc_ast::{MetaItemLit, Path, Safety, StrStyle};
+use rustc_ast::ast::LitIntType;
+use rustc_ast::{MetaItemLit, NestedMetaItem, Path, Safety, StrStyle};
 use rustc_span::symbol::{Ident, kw};
 use rustc_span::{DUMMY_SP, create_default_session_globals_then};
 use thin_vec::thin_vec;
@@ -13,52 +14,52 @@ fn name_value_cfg(name: &str, value: &str) -> Cfg {
     Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value)))
 }
 
-fn dummy_meta_item_word(name: &str) -> MetaItem {
-    MetaItem {
+fn dummy_lit(symbol: Symbol, kind: LitKind) -> NestedMetaItem {
+    NestedMetaItem::Lit(MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP })
+}
+
+fn dummy_meta_item_word(name: &str) -> NestedMetaItem {
+    NestedMetaItem::MetaItem(MetaItem {
         unsafety: Safety::Default,
         path: Path::from_ident(Ident::from_str(name)),
         kind: MetaItemKind::Word,
         span: DUMMY_SP,
-    }
+    })
 }
 
-fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> MetaItem {
+fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> NestedMetaItem {
     let lit = MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP };
-    MetaItem {
+    NestedMetaItem::MetaItem(MetaItem {
         unsafety: Safety::Default,
         path: Path::from_ident(Ident::from_str(name)),
         kind: MetaItemKind::NameValue(lit),
         span: DUMMY_SP,
-    }
+    })
 }
 
 macro_rules! dummy_meta_item_list {
     ($name:ident, [$($list:ident),* $(,)?]) => {
-        MetaItem {
+        NestedMetaItem::MetaItem(MetaItem {
             unsafety: Safety::Default,
             path: Path::from_ident(Ident::from_str(stringify!($name))),
             kind: MetaItemKind::List(thin_vec![
                 $(
-                    NestedMetaItem::MetaItem(
-                        dummy_meta_item_word(stringify!($list)),
-                    ),
+                    dummy_meta_item_word(stringify!($list)),
                 )*
             ]),
             span: DUMMY_SP,
-        }
+        })
     };
 
     ($name:ident, [$($list:expr),* $(,)?]) => {
-        MetaItem {
+        NestedMetaItem::MetaItem(MetaItem {
             unsafety: Safety::Default,
             path: Path::from_ident(Ident::from_str(stringify!($name))),
             kind: MetaItemKind::List(thin_vec![
-                $(
-                    NestedMetaItem::MetaItem($list),
-                )*
+                $($list,)*
             ]),
             span: DUMMY_SP,
-        }
+        })
     };
 }
 
@@ -251,6 +252,14 @@ fn test_cfg_or() {
 #[test]
 fn test_parse_ok() {
     create_default_session_globals_then(|| {
+        let r#true = Symbol::intern("true");
+        let mi = dummy_lit(r#true, LitKind::Bool(true));
+        assert_eq!(Cfg::parse(&mi), Ok(Cfg::True));
+
+        let r#false = Symbol::intern("false");
+        let mi = dummy_lit(r#false, LitKind::Bool(false));
+        assert_eq!(Cfg::parse(&mi), Ok(Cfg::False));
+
         let mi = dummy_meta_item_word("all");
         assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all")));
 
@@ -309,6 +318,14 @@ fn test_parse_err() {
 
         let mi = dummy_meta_item_list!(not, [dummy_meta_item_list!(foo, []),]);
         assert!(Cfg::parse(&mi).is_err());
+
+        let c = Symbol::intern("e");
+        let mi = dummy_lit(c, LitKind::Char('e'));
+        assert!(Cfg::parse(&mi).is_err());
+
+        let five = Symbol::intern("5");
+        let mi = dummy_lit(five, LitKind::Int(5.into(), LitIntType::Unsuffixed));
+        assert!(Cfg::parse(&mi).is_err());
     })
 }
 
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index d3c4ef4dc90..e7f921eef7f 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -672,6 +672,7 @@ fn build_module_items(
                     item_id: ItemId::DefId(did),
                     inner: Box::new(clean::ItemInner {
                         attrs: Default::default(),
+                        stability: None,
                         kind: clean::ImportItem(clean::Import::new_simple(
                             item.ident.name,
                             clean::ImportSource {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 3d845cf878f..fa73733360c 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1828,13 +1828,8 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
             Array(Box::new(clean_ty(ty, cx)), length.into())
         }
         TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
-        TyKind::OpaqueDef(item_id, _, _) => {
-            let item = cx.tcx.hir().item(item_id);
-            if let hir::ItemKind::OpaqueTy(ty) = item.kind {
-                ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
-            } else {
-                unreachable!()
-            }
+        TyKind::OpaqueDef(ty, _) => {
+            ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
         }
         TyKind::Path(_) => clean_qpath(ty, cx),
         TyKind::TraitObject(bounds, lifetime, _) => {
@@ -2736,9 +2731,6 @@ fn clean_maybe_renamed_item<'tcx>(
                 type_: clean_ty(ty, cx),
                 kind: ConstantKind::Local { body: body_id, def_id },
             })),
-            // clean_ty changes types which reference an OpaqueTy item to instead be
-            // an ImplTrait, so it's ok to return nothing here.
-            ItemKind::OpaqueTy(_) => return vec![],
             ItemKind::TyAlias(hir_ty, generics) => {
                 *cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
                 let rustdoc_ty = clean_ty(hir_ty, cx);
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index b9c5e8e787b..ea4388b305b 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -5,10 +5,11 @@ use std::sync::{Arc, OnceLock as OnceCell};
 use std::{fmt, iter};
 
 use arrayvec::ArrayVec;
+use rustc_ast::NestedMetaItem;
 use rustc_ast_pretty::pprust;
-use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel, StableSince};
+use rustc_attr::{ConstStability, Deprecation, Stability, StableSince};
 use rustc_const_eval::const_eval::is_unstable_const_fn;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
 use rustc_hir::lang_items::LangItem;
@@ -113,7 +114,7 @@ impl From<DefId> for ItemId {
 pub(crate) struct Crate {
     pub(crate) module: Item,
     /// Only here so that they can be filtered through the rustdoc passes.
-    pub(crate) external_traits: Box<FxHashMap<DefId, Trait>>,
+    pub(crate) external_traits: Box<FxIndexMap<DefId, Trait>>,
 }
 
 impl Crate {
@@ -333,6 +334,8 @@ pub(crate) struct ItemInner {
     /// E.g., struct vs enum vs function.
     pub(crate) kind: ItemKind,
     pub(crate) attrs: Attributes,
+    /// The effective stability, filled out by the `propagate-stability` pass.
+    pub(crate) stability: Option<Stability>,
 }
 
 impl std::ops::Deref for Item {
@@ -381,46 +384,17 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 }
 
 impl Item {
+    /// Returns the effective stability of the item.
+    ///
+    /// This method should only be called after the `propagate-stability` pass has been run.
     pub(crate) fn stability(&self, tcx: TyCtxt<'_>) -> Option<Stability> {
-        let (mut def_id, mut stability) = if let Some(inlined) = self.inline_stmt_id {
-            let inlined_def_id = inlined.to_def_id();
-            if let Some(stability) = tcx.lookup_stability(inlined_def_id) {
-                (inlined_def_id, stability)
-            } else {
-                // For re-exports into crates without `staged_api`, reuse the original stability.
-                // This is necessary, because we always want to mark unstable items.
-                let def_id = self.def_id()?;
-                return tcx.lookup_stability(def_id);
-            }
-        } else {
-            let def_id = self.def_id()?;
-            let stability = tcx.lookup_stability(def_id)?;
-            (def_id, stability)
-        };
-
-        let StabilityLevel::Stable { mut since, allowed_through_unstable_modules: false } =
-            stability.level
-        else {
-            return Some(stability);
-        };
-
-        // If any of the item's ancestors was stabilized later or is still unstable,
-        // then report the ancestor's stability instead.
-        while let Some(parent_def_id) = tcx.opt_parent(def_id) {
-            if let Some(parent_stability) = tcx.lookup_stability(parent_def_id) {
-                match parent_stability.level {
-                    StabilityLevel::Unstable { .. } => return Some(parent_stability),
-                    StabilityLevel::Stable { since: parent_since, .. } => {
-                        if parent_since > since {
-                            stability = parent_stability;
-                            since = parent_since;
-                        }
-                    }
-                }
-            }
-            def_id = parent_def_id;
-        }
-        Some(stability)
+        let stability = self.inner.stability;
+        debug_assert!(
+            stability.is_some()
+                || self.def_id().is_none_or(|did| tcx.lookup_stability(did).is_none()),
+            "missing stability for cleaned item: {self:?}",
+        );
+        stability
     }
 
     pub(crate) fn const_stability(&self, tcx: TyCtxt<'_>) -> Option<ConstStability> {
@@ -502,7 +476,7 @@ impl Item {
 
         Item {
             item_id: def_id.into(),
-            inner: Box::new(ItemInner { kind, attrs }),
+            inner: Box::new(ItemInner { kind, attrs, stability: None }),
             name,
             cfg,
             inline_stmt_id: None,
@@ -638,10 +612,7 @@ impl Item {
     }
 
     pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<StableSince> {
-        match self.stability(tcx)?.level {
-            StabilityLevel::Stable { since, .. } => Some(since),
-            StabilityLevel::Unstable { .. } => None,
-        }
+        self.stability(tcx).and_then(|stability| stability.stable_since())
     }
 
     pub(crate) fn is_non_exhaustive(&self) -> bool {
@@ -1016,7 +987,7 @@ pub(crate) trait AttributesExt {
                 .peekable();
             if doc_cfg.peek().is_some() && doc_cfg_active {
                 doc_cfg
-                    .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
+                    .filter_map(|attr| Cfg::parse(&attr).ok())
                     .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
             } else if doc_auto_cfg_active {
                 // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
@@ -1072,7 +1043,7 @@ pub(crate) trait AttributesExt {
                     let mut meta = attr.meta_item().unwrap().clone();
                     meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
 
-                    if let Ok(feat_cfg) = Cfg::parse(&meta) {
+                    if let Ok(feat_cfg) = Cfg::parse(&NestedMetaItem::MetaItem(meta)) {
                         cfg &= feat_cfg;
                     }
                 }
@@ -1252,7 +1223,7 @@ impl Attributes {
     }
 
     pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
-        let mut aliases = FxHashSet::default();
+        let mut aliases = FxIndexSet::default();
 
         for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) {
             if let Some(values) = attr.meta_item_list() {
@@ -1788,7 +1759,7 @@ pub(crate) enum PrimitiveType {
     Never,
 }
 
-type SimplifiedTypes = FxHashMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
+type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
 impl PrimitiveType {
     pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
         use ast::{FloatTy, IntTy, UintTy};
@@ -1956,10 +1927,10 @@ impl PrimitiveType {
     /// In particular, if a crate depends on both `std` and another crate that also defines
     /// `rustc_doc_primitive`, then it's entirely random whether `std` or the other crate is picked.
     /// (no_std crates are usually fine unless multiple dependencies define a primitive.)
-    pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxHashMap<PrimitiveType, DefId> {
-        static PRIMITIVE_LOCATIONS: OnceCell<FxHashMap<PrimitiveType, DefId>> = OnceCell::new();
+    pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
+        static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
         PRIMITIVE_LOCATIONS.get_or_init(|| {
-            let mut primitive_locations = FxHashMap::default();
+            let mut primitive_locations = FxIndexMap::default();
             // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
             // This is a degenerate case that I don't plan to support.
             for &crate_num in tcx.crates(()) {
@@ -2489,7 +2460,7 @@ pub(crate) struct Impl {
 }
 
 impl Impl {
-    pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet<Symbol> {
+    pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
         self.trait_
             .as_ref()
             .map(|t| t.def_id())
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 7a37f5c70a5..2cd69474b1c 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -5,7 +5,7 @@ use std::path::{Path, PathBuf};
 use std::str::FromStr;
 use std::{fmt, io};
 
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::DiagCtxtHandle;
 use rustc_session::config::{
     self, CodegenOptions, CrateType, ErrorOutputType, Externs, Input, JsonUnusedExterns,
@@ -249,7 +249,7 @@ pub(crate) struct RenderOptions {
     pub(crate) extern_html_root_takes_precedence: bool,
     /// A map of the default settings (values are as for DOM storage API). Keys should lack the
     /// `rustdoc-` prefix.
-    pub(crate) default_settings: FxHashMap<String, String>,
+    pub(crate) default_settings: FxIndexMap<String, String>,
     /// If present, suffix added to CSS/JavaScript files when referencing them in generated pages.
     pub(crate) resource_suffix: String,
     /// Whether to create an index page in the root of the output directory. If this is true but
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 4c48c075a94..aaf4c80f997 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -2,7 +2,7 @@ use std::sync::atomic::AtomicBool;
 use std::sync::{Arc, LazyLock};
 use std::{io, mem};
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::codes::*;
@@ -39,7 +39,7 @@ pub(crate) struct DocContext<'tcx> {
     /// Most of this logic is copied from rustc_lint::late.
     pub(crate) param_env: ParamEnv<'tcx>,
     /// Later on moved through `clean::Crate` into `cache`
-    pub(crate) external_traits: FxHashMap<DefId, clean::Trait>,
+    pub(crate) external_traits: FxIndexMap<DefId, clean::Trait>,
     /// Used while populating `external_traits` to ensure we don't process the same trait twice at
     /// the same time.
     pub(crate) active_extern_traits: DefIdSet,
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 3ee6b24ac92..d5bc2a93fa8 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -14,7 +14,7 @@ use std::{panic, str};
 pub(crate) use make::DocTestBuilder;
 pub(crate) use markdown::test as test_markdown;
 use rustc_ast as ast;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
 use rustc_errors::{ColorConfig, DiagCtxtHandle, ErrorGuaranteed, FatalError};
 use rustc_hir::CRATE_HIR_ID;
 use rustc_hir::def_id::LOCAL_CRATE;
@@ -186,8 +186,6 @@ pub(crate) fn run(
 
                 let mut collector = CreateRunnableDocTests::new(options, opts);
                 let hir_collector = HirCollector::new(
-                    &compiler.sess,
-                    tcx.hir(),
                     ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()),
                     enable_per_target_ignores,
                     tcx,
@@ -215,12 +213,13 @@ pub(crate) fn run(
         let unused_extern_reports: Vec<_> =
             std::mem::take(&mut unused_extern_reports.lock().unwrap());
         if unused_extern_reports.len() == compiling_test_count {
-            let extern_names = externs.iter().map(|(name, _)| name).collect::<FxHashSet<&String>>();
+            let extern_names =
+                externs.iter().map(|(name, _)| name).collect::<FxIndexSet<&String>>();
             let mut unused_extern_names = unused_extern_reports
                 .iter()
-                .map(|uexts| uexts.unused_extern_names.iter().collect::<FxHashSet<&String>>())
+                .map(|uexts| uexts.unused_extern_names.iter().collect::<FxIndexSet<&String>>())
                 .fold(extern_names, |uextsa, uextsb| {
-                    uextsa.intersection(&uextsb).copied().collect::<FxHashSet<&String>>()
+                    uextsa.intersection(&uextsb).copied().collect::<FxIndexSet<&String>>()
                 })
                 .iter()
                 .map(|v| (*v).clone())
@@ -255,7 +254,7 @@ pub(crate) fn run_tests(
     rustdoc_options: &Arc<RustdocOptions>,
     unused_extern_reports: &Arc<Mutex<Vec<UnusedExterns>>>,
     mut standalone_tests: Vec<test::TestDescAndFn>,
-    mergeable_tests: FxHashMap<Edition, Vec<(DocTestBuilder, ScrapedDocTest)>>,
+    mergeable_tests: FxIndexMap<Edition, Vec<(DocTestBuilder, ScrapedDocTest)>>,
 ) {
     let mut test_args = Vec::with_capacity(rustdoc_options.test_args.len() + 1);
     test_args.insert(0, "rustdoctest".to_string());
@@ -777,7 +776,7 @@ pub(crate) trait DocTestVisitor {
 
 struct CreateRunnableDocTests {
     standalone_tests: Vec<test::TestDescAndFn>,
-    mergeable_tests: FxHashMap<Edition, Vec<(DocTestBuilder, ScrapedDocTest)>>,
+    mergeable_tests: FxIndexMap<Edition, Vec<(DocTestBuilder, ScrapedDocTest)>>,
 
     rustdoc_options: Arc<RustdocOptions>,
     opts: GlobalTestOptions,
@@ -792,7 +791,7 @@ impl CreateRunnableDocTests {
         let can_merge_doctests = rustdoc_options.edition >= Edition::Edition2024;
         CreateRunnableDocTests {
             standalone_tests: Vec::new(),
-            mergeable_tests: FxHashMap::default(),
+            mergeable_tests: FxIndexMap::default(),
             rustdoc_options: Arc::new(rustdoc_options),
             opts,
             visited_tests: FxHashMap::default(),
@@ -837,7 +836,7 @@ impl CreateRunnableDocTests {
         let is_standalone = !doctest.can_be_merged
             || scraped_test.langstr.compile_fail
             || scraped_test.langstr.test_harness
-            || scraped_test.langstr.standalone
+            || scraped_test.langstr.standalone_crate
             || self.rustdoc_options.nocapture
             || self.rustdoc_options.test_args.iter().any(|arg| arg == "--show-output");
         if is_standalone {
diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs
index d560e3a476b..efbb332d12d 100644
--- a/src/librustdoc/doctest/make.rs
+++ b/src/librustdoc/doctest/make.rs
@@ -48,7 +48,7 @@ impl DocTestBuilder {
     ) -> Self {
         let can_merge_doctests = can_merge_doctests
             && lang_str.is_some_and(|lang_str| {
-                !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone
+                !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone_crate
             });
 
         let SourceInfo { crate_attrs, maybe_crate_attrs, crates, everything_else } =
diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs
index 326ca4ee1e6..942ec8d9936 100644
--- a/src/librustdoc/doctest/runner.rs
+++ b/src/librustdoc/doctest/runner.rs
@@ -1,6 +1,6 @@
 use std::fmt::Write;
 
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_span::edition::Edition;
 
 use crate::doctest::{
@@ -11,7 +11,7 @@ use crate::html::markdown::{Ignore, LangString};
 
 /// Convenient type to merge compatible doctests into one.
 pub(crate) struct DocTestRunner {
-    crate_attrs: FxHashSet<String>,
+    crate_attrs: FxIndexSet<String>,
     ids: String,
     output: String,
     supports_color: bool,
@@ -21,7 +21,7 @@ pub(crate) struct DocTestRunner {
 impl DocTestRunner {
     pub(crate) fn new() -> Self {
         Self {
-            crate_attrs: FxHashSet::default(),
+            crate_attrs: FxIndexSet::default(),
             ids: String::new(),
             output: String::new(),
             supports_color: true,
diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs
index cc85a73430b..a9ab02e29cd 100644
--- a/src/librustdoc/doctest/rust.rs
+++ b/src/librustdoc/doctest/rust.rs
@@ -6,11 +6,9 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
 use rustc_hir::{self as hir, CRATE_HIR_ID, intravisit};
-use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_resolve::rustdoc::span_of_fragments;
-use rustc_session::Session;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span};
 
@@ -63,30 +61,22 @@ impl DocTestVisitor for RustCollector {
     fn visit_header(&mut self, _name: &str, _level: u32) {}
 }
 
-pub(super) struct HirCollector<'a, 'tcx> {
-    sess: &'a Session,
-    map: Map<'tcx>,
+pub(super) struct HirCollector<'tcx> {
     codes: ErrorCodes,
     tcx: TyCtxt<'tcx>,
     enable_per_target_ignores: bool,
     collector: RustCollector,
 }
 
-impl<'a, 'tcx> HirCollector<'a, 'tcx> {
-    pub fn new(
-        sess: &'a Session,
-        map: Map<'tcx>,
-        codes: ErrorCodes,
-        enable_per_target_ignores: bool,
-        tcx: TyCtxt<'tcx>,
-    ) -> Self {
+impl<'tcx> HirCollector<'tcx> {
+    pub fn new(codes: ErrorCodes, enable_per_target_ignores: bool, tcx: TyCtxt<'tcx>) -> Self {
         let collector = RustCollector {
-            source_map: sess.psess.clone_source_map(),
+            source_map: tcx.sess.psess.clone_source_map(),
             cur_path: vec![],
             position: DUMMY_SP,
             tests: vec![],
         };
-        Self { sess, map, codes, enable_per_target_ignores, tcx, collector }
+        Self { codes, enable_per_target_ignores, tcx, collector }
     }
 
     pub fn collect_crate(mut self) -> Vec<ScrapedDocTest> {
@@ -98,7 +88,7 @@ impl<'a, 'tcx> HirCollector<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> HirCollector<'a, 'tcx> {
+impl<'tcx> HirCollector<'tcx> {
     fn visit_testable<F: FnOnce(&mut Self)>(
         &mut self,
         name: String,
@@ -108,7 +98,7 @@ impl<'a, 'tcx> HirCollector<'a, 'tcx> {
     ) {
         let ast_attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id));
         if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) {
-            if !cfg.matches(&self.sess.psess, Some(self.tcx.features())) {
+            if !cfg.matches(&self.tcx.sess.psess, Some(self.tcx.features())) {
                 return;
             }
         }
@@ -141,17 +131,17 @@ impl<'a, 'tcx> HirCollector<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> intravisit::Visitor<'tcx> for HirCollector<'a, 'tcx> {
+impl<'tcx> intravisit::Visitor<'tcx> for HirCollector<'tcx> {
     type NestedFilter = nested_filter::All;
 
     fn nested_visit_map(&mut self) -> Self::Map {
-        self.map
+        self.tcx.hir()
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'_>) {
         let name = match &item.kind {
             hir::ItemKind::Impl(impl_) => {
-                rustc_hir_pretty::id_to_string(&self.map, impl_.self_ty.hir_id)
+                rustc_hir_pretty::id_to_string(&self.tcx.hir(), impl_.self_ty.hir_id)
             }
             _ => item.ident.to_string(),
         };
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index db1a0bd0af9..ff0d537b19f 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -1,6 +1,6 @@
 use std::mem;
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::Symbol;
@@ -42,7 +42,7 @@ pub(crate) struct Cache {
     /// URLs when a type is being linked to. External paths are not located in
     /// this map because the `External` type itself has all the information
     /// necessary.
-    pub(crate) paths: FxHashMap<DefId, (Vec<Symbol>, ItemType)>,
+    pub(crate) paths: FxIndexMap<DefId, (Vec<Symbol>, ItemType)>,
 
     /// Similar to `paths`, but only holds external paths. This is only used for
     /// generating explicit hyperlinks to other crates.
@@ -64,18 +64,18 @@ pub(crate) struct Cache {
     /// Implementations of a crate should inherit the documentation of the
     /// parent trait if no extra documentation is specified, and default methods
     /// should show up in documentation about trait implementations.
-    pub(crate) traits: FxHashMap<DefId, clean::Trait>,
+    pub(crate) traits: FxIndexMap<DefId, clean::Trait>,
 
     /// When rendering traits, it's often useful to be able to list all
     /// implementors of the trait, and this mapping is exactly, that: a mapping
     /// of trait ids to the list of known implementors of the trait
-    pub(crate) implementors: FxHashMap<DefId, Vec<Impl>>,
+    pub(crate) implementors: FxIndexMap<DefId, Vec<Impl>>,
 
     /// Cache of where external crate documentation can be found.
-    pub(crate) extern_locations: FxHashMap<CrateNum, ExternalLocation>,
+    pub(crate) extern_locations: FxIndexMap<CrateNum, ExternalLocation>,
 
     /// Cache of where documentation for primitives can be found.
-    pub(crate) primitive_locations: FxHashMap<clean::PrimitiveType, DefId>,
+    pub(crate) primitive_locations: FxIndexMap<clean::PrimitiveType, DefId>,
 
     // Note that external items for which `doc(hidden)` applies to are shown as
     // non-reachable while local items aren't. This is because we're reusing
@@ -118,7 +118,7 @@ pub(crate) struct Cache {
     // crawl. In order to prevent crashes when looking for notable traits or
     // when gathering trait documentation on a type, hold impls here while
     // folding and add them to the cache later on if we find the trait.
-    orphan_trait_impls: Vec<(DefId, FxHashSet<DefId>, Impl)>,
+    orphan_trait_impls: Vec<(DefId, FxIndexSet<DefId>, Impl)>,
 
     /// All intra-doc links resolved so far.
     ///
@@ -376,7 +376,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
             // Figure out the id of this impl. This may map to a
             // primitive rather than always to a struct/enum.
             // Note: matching twice to restrict the lifetime of the `i` borrow.
-            let mut dids = FxHashSet::default();
+            let mut dids = FxIndexSet::default();
             match i.for_ {
                 clean::Type::Path { ref path }
                 | clean::BorrowedRef { type_: box clean::Type::Path { ref path }, .. } => {
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 69b3421f888..e7ddd4b73b4 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -8,7 +8,7 @@
 use std::collections::VecDeque;
 use std::fmt::{Display, Write};
 
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_lexer::{Cursor, LiteralKind, TokenKind};
 use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
@@ -34,7 +34,7 @@ pub(crate) struct HrefContext<'a, 'tcx> {
 /// Decorations are represented as a map from CSS class to vector of character ranges.
 /// Each range will be wrapped in a span with that class.
 #[derive(Default)]
-pub(crate) struct DecorationInfo(pub(crate) FxHashMap<&'static str, Vec<(u32, u32)>>);
+pub(crate) struct DecorationInfo(pub(crate) FxIndexMap<&'static str, Vec<(u32, u32)>>);
 
 #[derive(Eq, PartialEq, Clone, Copy)]
 pub(crate) enum Tooltip {
diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
index 75328e724fe..fd5275189d6 100644
--- a/src/librustdoc/html/highlight/tests.rs
+++ b/src/librustdoc/html/highlight/tests.rs
@@ -1,5 +1,5 @@
 use expect_test::expect_file;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_span::create_default_session_globals_then;
 
 use super::{DecorationInfo, write_code};
@@ -73,7 +73,7 @@ fn test_decorations() {
 let y = 2;
 let z = 3;
 let a = 4;";
-        let mut decorations = FxHashMap::default();
+        let mut decorations = FxIndexMap::default();
         decorations.insert("example", vec![(0, 10), (11, 21)]);
         decorations.insert("example2", vec![(22, 32)]);
 
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 3684dc42ac7..31ccfeb3873 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -1,7 +1,7 @@
 use std::path::PathBuf;
 
 use rinja::Template;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
 
 use super::static_files::{STATIC_FILES, StaticFiles};
 use crate::externalfiles::ExternalHtml;
@@ -13,7 +13,7 @@ pub(crate) struct Layout {
     pub(crate) logo: String,
     pub(crate) favicon: String,
     pub(crate) external_html: ExternalHtml,
-    pub(crate) default_settings: FxHashMap<String, String>,
+    pub(crate) default_settings: FxIndexMap<String, String>,
     pub(crate) krate: String,
     pub(crate) krate_version: String,
     /// The given user css file which allow to customize the generated
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index b18d621478c..6c5c58754a8 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -38,7 +38,7 @@ use pulldown_cmark::{
     BrokenLink, BrokenLinkCallback, CodeBlockKind, CowStr, Event, LinkType, OffsetIter, Options,
     Parser, Tag, TagEnd, html,
 };
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::{Diag, DiagMessage};
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::TyCtxt;
@@ -651,12 +651,12 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> {
 /// references.
 struct Footnotes<'a, I> {
     inner: I,
-    footnotes: FxHashMap<String, (Vec<Event<'a>>, u16)>,
+    footnotes: FxIndexMap<String, (Vec<Event<'a>>, u16)>,
 }
 
 impl<'a, I> Footnotes<'a, I> {
     fn new(iter: I) -> Self {
-        Footnotes { inner: iter, footnotes: FxHashMap::default() }
+        Footnotes { inner: iter, footnotes: FxIndexMap::default() }
     }
 
     fn get_entry(&mut self, key: &str) -> &mut (Vec<Event<'a>>, u16) {
@@ -694,7 +694,7 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> {
                 Some(e) => return Some(e),
                 None => {
                     if !self.footnotes.is_empty() {
-                        let mut v: Vec<_> = self.footnotes.drain().map(|(_, x)| x).collect();
+                        let mut v: Vec<_> = self.footnotes.drain(..).map(|(_, x)| x).collect();
                         v.sort_by(|a, b| a.1.cmp(&b.1));
                         let mut ret = String::from("<div class=\"footnotes\"><hr><ol>");
                         for (mut content, id) in v {
@@ -871,7 +871,7 @@ pub(crate) struct LangString {
     pub(crate) rust: bool,
     pub(crate) test_harness: bool,
     pub(crate) compile_fail: bool,
-    pub(crate) standalone: bool,
+    pub(crate) standalone_crate: bool,
     pub(crate) error_codes: Vec<String>,
     pub(crate) edition: Option<Edition>,
     pub(crate) added_classes: Vec<String>,
@@ -1194,7 +1194,7 @@ impl Default for LangString {
             rust: true,
             test_harness: false,
             compile_fail: false,
-            standalone: false,
+            standalone_crate: false,
             error_codes: Vec::new(),
             edition: None,
             added_classes: Vec::new(),
@@ -1264,8 +1264,8 @@ impl LangString {
                         seen_rust_tags = !seen_other_tags || seen_rust_tags;
                         data.no_run = true;
                     }
-                    LangStringToken::LangToken("standalone") => {
-                        data.standalone = true;
+                    LangStringToken::LangToken("standalone_crate") => {
+                        data.standalone_crate = true;
                         seen_rust_tags = !seen_other_tags || seen_rust_tags;
                     }
                     LangStringToken::LangToken(x) if x.starts_with("edition") => {
@@ -1298,44 +1298,47 @@ impl LangString {
                     }
                     LangStringToken::LangToken(x) if extra.is_some() => {
                         let s = x.to_lowercase();
-                        if let Some((flag, help)) = if s == "compile-fail"
-                            || s == "compile_fail"
-                            || s == "compilefail"
-                        {
-                            Some((
-                                "compile_fail",
-                                "the code block will either not be tested if not marked as a rust one \
-                                 or won't fail if it compiles successfully",
-                            ))
-                        } else if s == "should-panic" || s == "should_panic" || s == "shouldpanic" {
-                            Some((
-                                "should_panic",
-                                "the code block will either not be tested if not marked as a rust one \
-                                 or won't fail if it doesn't panic when running",
-                            ))
-                        } else if s == "no-run" || s == "no_run" || s == "norun" {
-                            Some((
-                                "no_run",
-                                "the code block will either not be tested if not marked as a rust one \
-                                 or will be run (which you might not want)",
-                            ))
-                        } else if s == "test-harness" || s == "test_harness" || s == "testharness" {
-                            Some((
-                                "test_harness",
-                                "the code block will either not be tested if not marked as a rust one \
-                                 or the code will be wrapped inside a main function",
-                            ))
-                        } else {
-                            None
+                        if let Some(help) = match s.as_str() {
+                            "compile-fail" | "compile_fail" | "compilefail" => Some(
+                                "use `compile_fail` to invert the results of this test, so that it \
+                                passes if it cannot be compiled and fails if it can",
+                            ),
+                            "should-panic" | "should_panic" | "shouldpanic" => Some(
+                                "use `should_panic` to invert the results of this test, so that if \
+                                passes if it panics and fails if it does not",
+                            ),
+                            "no-run" | "no_run" | "norun" => Some(
+                                "use `no_run` to compile, but not run, the code sample during \
+                                testing",
+                            ),
+                            "test-harness" | "test_harness" | "testharness" => Some(
+                                "use `test_harness` to run functions marked `#[test]` instead of a \
+                                potentially-implicit `main` function",
+                            ),
+                            "standalone" | "standalone_crate" | "standalone-crate" => {
+                                if let Some(extra) = extra
+                                    && extra.sp.at_least_rust_2024()
+                                {
+                                    Some(
+                                        "use `standalone_crate` to compile this code block \
+                                        separately",
+                                    )
+                                } else {
+                                    None
+                                }
+                            }
+                            _ => None,
                         } {
                             if let Some(extra) = extra {
                                 extra.error_invalid_codeblock_attr_with_help(
                                     format!("unknown attribute `{x}`"),
                                     |lint| {
-                                        lint.help(format!(
-                                            "there is an attribute with a similar name: `{flag}`"
-                                        ))
-                                        .help(help);
+                                        lint.help(help).help(
+                                            "this code block may be skipped during testing, \
+                                            because unknown attributes are treated as markers for \
+                                            code samples written in other programming languages, \
+                                            unless it is also explicitly marked as `rust`",
+                                        );
                                     },
                                 );
                             }
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index bce3f218908..dc4d45e592e 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -6,7 +6,7 @@ use std::rc::Rc;
 use std::sync::mpsc::{Receiver, channel};
 
 use rinja::Template;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
@@ -69,16 +69,16 @@ pub(crate) struct Context<'tcx> {
     /// `true`.
     pub(crate) include_sources: bool,
     /// Collection of all types with notable traits referenced in the current module.
-    pub(crate) types_with_notable_traits: FxHashSet<clean::Type>,
+    pub(crate) types_with_notable_traits: FxIndexSet<clean::Type>,
     /// Field used during rendering, to know if we're inside an inlined item.
     pub(crate) is_inside_inlined_module: bool,
 }
 
 // `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
 #[cfg(all(not(windows), target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Context<'_>, 160);
+rustc_data_structures::static_assert_size!(Context<'_>, 184);
 #[cfg(all(windows, target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Context<'_>, 168);
+rustc_data_structures::static_assert_size!(Context<'_>, 192);
 
 /// Shared mutable state used in [`Context`] and elsewhere.
 pub(crate) struct SharedContext<'tcx> {
@@ -90,7 +90,7 @@ pub(crate) struct SharedContext<'tcx> {
     /// creation of the context (contains info like the favicon and added html).
     pub(crate) layout: layout::Layout,
     /// The local file sources we've emitted and their respective url-paths.
-    pub(crate) local_sources: FxHashMap<PathBuf, String>,
+    pub(crate) local_sources: FxIndexMap<PathBuf, String>,
     /// Show the memory layout of types in the docs.
     pub(super) show_type_layout: bool,
     /// The base-URL of the issue tracker for when an item has been tagged with
@@ -567,7 +567,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             deref_id_map: Default::default(),
             shared: Rc::new(scx),
             include_sources,
-            types_with_notable_traits: FxHashSet::default(),
+            types_with_notable_traits: FxIndexSet::default(),
             is_inside_inlined_module: false,
         };
 
@@ -591,7 +591,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             id_map: IdMap::new(),
             shared: Rc::clone(&self.shared),
             include_sources: self.include_sources,
-            types_with_notable_traits: FxHashSet::default(),
+            types_with_notable_traits: FxIndexSet::default(),
             is_inside_inlined_module: self.is_inside_inlined_module,
         }
     }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 227df0c5f39..399730a01c8 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -47,7 +47,7 @@ use std::{fs, str};
 use rinja::Template;
 use rustc_attr::{ConstStability, DeprecatedSince, Deprecation, StabilityLevel, StableSince};
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::Mutability;
 use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_middle::ty::print::PrintTraitRefExt;
@@ -328,24 +328,24 @@ impl Ord for ItemEntry {
 
 #[derive(Debug)]
 struct AllTypes {
-    structs: FxHashSet<ItemEntry>,
-    enums: FxHashSet<ItemEntry>,
-    unions: FxHashSet<ItemEntry>,
-    primitives: FxHashSet<ItemEntry>,
-    traits: FxHashSet<ItemEntry>,
-    macros: FxHashSet<ItemEntry>,
-    functions: FxHashSet<ItemEntry>,
-    type_aliases: FxHashSet<ItemEntry>,
-    statics: FxHashSet<ItemEntry>,
-    constants: FxHashSet<ItemEntry>,
-    attribute_macros: FxHashSet<ItemEntry>,
-    derive_macros: FxHashSet<ItemEntry>,
-    trait_aliases: FxHashSet<ItemEntry>,
+    structs: FxIndexSet<ItemEntry>,
+    enums: FxIndexSet<ItemEntry>,
+    unions: FxIndexSet<ItemEntry>,
+    primitives: FxIndexSet<ItemEntry>,
+    traits: FxIndexSet<ItemEntry>,
+    macros: FxIndexSet<ItemEntry>,
+    functions: FxIndexSet<ItemEntry>,
+    type_aliases: FxIndexSet<ItemEntry>,
+    statics: FxIndexSet<ItemEntry>,
+    constants: FxIndexSet<ItemEntry>,
+    attribute_macros: FxIndexSet<ItemEntry>,
+    derive_macros: FxIndexSet<ItemEntry>,
+    trait_aliases: FxIndexSet<ItemEntry>,
 }
 
 impl AllTypes {
     fn new() -> AllTypes {
-        let new_set = |cap| FxHashSet::with_capacity_and_hasher(cap, Default::default());
+        let new_set = |cap| FxIndexSet::with_capacity_and_hasher(cap, Default::default());
         AllTypes {
             structs: new_set(100),
             enums: new_set(100),
@@ -437,7 +437,7 @@ impl AllTypes {
     }
 
     fn print(self, f: &mut Buffer) {
-        fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, kind: ItemSection) {
+        fn print_entries(f: &mut Buffer, e: &FxIndexSet<ItemEntry>, kind: ItemSection) {
             if !e.is_empty() {
                 let mut e: Vec<&ItemEntry> = e.iter().collect();
                 e.sort();
@@ -1151,7 +1151,7 @@ fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Con
 #[derive(Copy, Clone)]
 enum AssocItemLink<'a> {
     Anchor(Option<&'a str>),
-    GotoSource(ItemId, &'a FxHashSet<Symbol>),
+    GotoSource(ItemId, &'a FxIndexSet<Symbol>),
 }
 
 impl<'a> AssocItemLink<'a> {
@@ -1494,7 +1494,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
                 for it in &impl_.items {
                     if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind {
                         out.push_str("<div class=\"where\">    ");
-                        let empty_set = FxHashSet::default();
+                        let empty_set = FxIndexSet::default();
                         let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
                         assoc_type(
                             &mut out,
@@ -2526,7 +2526,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c
         })()
         .unwrap_or(DUMMY_SP);
 
-        let mut decoration_info = FxHashMap::default();
+        let mut decoration_info = FxIndexMap::default();
         decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]);
         decoration_info.insert("highlight", byte_ranges);
 
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index d120e7f36eb..3c96f873681 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -6,7 +6,7 @@ use std::rc::Rc;
 use itertools::Itertools;
 use rinja::Template;
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_hir as hir;
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::DefId;
@@ -436,16 +436,9 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
             }
 
             clean::ImportItem(ref import) => {
-                let stab_tags = if let Some(import_def_id) = import.source.did {
-                    // Just need an item with the correct def_id and attrs
-                    let import_item =
-                        clean::Item { item_id: import_def_id.into(), ..(*myitem).clone() };
-
-                    let stab_tags = Some(extra_info_tags(&import_item, item, tcx).to_string());
-                    stab_tags
-                } else {
-                    None
-                };
+                let stab_tags = import.source.did.map_or_else(String::new, |import_def_id| {
+                    extra_info_tags(tcx, myitem, item, Some(import_def_id)).to_string()
+                });
 
                 w.write_str(ITEM_TABLE_ROW_OPEN);
                 let id = match import.kind {
@@ -454,7 +447,6 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
                     }
                     clean::ImportKind::Glob => String::new(),
                 };
-                let stab_tags = stab_tags.unwrap_or_default();
                 let (stab_tags_before, stab_tags_after) = if stab_tags.is_empty() {
                     ("", "")
                 } else {
@@ -521,7 +513,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
                      {docs_before}{docs}{docs_after}",
                     name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
                     visibility_and_hidden = visibility_and_hidden,
-                    stab_tags = extra_info_tags(myitem, item, tcx),
+                    stab_tags = extra_info_tags(tcx, myitem, item, None),
                     class = myitem.type_(),
                     unsafety_flag = unsafety_flag,
                     href = item_path(myitem.type_(), myitem.name.unwrap().as_str()),
@@ -544,9 +536,10 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
 /// Render the stability, deprecation and portability tags that are displayed in the item's summary
 /// at the module level.
 fn extra_info_tags<'a, 'tcx: 'a>(
+    tcx: TyCtxt<'tcx>,
     item: &'a clean::Item,
     parent: &'a clean::Item,
-    tcx: TyCtxt<'tcx>,
+    import_def_id: Option<DefId>,
 ) -> impl fmt::Display + 'a + Captures<'tcx> {
     display_fn(move |f| {
         fn tag_html<'a>(
@@ -564,18 +557,18 @@ fn extra_info_tags<'a, 'tcx: 'a>(
         }
 
         // The trailing space after each tag is to space it properly against the rest of the docs.
-        if let Some(depr) = &item.deprecation(tcx) {
+        let deprecation = import_def_id
+            .map_or_else(|| item.deprecation(tcx), |import_did| tcx.lookup_deprecation(import_did));
+        if let Some(depr) = deprecation {
             let message = if depr.is_in_effect() { "Deprecated" } else { "Deprecation planned" };
             write!(f, "{}", tag_html("deprecated", "", message))?;
         }
 
         // The "rustc_private" crates are permanently unstable so it makes no sense
         // to render "unstable" everywhere.
-        if item
-            .stability(tcx)
-            .as_ref()
-            .is_some_and(|s| s.is_unstable() && s.feature != sym::rustc_private)
-        {
+        let stability = import_def_id
+            .map_or_else(|| item.stability(tcx), |import_did| tcx.lookup_stability(import_did));
+        if stability.is_some_and(|s| s.is_unstable() && s.feature != sym::rustc_private) {
             write!(f, "{}", tag_html("unstable", "", "Experimental"))?;
         }
 
@@ -939,7 +932,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
 
     let cloned_shared = Rc::clone(&cx.shared);
     let cache = &cloned_shared.cache;
-    let mut extern_crates = FxHashSet::default();
+    let mut extern_crates = FxIndexSet::default();
 
     if !t.is_object_safe(cx.tcx()) {
         write_section_heading(
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 660ca3b2594..c958458b662 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -774,7 +774,7 @@ pub(crate) fn get_function_type_for_search<'tcx>(
 fn get_index_type(
     clean_type: &clean::Type,
     generics: Vec<RenderType>,
-    rgen: &mut FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)>,
+    rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
 ) -> RenderType {
     RenderType {
         id: get_index_type_id(clean_type, rgen),
@@ -785,7 +785,7 @@ fn get_index_type(
 
 fn get_index_type_id(
     clean_type: &clean::Type,
-    rgen: &mut FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)>,
+    rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
 ) -> Option<RenderTypeId> {
     use rustc_hir::def::{DefKind, Res};
     match *clean_type {
@@ -854,7 +854,7 @@ fn simplify_fn_type<'a, 'tcx>(
     tcx: TyCtxt<'tcx>,
     recurse: usize,
     res: &mut Vec<RenderType>,
-    rgen: &mut FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)>,
+    rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
     is_return: bool,
     cache: &Cache,
 ) {
@@ -1198,7 +1198,7 @@ fn simplify_fn_constraint<'a, 'tcx>(
     tcx: TyCtxt<'tcx>,
     recurse: usize,
     res: &mut Vec<(RenderTypeId, Vec<RenderType>)>,
-    rgen: &mut FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)>,
+    rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
     is_return: bool,
     cache: &Cache,
 ) {
@@ -1285,7 +1285,7 @@ fn get_fn_inputs_and_outputs<'tcx>(
 ) -> (Vec<RenderType>, Vec<RenderType>, Vec<Vec<RenderType>>) {
     let decl = &func.decl;
 
-    let mut rgen: FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
+    let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
 
     let combined_generics;
     let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_or_trait_generics {
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index 2143f1ff236..b314b060368 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -1,6 +1,6 @@
 use std::path::{Path, PathBuf};
 
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, Visitor};
@@ -44,7 +44,7 @@ pub(crate) fn collect_spans_and_sources(
     src_root: &Path,
     include_sources: bool,
     generate_link_to_definition: bool,
-) -> (FxHashMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) {
+) -> (FxIndexMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) {
     let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() };
 
     if include_sources {
@@ -243,7 +243,6 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
             | ItemKind::ExternCrate(_)
             | ItemKind::ForeignMod { .. }
             | ItemKind::GlobalAsm(_)
-            | ItemKind::OpaqueTy(_)
             // We already have "visit_mod" above so no need to check it here.
             | ItemKind::Mod(_) => {}
         }
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index af94b1042c0..12b63460056 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -28,7 +28,7 @@ use indexmap::IndexMap;
 use itertools::Itertools;
 use regex::Regex;
 use rustc_data_structures::flock;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_span::Symbol;
@@ -505,8 +505,8 @@ createSrcSidebar();",
 struct Hierarchy {
     parent: Weak<Self>,
     elem: OsString,
-    children: RefCell<FxHashMap<OsString, Rc<Self>>>,
-    elems: RefCell<FxHashSet<OsString>>,
+    children: RefCell<FxIndexMap<OsString, Rc<Self>>>,
+    elems: RefCell<FxIndexSet<OsString>>,
 }
 
 impl Hierarchy {
@@ -961,8 +961,8 @@ impl Serialize for AliasSerializableImpl {
 fn get_path_parts<T: CciPart>(
     dst: &Path,
     crates_info: &[CrateInfo],
-) -> FxHashMap<PathBuf, Vec<String>> {
-    let mut templates: FxHashMap<PathBuf, Vec<String>> = FxHashMap::default();
+) -> FxIndexMap<PathBuf, Vec<String>> {
+    let mut templates: FxIndexMap<PathBuf, Vec<String>> = FxIndexMap::default();
     crates_info
         .iter()
         .map(|crate_info| T::from_crate_info(crate_info).parts.iter())
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 7be9cc0b885..f4a0ef01c25 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -6,7 +6,7 @@ use std::rc::Rc;
 use std::{fmt, fs};
 
 use rinja::Template;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
@@ -39,15 +39,15 @@ pub(crate) fn collect_local_sources<'tcx>(
     tcx: TyCtxt<'tcx>,
     src_root: &Path,
     krate: &clean::Crate,
-) -> FxHashMap<PathBuf, String> {
-    let mut lsc = LocalSourcesCollector { tcx, local_sources: FxHashMap::default(), src_root };
+) -> FxIndexMap<PathBuf, String> {
+    let mut lsc = LocalSourcesCollector { tcx, local_sources: FxIndexMap::default(), src_root };
     lsc.visit_crate(krate);
     lsc.local_sources
 }
 
 struct LocalSourcesCollector<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    local_sources: FxHashMap<PathBuf, String>,
+    local_sources: FxIndexMap<PathBuf, String>,
     src_root: &'a Path,
 }
 
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 40391b1b4df..5f6f3c65c7f 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -182,17 +182,18 @@ h1, h2, h3, h4 {
 		"main-heading-breadcrumbs main-heading-breadcrumbs"
 		"main-heading-h1 main-heading-toolbar"
 		"main-heading-sub-heading main-heading-toolbar";
-	grid-template-columns: 1fr max-content;
-	grid-template-rows: 25px min-content min-content;
+	grid-template-columns: minmax(105px, 1fr) minmax(0, max-content);
+	grid-template-rows: minmax(25px, min-content) min-content min-content;
 	padding-bottom: 6px;
 	margin-bottom: 11px;
 }
 .rustdoc-breadcrumbs {
 	grid-area: main-heading-breadcrumbs;
-	height: 25px;
 	line-height: 1.25;
 	display: flex;
+	flex-wrap: wrap;
 	align-items: end;
+	padding-top: 5px;
 }
 .rustdoc-breadcrumbs a {
 	padding: 4px 0;
@@ -928,6 +929,7 @@ rustdoc-toolbar {
 	display: flex;
 	flex-direction: row;
 	flex-wrap: nowrap;
+	min-height: 60px;
 }
 
 .docblock code, .docblock-short code,
@@ -958,6 +960,16 @@ pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers {
 	display: inline-block;
 }
 
+.docblock li {
+	margin-bottom: .4em;
+}
+.docblock li p:not(:last-child) {
+	/* This margin is voluntarily smaller than `.docblock li` to keep the visual
+	   list element items separated while also having a visual separation (although
+	   smaller) for paragraphs. */
+	margin-bottom: .3em;
+}
+
 /* "where ..." clauses with block display are also smaller */
 div.where {
 	white-space: pre-wrap;
@@ -1104,17 +1116,17 @@ table,
 .search-results-title + .sub-heading {
 	color: var(--main-color);
 	display: flex;
-	align-items: center;
+	align-items: baseline;
+	white-space: nowrap;
 }
 #crate-search-div {
 	/* ensures that 100% in properties of #crate-search-div:after
 	are relative to the size of this div */
 	position: relative;
 	/* allows this div (and with it the <select>-element "#crate-search") to be shrunk */
-	min-width: 5em;
+	min-width: 0;
 }
 #crate-search {
-	min-width: 115px;
 	padding: 0 23px 0 4px;
 	/* prevents the <select> from overflowing the containing div in case it's shrunk */
 	max-width: 100%;
@@ -1825,6 +1837,7 @@ a.tooltip:hover::after {
 	margin-left: var(--button-left-margin);
 	display: flex;
 	line-height: 1.25;
+	min-width: 14px;
 }
 #sidebar-button {
 	display: none;
@@ -1861,6 +1874,9 @@ a.tooltip:hover::after {
 	width: 80px;
 	border-radius: var(--toolbar-button-border-radius);
 }
+#settings-menu > a, #help-button > a {
+	min-width: 0;
+}
 #sidebar-button > a {
 	background-color: var(--button-background-color);
 	border-color: var(--border-color);
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 0d556e0a682..984b0877d8d 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -1828,11 +1828,15 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         return;
     }
     but.onclick = () => {
-        const path = [];
-        onEachLazy(document.querySelectorAll(".rustdoc-breadcrumbs a"), a => {
-            path.push(a.textContent);
-        });
-        path.push(document.querySelector("title").textContent.split(" ")[0]);
+        // Most page titles are '<Item> in <path::to::module> - Rust', except
+        // modules (which don't have the first part) and keywords/primitives
+        // (which don't have a module path)
+        const title = document.querySelector("title").textContent.replace(" - Rust", "");
+        const [item, module] = title.split(" in ");
+        const path = [item];
+        if (module !== undefined) {
+            path.unshift(module);
+        }
 
         copyContentToClipboard(path.join("::"));
         copyButtonAnimation(but);
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 2be415e2e0e..10fc0ea9990 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -20,7 +20,6 @@
 #![warn(rustc::internal)]
 #![allow(clippy::collapsible_if, clippy::collapsible_else_if)]
 #![allow(rustc::diagnostic_outside_of_impl)]
-#![allow(rustc::potential_query_instability)]
 #![allow(rustc::untranslatable_diagnostic)]
 
 extern crate thin_vec;
@@ -99,7 +98,7 @@ use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL;
 /// Commas between elements are required (even if the expression is a block).
 macro_rules! map {
     ($( $key: expr => $val: expr ),* $(,)*) => {{
-        let mut map = ::rustc_data_structures::fx::FxHashMap::default();
+        let mut map = ::rustc_data_structures::fx::FxIndexMap::default();
         $( map.insert($key, $val); )*
         map
     }}
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index e95e8762b1d..2eb0e32b831 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -9,7 +9,7 @@ use std::ops::Range;
 
 use pulldown_cmark::LinkType;
 use rustc_ast::util::comments::may_have_doc_links;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{Applicability, Diag, DiagMessage};
 use rustc_hir::def::Namespace::*;
@@ -110,7 +110,6 @@ impl Res {
 
         let prefix = match kind {
             DefKind::Fn | DefKind::AssocFn => return Suggestion::Function,
-            DefKind::Field => return Suggestion::RemoveDisambiguator,
             DefKind::Macro(MacroKind::Bang) => return Suggestion::Macro,
 
             DefKind::Macro(MacroKind::Derive) => "derive",
@@ -123,6 +122,8 @@ impl Res {
                 "const"
             }
             DefKind::Static { .. } => "static",
+            DefKind::Field => "field",
+            DefKind::Variant | DefKind::Ctor(..) => "variant",
             // Now handle things that don't have a specific disambiguator
             _ => match kind
                 .ns()
@@ -415,6 +416,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         &mut self,
         path_str: &'path str,
         ns: Namespace,
+        disambiguator: Option<Disambiguator>,
         item_id: DefId,
         module_id: DefId,
     ) -> Result<Vec<(Res, Option<DefId>)>, UnresolvedPath<'path>> {
@@ -454,7 +456,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         match resolve_primitive(path_root, TypeNS)
             .or_else(|| self.resolve_path(path_root, TypeNS, item_id, module_id))
             .map(|ty_res| {
-                self.resolve_associated_item(ty_res, item_name, ns, module_id)
+                self.resolve_associated_item(ty_res, item_name, ns, disambiguator, module_id)
                     .into_iter()
                     .map(|(res, def_id)| (res, Some(def_id)))
                     .collect::<Vec<_>>()
@@ -557,6 +559,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         root_res: Res,
         item_name: Symbol,
         ns: Namespace,
+        disambiguator: Option<Disambiguator>,
         module_id: DefId,
     ) -> Vec<(Res, DefId)> {
         let tcx = self.cx.tcx;
@@ -583,7 +586,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 // FIXME: if the associated item is defined directly on the type alias,
                 // it will show up on its documentation page, we should link there instead.
                 let Some(res) = self.def_id_to_res(did) else { return Vec::new() };
-                self.resolve_associated_item(res, item_name, ns, module_id)
+                self.resolve_associated_item(res, item_name, ns, disambiguator, module_id)
             }
             Res::Def(
                 def_kind @ (DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::ForeignTy),
@@ -604,6 +607,39 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                     }
                 }
 
+                let search_for_field = || {
+                    let (DefKind::Struct | DefKind::Union) = def_kind else { return vec![] };
+                    debug!("looking for fields named {item_name} for {did:?}");
+                    // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?)
+                    // NOTE: it's different from variant_field because it only resolves struct fields,
+                    // not variant fields (2 path segments, not 3).
+                    //
+                    // We need to handle struct (and union) fields in this code because
+                    // syntactically their paths are identical to associated item paths:
+                    // `module::Type::field` and `module::Type::Assoc`.
+                    //
+                    // On the other hand, variant fields can't be mistaken for associated
+                    // items because they look like this: `module::Type::Variant::field`.
+                    //
+                    // Variants themselves don't need to be handled here, even though
+                    // they also look like associated items (`module::Type::Variant`),
+                    // because they are real Rust syntax (unlike the intra-doc links
+                    // field syntax) and are handled by the compiler's resolver.
+                    let ty::Adt(def, _) = tcx.type_of(did).instantiate_identity().kind() else {
+                        unreachable!()
+                    };
+                    def.non_enum_variant()
+                        .fields
+                        .iter()
+                        .filter(|field| field.name == item_name)
+                        .map(|field| (root_res, field.did))
+                        .collect::<Vec<_>>()
+                };
+
+                if let Some(Disambiguator::Kind(DefKind::Field)) = disambiguator {
+                    return search_for_field();
+                }
+
                 // Checks if item_name belongs to `impl SomeItem`
                 let mut assoc_items: Vec<_> = tcx
                     .inherent_impls(did)
@@ -646,32 +682,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 if ns != Namespace::ValueNS {
                     return Vec::new();
                 }
-                debug!("looking for fields named {item_name} for {did:?}");
-                // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?)
-                // NOTE: it's different from variant_field because it only resolves struct fields,
-                // not variant fields (2 path segments, not 3).
-                //
-                // We need to handle struct (and union) fields in this code because
-                // syntactically their paths are identical to associated item paths:
-                // `module::Type::field` and `module::Type::Assoc`.
-                //
-                // On the other hand, variant fields can't be mistaken for associated
-                // items because they look like this: `module::Type::Variant::field`.
-                //
-                // Variants themselves don't need to be handled here, even though
-                // they also look like associated items (`module::Type::Variant`),
-                // because they are real Rust syntax (unlike the intra-doc links
-                // field syntax) and are handled by the compiler's resolver.
-                let def = match tcx.type_of(did).instantiate_identity().kind() {
-                    ty::Adt(def, _) if !def.is_enum() => def,
-                    _ => return Vec::new(),
-                };
-                def.non_enum_variant()
-                    .fields
-                    .iter()
-                    .filter(|field| field.name == item_name)
-                    .map(|field| (root_res, field.did))
-                    .collect::<Vec<_>>()
+
+                search_for_field()
             }
             Res::Def(DefKind::Trait, did) => filter_assoc_items_by_name_and_namespace(
                 tcx,
@@ -766,9 +778,9 @@ fn trait_impls_for<'a>(
     cx: &mut DocContext<'a>,
     ty: Ty<'a>,
     module: DefId,
-) -> FxHashSet<(DefId, DefId)> {
+) -> FxIndexSet<(DefId, DefId)> {
     let tcx = cx.tcx;
-    let mut impls = FxHashSet::default();
+    let mut impls = FxIndexSet::default();
 
     for &trait_ in tcx.doc_link_traits_in_scope(module) {
         tcx.for_each_relevant_impl(trait_, ty, |impl_| {
@@ -1297,7 +1309,7 @@ impl LinkCollector<'_, '_> {
 
         match disambiguator.map(Disambiguator::ns) {
             Some(expected_ns) => {
-                match self.resolve(path_str, expected_ns, item_id, module_id) {
+                match self.resolve(path_str, expected_ns, disambiguator, item_id, module_id) {
                     Ok(candidates) => candidates,
                     Err(err) => {
                         // We only looked in one namespace. Try to give a better error if possible.
@@ -1306,8 +1318,9 @@ impl LinkCollector<'_, '_> {
                         let mut err = ResolutionFailure::NotResolved(err);
                         for other_ns in [TypeNS, ValueNS, MacroNS] {
                             if other_ns != expected_ns {
-                                if let Ok(&[res, ..]) =
-                                    self.resolve(path_str, other_ns, item_id, module_id).as_deref()
+                                if let Ok(&[res, ..]) = self
+                                    .resolve(path_str, other_ns, None, item_id, module_id)
+                                    .as_deref()
                                 {
                                     err = ResolutionFailure::WrongNamespace {
                                         res: full_res(self.cx.tcx, res),
@@ -1327,7 +1340,7 @@ impl LinkCollector<'_, '_> {
             None => {
                 // Try everything!
                 let mut candidate = |ns| {
-                    self.resolve(path_str, ns, item_id, module_id)
+                    self.resolve(path_str, ns, None, item_id, module_id)
                         .map_err(ResolutionFailure::NotResolved)
                 };
 
@@ -1531,6 +1544,8 @@ impl Disambiguator {
                 }),
                 "function" | "fn" | "method" => Kind(DefKind::Fn),
                 "derive" => Kind(DefKind::Macro(MacroKind::Derive)),
+                "field" => Kind(DefKind::Field),
+                "variant" => Kind(DefKind::Variant),
                 "type" => NS(Namespace::TypeNS),
                 "value" => NS(Namespace::ValueNS),
                 "macro" => NS(Namespace::MacroNS),
@@ -1569,6 +1584,8 @@ impl Disambiguator {
     fn ns(self) -> Namespace {
         match self {
             Self::Namespace(n) => n,
+            // for purposes of link resolution, fields are in the value namespace.
+            Self::Kind(DefKind::Field) => ValueNS,
             Self::Kind(k) => {
                 k.ns().expect("only DefKinds with a valid namespace can be disambiguators")
             }
@@ -1603,8 +1620,6 @@ enum Suggestion {
     Function,
     /// `m!`
     Macro,
-    /// `foo` without any disambiguator
-    RemoveDisambiguator,
 }
 
 impl Suggestion {
@@ -1613,7 +1628,6 @@ impl Suggestion {
             Self::Prefix(x) => format!("prefix with `{x}@`").into(),
             Self::Function => "add parentheses".into(),
             Self::Macro => "add an exclamation mark".into(),
-            Self::RemoveDisambiguator => "remove the disambiguator".into(),
         }
     }
 
@@ -1623,13 +1637,11 @@ impl Suggestion {
             Self::Prefix(prefix) => format!("{prefix}@{path_str}"),
             Self::Function => format!("{path_str}()"),
             Self::Macro => format!("{path_str}!"),
-            Self::RemoveDisambiguator => path_str.into(),
         }
     }
 
     fn as_help_span(
         &self,
-        path_str: &str,
         ori_link: &str,
         sp: rustc_span::Span,
     ) -> Vec<(rustc_span::Span, String)> {
@@ -1677,7 +1689,6 @@ impl Suggestion {
                 }
                 sugg
             }
-            Self::RemoveDisambiguator => vec![(sp, path_str.into())],
         }
     }
 }
@@ -1826,7 +1837,9 @@ fn resolution_failure(
                         };
                         name = start;
                         for ns in [TypeNS, ValueNS, MacroNS] {
-                            if let Ok(v_res) = collector.resolve(start, ns, item_id, module_id) {
+                            if let Ok(v_res) =
+                                collector.resolve(start, ns, None, item_id, module_id)
+                            {
                                 debug!("found partial_res={v_res:?}");
                                 if let Some(&res) = v_res.first() {
                                     *partial_res = Some(full_res(tcx, res));
@@ -1983,11 +1996,22 @@ fn resolution_failure(
                             &diag_info,
                         );
 
-                        format!(
-                            "this link resolves to {}, which is not in the {} namespace",
-                            item(res),
-                            expected_ns.descr()
-                        )
+                        if let Some(disambiguator) = disambiguator
+                            && !matches!(disambiguator, Disambiguator::Namespace(..))
+                        {
+                            format!(
+                                "this link resolves to {}, which is not {} {}",
+                                item(res),
+                                disambiguator.article(),
+                                disambiguator.descr()
+                            )
+                        } else {
+                            format!(
+                                "this link resolves to {}, which is not in the {} namespace",
+                                item(res),
+                                expected_ns.descr()
+                            )
+                        }
                     }
                 };
                 if let Some(span) = sp {
@@ -2164,7 +2188,7 @@ fn suggest_disambiguator(
     };
 
     if let (Some(sp), Some(ori_link)) = (sp, ori_link) {
-        let mut spans = suggestion.as_help_span(path_str, ori_link, sp);
+        let mut spans = suggestion.as_help_span(ori_link, sp);
         if spans.len() > 1 {
             diag.multipart_suggestion(help, spans, Applicability::MaybeIncorrect);
         } else {
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index b307e84e42e..d1a1f0df3e7 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -219,7 +219,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
         panic!("collect-trait-impls can't run");
     };
 
-    krate.external_traits.extend(cx.external_traits.drain());
+    krate.external_traits.extend(cx.external_traits.drain(..));
 
     krate
 }
diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs
index 848e70a7bdb..e0dc5b4c513 100644
--- a/src/librustdoc/passes/lint/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs
@@ -145,7 +145,7 @@ struct BufferEmitter {
 }
 
 impl Translate for BufferEmitter {
-    fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
+    fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> {
         None
     }
 
@@ -169,7 +169,7 @@ impl Emitter for BufferEmitter {
         }
     }
 
-    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
+    fn source_map(&self) -> Option<&SourceMap> {
         None
     }
 }
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index b1dc766049d..f5b78023721 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -23,6 +23,9 @@ pub(crate) use self::strip_priv_imports::STRIP_PRIV_IMPORTS;
 mod propagate_doc_cfg;
 pub(crate) use self::propagate_doc_cfg::PROPAGATE_DOC_CFG;
 
+mod propagate_stability;
+pub(crate) use self::propagate_stability::PROPAGATE_STABILITY;
+
 pub(crate) mod collect_intra_doc_links;
 pub(crate) use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS;
 
@@ -75,6 +78,7 @@ pub(crate) const PASSES: &[Pass] = &[
     STRIP_PRIVATE,
     STRIP_PRIV_IMPORTS,
     PROPAGATE_DOC_CFG,
+    PROPAGATE_STABILITY,
     COLLECT_INTRA_DOC_LINKS,
     COLLECT_TRAIT_IMPLS,
     CALCULATE_DOC_COVERAGE,
@@ -91,6 +95,7 @@ pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[
     ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate),
     ConditionalPass::always(COLLECT_INTRA_DOC_LINKS),
     ConditionalPass::always(PROPAGATE_DOC_CFG),
+    ConditionalPass::always(PROPAGATE_STABILITY),
     ConditionalPass::always(RUN_LINTS),
 ];
 
diff --git a/src/librustdoc/passes/propagate_stability.rs b/src/librustdoc/passes/propagate_stability.rs
new file mode 100644
index 00000000000..f51e993bfa5
--- /dev/null
+++ b/src/librustdoc/passes/propagate_stability.rs
@@ -0,0 +1,72 @@
+//! Propagates stability to child items.
+//!
+//! The purpose of this pass is to make items whose parents are "more unstable"
+//! than the item itself inherit the parent's stability.
+//! For example, [`core::error::Error`] is marked as stable since 1.0.0, but the
+//! [`core::error`] module is marked as stable since 1.81.0, so we want to show
+//! [`core::error::Error`] as stable since 1.81.0 as well.
+
+use rustc_attr::{Stability, StabilityLevel};
+use rustc_hir::def_id::CRATE_DEF_ID;
+
+use crate::clean::{Crate, Item, ItemId};
+use crate::core::DocContext;
+use crate::fold::DocFolder;
+use crate::passes::Pass;
+
+pub(crate) const PROPAGATE_STABILITY: Pass = Pass {
+    name: "propagate-stability",
+    run: propagate_stability,
+    description: "propagates stability to child items",
+};
+
+pub(crate) fn propagate_stability(cr: Crate, cx: &mut DocContext<'_>) -> Crate {
+    let crate_stability = cx.tcx.lookup_stability(CRATE_DEF_ID);
+    StabilityPropagator { parent_stability: crate_stability, cx }.fold_crate(cr)
+}
+
+struct StabilityPropagator<'a, 'tcx> {
+    parent_stability: Option<Stability>,
+    cx: &'a mut DocContext<'tcx>,
+}
+
+impl<'a, 'tcx> DocFolder for StabilityPropagator<'a, 'tcx> {
+    fn fold_item(&mut self, mut item: Item) -> Option<Item> {
+        let parent_stability = self.parent_stability;
+
+        let stability = match item.item_id {
+            ItemId::DefId(def_id) => {
+                let own_stability = self.cx.tcx.lookup_stability(def_id);
+
+                // If any of the item's parents was stabilized later or is still unstable,
+                // then use the parent's stability instead.
+                if let Some(own_stab) = own_stability
+                    && let StabilityLevel::Stable {
+                        since: own_since,
+                        allowed_through_unstable_modules: false,
+                    } = own_stab.level
+                    && let Some(parent_stab) = parent_stability
+                    && (parent_stab.is_unstable()
+                        || parent_stab
+                            .stable_since()
+                            .is_some_and(|parent_since| parent_since > own_since))
+                {
+                    parent_stability
+                } else {
+                    own_stability
+                }
+            }
+            ItemId::Auto { .. } | ItemId::Blanket { .. } => {
+                // For now, we do now show stability for synthesized impls.
+                None
+            }
+        };
+
+        item.inner.stability = stability;
+        self.parent_stability = stability;
+        let item = self.fold_item_recur(item);
+        self.parent_stability = parent_stability;
+
+        Some(item)
+    }
+}
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index 9d4d203562c..a59c43bfbf9 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -3,7 +3,7 @@
 use std::fs;
 use std::path::PathBuf;
 
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::DiagCtxtHandle;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{self as hir};
@@ -102,8 +102,8 @@ pub(crate) struct CallData {
     pub(crate) is_bin: bool,
 }
 
-pub(crate) type FnCallLocations = FxHashMap<PathBuf, CallData>;
-pub(crate) type AllCallLocations = FxHashMap<DefPathHash, FnCallLocations>;
+pub(crate) type FnCallLocations = FxIndexMap<PathBuf, CallData>;
+pub(crate) type AllCallLocations = FxIndexMap<DefPathHash, FnCallLocations>;
 
 /// Visitor for traversing a crate and finding instances of function calls.
 struct FindCalls<'a, 'tcx> {
@@ -293,7 +293,7 @@ pub(crate) fn run(
         debug!("Scrape examples target_crates: {target_crates:?}");
 
         // Run call-finder on all items
-        let mut calls = FxHashMap::default();
+        let mut calls = FxIndexMap::default();
         let mut finder =
             FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates, bin_crate };
         tcx.hir().visit_all_item_likes_in_crate(&mut finder);
@@ -332,7 +332,7 @@ pub(crate) fn load_call_locations(
     with_examples: Vec<String>,
     dcx: DiagCtxtHandle<'_>,
 ) -> AllCallLocations {
-    let mut all_calls: AllCallLocations = FxHashMap::default();
+    let mut all_calls: AllCallLocations = FxIndexMap::default();
     for path in with_examples {
         let bytes = match fs::read(&path) {
             Ok(bytes) => bytes,
diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs
index 409728a8e86..2c00bb7e132 100644
--- a/src/librustdoc/theme.rs
+++ b/src/librustdoc/theme.rs
@@ -1,10 +1,9 @@
-use std::collections::hash_map::Entry;
 use std::fs;
 use std::iter::Peekable;
 use std::path::Path;
 use std::str::Chars;
 
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxIndexMap, IndexEntry};
 use rustc_errors::DiagCtxtHandle;
 
 #[cfg(test)]
@@ -12,8 +11,8 @@ mod tests;
 
 #[derive(Debug)]
 pub(crate) struct CssPath {
-    pub(crate) rules: FxHashMap<String, String>,
-    pub(crate) children: FxHashMap<String, CssPath>,
+    pub(crate) rules: FxIndexMap<String, String>,
+    pub(crate) children: FxIndexMap<String, CssPath>,
 }
 
 /// When encountering a `"` or a `'`, returns the whole string, including the quote characters.
@@ -120,10 +119,10 @@ fn parse_rules(
     content: &str,
     selector: String,
     iter: &mut Peekable<Chars<'_>>,
-    paths: &mut FxHashMap<String, CssPath>,
+    paths: &mut FxIndexMap<String, CssPath>,
 ) -> Result<(), String> {
-    let mut rules = FxHashMap::default();
-    let mut children = FxHashMap::default();
+    let mut rules = FxIndexMap::default();
+    let mut children = FxIndexMap::default();
 
     loop {
         // If the parent isn't a "normal" CSS selector, we only expect sub-selectors and not CSS
@@ -146,10 +145,10 @@ fn parse_rules(
             return Err(format!("Found empty value for rule `{rule}` in selector `{selector}`"));
         }
         match rules.entry(rule) {
-            Entry::Occupied(mut o) => {
+            IndexEntry::Occupied(mut o) => {
                 *o.get_mut() = value;
             }
-            Entry::Vacant(v) => {
+            IndexEntry::Vacant(v) => {
                 v.insert(value);
             }
         }
@@ -159,7 +158,7 @@ fn parse_rules(
     }
 
     match paths.entry(selector) {
-        Entry::Occupied(mut o) => {
+        IndexEntry::Occupied(mut o) => {
             let v = o.get_mut();
             for (key, value) in rules.into_iter() {
                 v.rules.insert(key, value);
@@ -168,7 +167,7 @@ fn parse_rules(
                 v.children.insert(sel, child);
             }
         }
-        Entry::Vacant(v) => {
+        IndexEntry::Vacant(v) => {
             v.insert(CssPath { rules, children });
         }
     }
@@ -178,7 +177,7 @@ fn parse_rules(
 pub(crate) fn parse_selectors(
     content: &str,
     iter: &mut Peekable<Chars<'_>>,
-    paths: &mut FxHashMap<String, CssPath>,
+    paths: &mut FxIndexMap<String, CssPath>,
 ) -> Result<(), String> {
     let mut selector = String::new();
 
@@ -202,17 +201,17 @@ pub(crate) fn parse_selectors(
 
 /// The entry point to parse the CSS rules. Every time we encounter a `{`, we then parse the rules
 /// inside it.
-pub(crate) fn load_css_paths(content: &str) -> Result<FxHashMap<String, CssPath>, String> {
+pub(crate) fn load_css_paths(content: &str) -> Result<FxIndexMap<String, CssPath>, String> {
     let mut iter = content.chars().peekable();
-    let mut paths = FxHashMap::default();
+    let mut paths = FxIndexMap::default();
 
     parse_selectors(content, &mut iter, &mut paths)?;
     Ok(paths)
 }
 
 pub(crate) fn get_differences(
-    origin: &FxHashMap<String, CssPath>,
-    against: &FxHashMap<String, CssPath>,
+    origin: &FxIndexMap<String, CssPath>,
+    against: &FxIndexMap<String, CssPath>,
     v: &mut Vec<String>,
 ) {
     for (selector, entry) in origin.iter() {
@@ -235,7 +234,7 @@ pub(crate) fn get_differences(
 
 pub(crate) fn test_theme_against<P: AsRef<Path>>(
     f: &P,
-    origin: &FxHashMap<String, CssPath>,
+    origin: &FxIndexMap<String, CssPath>,
     dcx: DiagCtxtHandle<'_>,
 ) -> (bool, Vec<String>) {
     let against = match fs::read_to_string(f)
diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs
index fbc18176ed8..bfa285c57fa 100644
--- a/src/librustdoc/visit.rs
+++ b/src/librustdoc/visit.rs
@@ -1,11 +1,17 @@
 use crate::clean::*;
 
+/// Allows a type to traverse the cleaned ast of a crate.
+///
+/// Note that like [`rustc_ast::visit::Visitor`], but
+/// unlike [`rustc_lint::EarlyLintPass`], if you override a
+/// `visit_*` method, you will need to manually recurse into
+/// its contents.
 pub(crate) trait DocVisitor<'a>: Sized {
     fn visit_item(&mut self, item: &'a Item) {
         self.visit_item_recur(item)
     }
 
-    /// don't override!
+    /// Don't override!
     fn visit_inner_recur(&mut self, kind: &'a ItemKind) {
         match kind {
             StrippedItem(..) => unreachable!(),
@@ -46,7 +52,7 @@ pub(crate) trait DocVisitor<'a>: Sized {
         }
     }
 
-    /// don't override!
+    /// Don't override!
     fn visit_item_recur(&mut self, item: &'a Item) {
         match &item.kind {
             StrippedItem(i) => self.visit_inner_recur(&*i),
@@ -58,6 +64,7 @@ pub(crate) trait DocVisitor<'a>: Sized {
         m.items.iter().for_each(|i| self.visit_item(i))
     }
 
+    /// This is the main entrypoint of [`DocVisitor`].
     fn visit_crate(&mut self, c: &'a Crate) {
         self.visit_item(&c.module);
 
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 2cf703f57c0..f789aca7378 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -164,7 +164,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     .unwrap_or(&[])
                     .iter()
                     .filter_map(|attr| {
-                        Cfg::parse(attr.meta_item()?)
+                        Cfg::parse(attr)
                             .map_err(|e| self.cx.sess().dcx().span_err(e.span, e.msg))
                             .ok()
                     })
@@ -505,21 +505,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             | hir::ItemKind::Struct(..)
             | hir::ItemKind::Union(..)
             | hir::ItemKind::TyAlias(..)
-            | hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-                origin: hir::OpaqueTyOrigin::TyAlias { .. },
-                ..
-            })
             | hir::ItemKind::Static(..)
             | hir::ItemKind::Trait(..)
             | hir::ItemKind::TraitAlias(..) => {
                 self.add_to_current_mod(item, renamed, import_id);
             }
-            hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-                origin: hir::OpaqueTyOrigin::AsyncFn(_) | hir::OpaqueTyOrigin::FnReturn(_),
-                ..
-            }) => {
-                // return-position impl traits are never nameable, and should never be documented.
-            }
             hir::ItemKind::Const(..) => {
                 // Underscore constants do not correspond to a nameable item and
                 // so are never useful in documentation.
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 56997739365e8132cc817e00899480746c09d7d
+Subproject dd46457da782554454106d48ecd4f6b4c2f9af7
diff --git a/src/tools/build_helper/src/ci.rs b/src/tools/build_helper/src/ci.rs
index 6d79c7c83ad..60f319129a0 100644
--- a/src/tools/build_helper/src/ci.rs
+++ b/src/tools/build_helper/src/ci.rs
@@ -19,6 +19,15 @@ impl CiEnv {
     pub fn is_ci() -> bool {
         Self::current() != CiEnv::None
     }
+
+    /// Checks if running in rust-lang/rust managed CI job.
+    pub fn is_rust_lang_managed_ci_job() -> bool {
+        Self::is_ci()
+            // If both are present, we can assume it's an upstream CI job
+            // as they are always set unconditionally.
+            && std::env::var_os("CI_JOB_NAME").is_some()
+            && std::env::var_os("TOOLSTATE_REPO").is_some()
+    }
 }
 
 pub mod gha {
diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs
index 10c5476cd8f..1e28d552fe6 100644
--- a/src/tools/build_helper/src/git.rs
+++ b/src/tools/build_helper/src/git.rs
@@ -196,67 +196,3 @@ pub fn get_git_untracked_files(
         .collect();
     Ok(Some(files))
 }
-
-/// Print a warning if the branch returned from `updated_master_branch` is old
-///
-/// For certain configurations of git repository, this remote will not be
-/// updated when running `git pull`.
-///
-/// This can result in formatting thousands of files instead of a dozen,
-/// so we should warn the user something is wrong.
-pub fn warn_old_master_branch(config: &GitConfig<'_>, git_dir: &Path) {
-    if crate::ci::CiEnv::is_ci() {
-        // this warning is useless in CI,
-        // and CI probably won't have the right branches anyway.
-        return;
-    }
-    // this will be overwritten by the actual name, if possible
-    let mut updated_master = "the upstream master branch".to_string();
-    match warn_old_master_branch_(config, git_dir, &mut updated_master) {
-        Ok(branch_is_old) => {
-            if !branch_is_old {
-                return;
-            }
-            // otherwise fall through and print the rest of the warning
-        }
-        Err(err) => {
-            eprintln!("warning: unable to check if {updated_master} is old due to error: {err}")
-        }
-    }
-    eprintln!(
-        "warning: {updated_master} is used to determine if files have been modified\n\
-         warning: if it is not updated, this may cause files to be needlessly reformatted"
-    );
-}
-
-pub fn warn_old_master_branch_(
-    config: &GitConfig<'_>,
-    git_dir: &Path,
-    updated_master: &mut String,
-) -> Result<bool, Box<dyn std::error::Error>> {
-    use std::time::Duration;
-    *updated_master = updated_master_branch(config, Some(git_dir))?;
-    let branch_path = git_dir.join(".git/refs/remotes").join(&updated_master);
-    const WARN_AFTER: Duration = Duration::from_secs(60 * 60 * 24 * 10);
-    let meta = match std::fs::metadata(&branch_path) {
-        Ok(meta) => meta,
-        Err(err) => {
-            let gcd = git_common_dir(&git_dir)?;
-            if branch_path.starts_with(&gcd) {
-                return Err(Box::new(err));
-            }
-            std::fs::metadata(Path::new(&gcd).join("refs/remotes").join(&updated_master))?
-        }
-    };
-    if meta.modified()?.elapsed()? > WARN_AFTER {
-        eprintln!("warning: {updated_master} has not been updated in 10 days");
-        Ok(true)
-    } else {
-        Ok(false)
-    }
-}
-
-fn git_common_dir(dir: &Path) -> Result<String, String> {
-    output_result(Command::new("git").arg("-C").arg(dir).arg("rev-parse").arg("--git-common-dir"))
-        .map(|x| x.trim().to_string())
-}
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 80d82ca22abbee5fb7b51fa1abeb1ae34e99e88
+Subproject ad074abe3a18ce8444c06f962ceecfd056acfc7
diff --git a/src/tools/clippy/.github/workflows/remark.yml b/src/tools/clippy/.github/workflows/remark.yml
index 348d52020fd..a1b011dc32d 100644
--- a/src/tools/clippy/.github/workflows/remark.yml
+++ b/src/tools/clippy/.github/workflows/remark.yml
@@ -19,7 +19,7 @@ jobs:
       uses: actions/checkout@v4
 
     - name: Setup Node.js
-      uses: actions/setup-node@v3
+      uses: actions/setup-node@v4
       with:
         node-version: '18.x'
 
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 41a86e8ce51..5d253d52531 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -5871,6 +5871,7 @@ Released 2018-09-13
 [`ref_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_as_ptr
 [`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
 [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
+[`ref_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option
 [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
 [`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns
 [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index 91159bc79c5..07a56fb33df 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -353,6 +353,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat
 * [`rc_buffer`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer)
 * [`rc_mutex`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex)
 * [`redundant_allocation`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation)
+* [`ref_option`](https://rust-lang.github.io/rust-clippy/master/index.html#ref_option)
 * [`single_call_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#single_call_fn)
 * [`trivially_copy_pass_by_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref)
 * [`unnecessary_box_returns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns)
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 757620341cc..e4e2c97fdc1 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -378,6 +378,7 @@ define_Conf! {
         rc_buffer,
         rc_mutex,
         redundant_allocation,
+        ref_option,
         single_call_fn,
         trivially_copy_pass_by_ref,
         unnecessary_box_returns,
diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs
index e30df3d3234..68a3b11d384 100644
--- a/src/tools/clippy/clippy_config/src/msrvs.rs
+++ b/src/tools/clippy/clippy_config/src/msrvs.rs
@@ -19,6 +19,7 @@ macro_rules! msrv_aliases {
 msrv_aliases! {
     1,83,0 { CONST_EXTERN_FN }
     1,83,0 { CONST_FLOAT_BITS_CONV }
+    1,82,0 { IS_NONE_OR }
     1,81,0 { LINT_REASONS_STABILIZATION }
     1,80,0 { BOX_INTO_ITER}
     1,77,0 { C_STR_LITERALS }
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 3c2af72624f..26888f7e3a0 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -1,3 +1,5 @@
+use clippy_config::Conf;
+use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::eq_expr_value;
 use clippy_utils::source::SpanRangeExt;
@@ -7,7 +9,7 @@ use rustc_errors::Applicability;
 use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
 use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp};
 use rustc_lint::{LateContext, LateLintPass, Level};
-use rustc_session::declare_lint_pass;
+use rustc_session::{RustcVersion, impl_lint_pass};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{Span, sym};
 
@@ -69,9 +71,25 @@ declare_clippy_lint! {
 }
 
 // For each pairs, both orders are considered.
-const METHODS_WITH_NEGATION: [(&str, &str); 2] = [("is_some", "is_none"), ("is_err", "is_ok")];
+const METHODS_WITH_NEGATION: [(Option<RustcVersion>, &str, &str); 3] = [
+    (None, "is_some", "is_none"),
+    (None, "is_err", "is_ok"),
+    (Some(msrvs::IS_NONE_OR), "is_some_and", "is_none_or"),
+];
+
+pub struct NonminimalBool {
+    msrv: Msrv,
+}
+
+impl NonminimalBool {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
+    }
+}
 
-declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, OVERLY_COMPLEX_BOOL_EXPR]);
+impl_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, OVERLY_COMPLEX_BOOL_EXPR]);
 
 impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
     fn check_fn(
@@ -83,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
         _: Span,
         _: LocalDefId,
     ) {
-        NonminimalBoolVisitor { cx }.visit_body(body);
+        NonminimalBoolVisitor { cx, msrv: &self.msrv }.visit_body(body);
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
@@ -100,6 +118,8 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
             _ => {},
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
 fn inverted_bin_op_eq_str(op: BinOpKind) -> Option<&'static str> {
@@ -176,11 +196,11 @@ fn check_inverted_bool_in_condition(
     );
 }
 
-fn check_simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) {
+fn check_simplify_not(cx: &LateContext<'_>, msrv: &Msrv, expr: &Expr<'_>) {
     if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind
         && !expr.span.from_expansion()
         && !inner.span.from_expansion()
-        && let Some(suggestion) = simplify_not(cx, inner)
+        && let Some(suggestion) = simplify_not(cx, msrv, inner)
         && cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow
     {
         span_lint_and_sugg(
@@ -197,6 +217,7 @@ fn check_simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) {
 
 struct NonminimalBoolVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
+    msrv: &'a Msrv,
 }
 
 use quine_mc_cluskey::Bool;
@@ -205,7 +226,7 @@ struct Hir2Qmm<'a, 'tcx, 'v> {
     cx: &'a LateContext<'tcx>,
 }
 
-impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
+impl<'v> Hir2Qmm<'_, '_, 'v> {
     fn extract(&mut self, op: BinOpKind, a: &[&'v Expr<'_>], mut v: Vec<Bool>) -> Result<Vec<Bool>, String> {
         for a in a {
             if let ExprKind::Binary(binop, lhs, rhs) = &a.kind {
@@ -289,10 +310,11 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
 struct SuggestContext<'a, 'tcx, 'v> {
     terminals: &'v [&'v Expr<'v>],
     cx: &'a LateContext<'tcx>,
+    msrv: &'a Msrv,
     output: String,
 }
 
-impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
+impl SuggestContext<'_, '_, '_> {
     fn recurse(&mut self, suggestion: &Bool) -> Option<()> {
         use quine_mc_cluskey::Bool::{And, False, Not, Or, Term, True};
         match suggestion {
@@ -311,7 +333,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
                 },
                 Term(n) => {
                     let terminal = self.terminals[n as usize];
-                    if let Some(str) = simplify_not(self.cx, terminal) {
+                    if let Some(str) = simplify_not(self.cx, self.msrv, terminal) {
                         self.output.push_str(&str);
                     } else {
                         self.output.push('!');
@@ -358,7 +380,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
     }
 }
 
-fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
+fn simplify_not(cx: &LateContext<'_>, curr_msrv: &Msrv, expr: &Expr<'_>) -> Option<String> {
     match &expr.kind {
         ExprKind::Binary(binop, lhs, rhs) => {
             if !implements_ord(cx, lhs) {
@@ -389,7 +411,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
                 Some(format!("{lhs_snippet}{op}{rhs_snippet}"))
             })
         },
-        ExprKind::MethodCall(path, receiver, [], _) => {
+        ExprKind::MethodCall(path, receiver, args, _) => {
             let type_of_receiver = cx.typeck_results().expr_ty(receiver);
             if !is_type_diagnostic_item(cx, type_of_receiver, sym::Option)
                 && !is_type_diagnostic_item(cx, type_of_receiver, sym::Result)
@@ -399,21 +421,41 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
             METHODS_WITH_NEGATION
                 .iter()
                 .copied()
-                .flat_map(|(a, b)| vec![(a, b), (b, a)])
-                .find(|&(a, _)| {
-                    let path: &str = path.ident.name.as_str();
-                    a == path
+                .flat_map(|(msrv, a, b)| vec![(msrv, a, b), (msrv, b, a)])
+                .find(|&(msrv, a, _)| msrv.is_none_or(|msrv| curr_msrv.meets(msrv)) && a == path.ident.name.as_str())
+                .and_then(|(_, _, neg_method)| {
+                    let negated_args = args
+                        .iter()
+                        .map(|arg| simplify_not(cx, curr_msrv, arg))
+                        .collect::<Option<Vec<_>>>()?
+                        .join(", ");
+                    Some(format!(
+                        "{}.{neg_method}({negated_args})",
+                        receiver.span.get_source_text(cx)?
+                    ))
                 })
-                .and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", receiver.span.get_source_text(cx)?)))
         },
+        ExprKind::Closure(closure) => {
+            let body = cx.tcx.hir().body(closure.body);
+            let params = body
+                .params
+                .iter()
+                .map(|param| param.span.get_source_text(cx).map(|t| t.to_string()))
+                .collect::<Option<Vec<_>>>()?
+                .join(", ");
+            let negated = simplify_not(cx, curr_msrv, body.value)?;
+            Some(format!("|{params}| {negated}"))
+        },
+        ExprKind::Unary(UnOp::Not, expr) => expr.span.get_source_text(cx).map(|t| t.to_string()),
         _ => None,
     }
 }
 
-fn suggest(cx: &LateContext<'_>, suggestion: &Bool, terminals: &[&Expr<'_>]) -> String {
+fn suggest(cx: &LateContext<'_>, msrv: &Msrv, suggestion: &Bool, terminals: &[&Expr<'_>]) -> String {
     let mut suggest_context = SuggestContext {
         terminals,
         cx,
+        msrv,
         output: String::new(),
     };
     suggest_context.recurse(suggestion);
@@ -475,7 +517,7 @@ fn terminal_stats(b: &Bool) -> Stats {
     stats
 }
 
-impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
+impl<'tcx> NonminimalBoolVisitor<'_, 'tcx> {
     fn bool_expr(&self, e: &'tcx Expr<'_>) {
         let mut h2q = Hir2Qmm {
             terminals: Vec::new(),
@@ -526,7 +568,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
                                 diag.span_suggestion(
                                     e.span,
                                     "it would look like the following",
-                                    suggest(self.cx, suggestion, &h2q.terminals),
+                                    suggest(self.cx, self.msrv, suggestion, &h2q.terminals),
                                     // nonminimal_bool can produce minimal but
                                     // not human readable expressions (#3141)
                                     Applicability::Unspecified,
@@ -569,12 +611,12 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
                 }
             };
             if improvements.is_empty() {
-                check_simplify_not(self.cx, e);
+                check_simplify_not(self.cx, self.msrv, e);
             } else {
                 nonminimal_bool_lint(
                     improvements
                         .into_iter()
-                        .map(|suggestion| suggest(self.cx, suggestion, &h2q.terminals))
+                        .map(|suggestion| suggest(self.cx, self.msrv, suggestion, &h2q.terminals))
                         .collect(),
                 );
             }
@@ -582,7 +624,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         if !e.span.from_expansion() {
             match &e.kind {
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 8261c65354f..40d154c0bdf 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -91,7 +91,7 @@ fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>)
 #[derive(Default)]
 struct InferVisitor(bool);
 
-impl<'tcx> Visitor<'tcx> for InferVisitor {
+impl Visitor<'_> for InferVisitor {
     fn visit_ty(&mut self, t: &Ty<'_>) {
         self.0 |= matches!(t.kind, TyKind::Infer | TyKind::OpaqueDef(..) | TyKind::TraitObject(..));
         if !self.0 {
diff --git a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs
index fed0aa8b275..6714c053913 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs
@@ -10,27 +10,27 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, ignore_publish: b
         // only run the lint if publish is `None` (`publish = true` or skipped entirely)
         // or if the vector isn't empty (`publish = ["something"]`)
         if package.publish.as_ref().filter(|publish| publish.is_empty()).is_none() || ignore_publish {
-            if is_empty_str(&package.description) {
+            if is_empty_str(package.description.as_ref()) {
                 missing_warning(cx, package, "package.description");
             }
 
-            if is_empty_str(&package.license) && is_empty_str(&package.license_file) {
+            if is_empty_str(package.license.as_ref()) && is_empty_str(package.license_file.as_ref()) {
                 missing_warning(cx, package, "either package.license or package.license_file");
             }
 
-            if is_empty_str(&package.repository) {
+            if is_empty_str(package.repository.as_ref()) {
                 missing_warning(cx, package, "package.repository");
             }
 
-            if is_empty_str(&package.readme) {
+            if is_empty_str(package.readme.as_ref()) {
                 missing_warning(cx, package, "package.readme");
             }
 
-            if is_empty_vec(&package.keywords) {
+            if is_empty_vec(package.keywords.as_ref()) {
                 missing_warning(cx, package, "package.keywords");
             }
 
-            if is_empty_vec(&package.categories) {
+            if is_empty_vec(package.categories.as_ref()) {
                 missing_warning(cx, package, "package.categories");
             }
         }
@@ -42,8 +42,8 @@ fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, fiel
     span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, message);
 }
 
-fn is_empty_str<T: AsRef<std::ffi::OsStr>>(value: &Option<T>) -> bool {
-    value.as_ref().map_or(true, |s| s.as_ref().is_empty())
+fn is_empty_str<T: AsRef<std::ffi::OsStr>>(value: Option<&T>) -> bool {
+    value.map_or(true, |s| s.as_ref().is_empty())
 }
 
 fn is_empty_vec(value: &[String]) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
index b7256dd2eae..4dd51dcbc9a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_no_std_crate;
 use clippy_utils::source::snippet_with_context;
+use clippy_utils::std_or_core;
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind};
 use rustc_lint::LateContext;
@@ -16,8 +16,8 @@ pub(super) fn check<'tcx>(
 ) {
     if matches!(cast_to.kind, TyKind::Ptr(_))
         && let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = cast_expr.kind
+        && let Some(std_or_core) = std_or_core(cx)
     {
-        let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
         let macro_name = match mutability {
             Mutability::Not => "addr_of",
             Mutability::Mut => "addr_of_mut",
@@ -40,7 +40,7 @@ pub(super) fn check<'tcx>(
             expr.span,
             "borrow as raw pointer",
             "try",
-            format!("{core_or_std}::ptr::{macro_name}!({snip})"),
+            format!("{std_or_core}::ptr::{macro_name}!({snip})"),
             Applicability::MachineApplicable,
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
index dfa240ccec6..f699bba20ed 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{ExprUseNode, expr_use_ctxt, is_no_std_crate};
+use clippy_utils::{ExprUseNode, expr_use_ctxt, std_or_core};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Mutability, Ty, TyKind};
 use rustc_lint::LateContext;
@@ -25,8 +25,8 @@ pub(super) fn check<'tcx>(
         && let use_cx = expr_use_ctxt(cx, expr)
         // TODO: only block the lint if `cast_expr` is a temporary
         && !matches!(use_cx.use_node(cx), ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_))
+        && let Some(std_or_core) = std_or_core(cx)
     {
-        let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
         let fn_name = match to_mutbl {
             Mutability::Not => "from_ref",
             Mutability::Mut => "from_mut",
@@ -56,7 +56,7 @@ pub(super) fn check<'tcx>(
             expr.span,
             "reference as raw pointer",
             "try",
-            format!("{core_or_std}::ptr::{fn_name}{turbofish}({cast_expr_sugg})"),
+            format!("{std_or_core}::ptr::{fn_name}{turbofish}({cast_expr_sugg})"),
             app,
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
index d3aa2fd1ea1..2e7f91a842e 100644
--- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -48,7 +48,7 @@ impl CheckedConversions {
 
 impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);
 
-impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
+impl LateLintPass<'_> for CheckedConversions {
     fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
         if let ExprKind::Binary(op, lhs, rhs) = item.kind
             && let (lt1, gt1, op2) = match op.node {
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 2b229d2fe6a..9cec672beb0 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -202,6 +202,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::functions::MUST_USE_CANDIDATE_INFO,
     crate::functions::MUST_USE_UNIT_INFO,
     crate::functions::NOT_UNSAFE_PTR_ARG_DEREF_INFO,
+    crate::functions::REF_OPTION_INFO,
     crate::functions::RENAMED_FUNCTION_PARAMS_INFO,
     crate::functions::RESULT_LARGE_ERR_INFO,
     crate::functions::RESULT_UNIT_ERR_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index a065dc2cf7e..4808c372754 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -119,7 +119,7 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         match &expr.kind {
             ExprKind::Block(
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 35a97adfb45..82a66cc9202 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -385,7 +385,7 @@ fn check_unsafe_derive_deserialize<'tcx>(
         && cx
             .tcx
             .inherent_impls(def.did())
-            .into_iter()
+            .iter()
             .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local()))
             .any(|imp| has_unsafe(cx, imp))
     {
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 0ae1fad5692..e090644ae44 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -970,7 +970,7 @@ impl<'a, 'tcx> FindPanicUnwrap<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs
index f4c55738cb8..70eb81fa09c 100644
--- a/src/tools/clippy/clippy_lints/src/empty_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs
@@ -60,7 +60,7 @@ declare_clippy_lint! {
 
 declare_lint_pass!(EmptyEnum => [EMPTY_ENUM]);
 
-impl<'tcx> LateLintPass<'tcx> for EmptyEnum {
+impl LateLintPass<'_> for EmptyEnum {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         if let ItemKind::Enum(..) = item.kind
             // Only suggest the `never_type` if the feature is enabled
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 5588124e791..a89f0d9c432 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -141,7 +141,7 @@ fn is_argument(tcx: TyCtxt<'_>, id: HirId) -> bool {
     matches!(tcx.parent_hir_node(id), Node::Param(_))
 }
 
-impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
+impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> {
     fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
         if cmt.place.projections.is_empty() {
             if let PlaceBase::Local(lid) = cmt.place.base {
@@ -188,7 +188,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
     fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
 }
 
-impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
+impl<'tcx> EscapeDelegate<'_, 'tcx> {
     fn is_large_box(&self, ty: Ty<'tcx>) -> bool {
         // Large types need to be boxed to avoid stack overflows.
         if let Some(boxed_ty) = ty.boxed_ty() {
diff --git a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
index ce0e0faa014..ffc76366983 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
@@ -135,7 +135,7 @@ impl NestingVisitor<'_, '_> {
     }
 }
 
-impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> {
+impl Visitor<'_> for NestingVisitor<'_, '_> {
     fn visit_block(&mut self, block: &Block) {
         if block.span.from_expansion() {
             return;
diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
index bf9388b4a70..6ad879b9fe7 100644
--- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
+++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
@@ -6,7 +6,7 @@ use rustc_errors::Applicability;
 use rustc_hir::intravisit::{Visitor, walk_impl_item, walk_item, walk_param_bound, walk_ty};
 use rustc_hir::{
     BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind,
-    PredicateOrigin, Ty, TyKind, WherePredicate,
+    PredicateOrigin, Ty, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::nested_filter;
@@ -193,18 +193,12 @@ fn bound_to_trait_def_id(bound: &GenericBound<'_>) -> Option<LocalDefId> {
     bound.trait_ref()?.trait_def_id()?.as_local()
 }
 
-impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
+impl<'tcx> Visitor<'tcx> for TypeWalker<'_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
         if let Some((def_id, _)) = t.peel_refs().as_generic_param() {
             self.ty_params.remove(&def_id);
-        } else if let TyKind::OpaqueDef(id, _, _) = t.kind {
-            // Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls
-            // `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're
-            // using `OnlyBodies`, so the check ends up failing and the type isn't fully walked.
-            let item = self.nested_visit_map().item(id);
-            walk_item(self, item);
         } else {
             walk_ty(self, t);
         }
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index 747ea9a4344..f822432cce6 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -73,7 +73,7 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl
         result: Vec<Span>,
     }
 
-    impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
+    impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> {
         fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             if let Some(macro_call) = root_macro_call_first_node(self.lcx, expr) {
                 if is_panic(self.lcx, macro_call.def_id) {
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 83ab9f6557b..4c043f8dc14 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -219,7 +219,7 @@ struct FormatArgsExpr<'a, 'tcx> {
     ignore_mixed: bool,
 }
 
-impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> {
+impl FormatArgsExpr<'_, '_> {
     fn check_templates(&self) {
         for piece in &self.format_args.template {
             if let FormatArgsPiece::Placeholder(placeholder) = piece
diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs
index c196f404ce6..7c0515b8c56 100644
--- a/src/tools/clippy/clippy_lints/src/format_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/format_impl.rs
@@ -148,7 +148,7 @@ struct FormatImplExpr<'a, 'tcx> {
     format_trait_impl: FormatTraitNames,
 }
 
-impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> {
+impl FormatImplExpr<'_, '_> {
     fn check_to_string_in_display(&self) {
         if self.format_trait_impl.name == sym::Display
             && let ExprKind::MethodCall(path, self_arg, ..) = self.expr.kind
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index 8832cd42dd9..d5a2e06863d 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -126,7 +126,7 @@ struct SelfFinder<'a, 'tcx> {
     invalid: bool,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for SelfFinder<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for SelfFinder<'_, 'tcx> {
     type NestedFilter = OnlyBodies;
 
     fn nested_visit_map(&mut self) -> Self::Map {
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index ba8a459c917..91d73c2a9c9 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -2,6 +2,7 @@ mod impl_trait_in_params;
 mod misnamed_getters;
 mod must_use;
 mod not_unsafe_ptr_arg_deref;
+mod ref_option;
 mod renamed_function_params;
 mod result;
 mod too_many_arguments;
@@ -399,6 +400,53 @@ declare_clippy_lint! {
     "renamed function parameters in trait implementation"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Warns when a function signature uses `&Option<T>` instead of `Option<&T>`.
+    ///
+    /// ### Why is this bad?
+    /// More flexibility, better memory optimization, and more idiomatic Rust code.
+    ///
+    /// `&Option<T>` in a function signature breaks encapsulation because the caller must own T
+    /// and move it into an Option to call with it. When returned, the owner must internally store
+    /// it as `Option<T>` in order to return it.
+    /// At a lower level, `&Option<T>` points to memory with the `presence` bit flag plus the `T` value,
+    /// whereas `Option<&T>` is usually [optimized](https://doc.rust-lang.org/1.81.0/std/option/index.html#representation)
+    /// to a single pointer, so it may be more optimal.
+    ///
+    /// See this [YouTube video](https://www.youtube.com/watch?v=6c7pZYP_iIE) by
+    /// Logan Smith for an in-depth explanation of why this is important.
+    ///
+    /// ### Known problems
+    /// This lint recommends changing the function signatures, but it cannot
+    /// automatically change the function calls or the function implementations.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// // caller uses  foo(&opt)
+    /// fn foo(a: &Option<String>) {}
+    /// # struct Unit {}
+    /// # impl Unit {
+    /// fn bar(&self) -> &Option<String> { &None }
+    /// # }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// // caller should use  `foo1(opt.as_ref())`
+    /// fn foo1(a: Option<&String>) {}
+    /// // better yet, use string slice  `foo2(opt.as_deref())`
+    /// fn foo2(a: Option<&str>) {}
+    /// # struct Unit {}
+    /// # impl Unit {
+    /// fn bar(&self) -> Option<&String> { None }
+    /// # }
+    /// ```
+    #[clippy::version = "1.82.0"]
+    pub REF_OPTION,
+    pedantic,
+    "function signature uses `&Option<T>` instead of `Option<&T>`"
+}
+
 pub struct Functions {
     too_many_arguments_threshold: u64,
     too_many_lines_threshold: u64,
@@ -437,6 +485,7 @@ impl_lint_pass!(Functions => [
     MISNAMED_GETTERS,
     IMPL_TRAIT_IN_PARAMS,
     RENAMED_FUNCTION_PARAMS,
+    REF_OPTION,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Functions {
@@ -455,6 +504,16 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
         not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id);
         misnamed_getters::check_fn(cx, kind, decl, body, span);
         impl_trait_in_params::check_fn(cx, &kind, body, hir_id);
+        ref_option::check_fn(
+            cx,
+            kind,
+            decl,
+            span,
+            hir_id,
+            def_id,
+            body,
+            self.avoid_breaking_exported_api,
+        );
     }
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
@@ -475,5 +534,6 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
         must_use::check_trait_item(cx, item);
         result::check_trait_item(cx, item, self.large_error_threshold);
         impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api);
+        ref_option::check_trait_item(cx, item, self.avoid_breaking_exported_api);
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/functions/ref_option.rs b/src/tools/clippy/clippy_lints/src/functions/ref_option.rs
new file mode 100644
index 00000000000..373ecd74cb3
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/functions/ref_option.rs
@@ -0,0 +1,122 @@
+use crate::functions::REF_OPTION;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_trait_impl_item;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{FnDecl, HirId};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, GenericArgKind, Mutability, Ty};
+use rustc_span::def_id::LocalDefId;
+use rustc_span::{Span, sym};
+
+fn check_ty<'a>(cx: &LateContext<'a>, param: &rustc_hir::Ty<'a>, param_ty: Ty<'a>, fixes: &mut Vec<(Span, String)>) {
+    if let ty::Ref(_, opt_ty, Mutability::Not) = param_ty.kind()
+        && is_type_diagnostic_item(cx, *opt_ty, sym::Option)
+        && let ty::Adt(_, opt_gen) = opt_ty.kind()
+        && let [gen] = opt_gen.as_slice()
+        && let GenericArgKind::Type(gen_ty) = gen.unpack()
+        && !gen_ty.is_ref()
+        // Need to gen the original spans, so first parsing mid, and hir parsing afterward
+        && let hir::TyKind::Ref(lifetime, hir::MutTy { ty, .. }) = param.kind
+        && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
+        && let (Some(first), Some(last)) = (path.segments.first(), path.segments.last())
+        && let Some(hir::GenericArgs {
+            args: [hir::GenericArg::Type(opt_ty)],
+            ..
+        }) = last.args
+    {
+        let lifetime = snippet(cx, lifetime.ident.span, "..");
+        fixes.push((
+            param.span,
+            format!(
+                "{}<&{lifetime}{}{}>",
+                snippet(cx, first.ident.span.to(last.ident.span), ".."),
+                if lifetime.is_empty() { "" } else { " " },
+                snippet(cx, opt_ty.span, "..")
+            ),
+        ));
+    }
+}
+
+fn check_fn_sig<'a>(cx: &LateContext<'a>, decl: &FnDecl<'a>, span: Span, sig: ty::FnSig<'a>) {
+    let mut fixes = Vec::new();
+    // Check function arguments' types
+    for (param, param_ty) in decl.inputs.iter().zip(sig.inputs()) {
+        check_ty(cx, param, *param_ty, &mut fixes);
+    }
+    // Check return type
+    if let hir::FnRetTy::Return(ty) = &decl.output {
+        check_ty(cx, ty, sig.output(), &mut fixes);
+    }
+    if !fixes.is_empty() {
+        span_lint_and_then(
+            cx,
+            REF_OPTION,
+            span,
+            "it is more idiomatic to use `Option<&T>` instead of `&Option<T>`",
+            |diag| {
+                diag.multipart_suggestion("change this to", fixes, Applicability::Unspecified);
+            },
+        );
+    }
+}
+
+#[allow(clippy::too_many_arguments)]
+pub(crate) fn check_fn<'a>(
+    cx: &LateContext<'a>,
+    kind: FnKind<'_>,
+    decl: &FnDecl<'a>,
+    span: Span,
+    hir_id: HirId,
+    def_id: LocalDefId,
+    body: &hir::Body<'_>,
+    avoid_breaking_exported_api: bool,
+) {
+    if avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
+        return;
+    }
+
+    if let FnKind::Closure = kind {
+        // Compute the span of the closure parameters + return type if set
+        let span = if let hir::FnRetTy::Return(out_ty) = &decl.output {
+            if decl.inputs.is_empty() {
+                out_ty.span
+            } else {
+                span.with_hi(out_ty.span.hi())
+            }
+        } else if let (Some(first), Some(last)) = (decl.inputs.first(), decl.inputs.last()) {
+            first.span.to(last.span)
+        } else {
+            // No parameters - no point in checking
+            return;
+        };
+
+        // Figure out the signature of the closure
+        let ty::Closure(_, args) = cx.typeck_results().expr_ty(body.value).kind() else {
+            return;
+        };
+        let sig = args.as_closure().sig().skip_binder();
+
+        check_fn_sig(cx, decl, span, sig);
+    } else if !is_trait_impl_item(cx, hir_id) {
+        let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
+        check_fn_sig(cx, decl, span, sig);
+    }
+}
+
+pub(super) fn check_trait_item<'a>(
+    cx: &LateContext<'a>,
+    trait_item: &hir::TraitItem<'a>,
+    avoid_breaking_exported_api: bool,
+) {
+    if let hir::TraitItemKind::Fn(ref sig, _) = trait_item.kind
+        && !(avoid_breaking_exported_api && cx.effective_visibilities.is_exported(trait_item.owner_id.def_id))
+    {
+        let def_id = trait_item.owner_id.def_id;
+        let ty_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
+        check_fn_sig(cx, sig.decl, sig.span, ty_sig);
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index f683925145a..4c5375730b8 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -281,7 +281,7 @@ impl<'a, 'tcx> ImplicitHasherTypeVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'_, 'tcx> {
     fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) {
         if let Some(target) = ImplicitHasherType::new(self.cx, t) {
             self.found.push(target);
@@ -318,7 +318,7 @@ impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
     }
 }
 
-impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
+impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_body(&mut self, body: &Body<'tcx>) {
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index 6794c6cabfe..5f349d78053 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::snippet;
 use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{
-    AssocItemConstraint, GenericArg, GenericBound, GenericBounds, ItemKind, PredicateOrigin, TraitBoundModifier,
+    AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifier,
     TyKind, WherePredicate,
 };
 use rustc_hir_analysis::lower_ty;
@@ -342,11 +342,8 @@ impl<'tcx> LateLintPass<'tcx> for ImpliedBoundsInImpls {
         }
     }
 
-    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &rustc_hir::Ty<'_>) {
-        if let TyKind::OpaqueDef(item_id, ..) = ty.kind
-            && let item = cx.tcx.hir().item(item_id)
-            && let ItemKind::OpaqueTy(opaque_ty) = item.kind
-        {
+    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &rustc_hir::Ty<'tcx>) {
+        if let TyKind::OpaqueDef(opaque_ty, ..) = ty.kind {
             check(cx, opaque_ty.bounds);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index 39afb6810b8..73ebe6aec15 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -226,7 +226,7 @@ struct SliceIndexLintingVisitor<'a, 'tcx> {
     max_suggested_slice: u64,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
     fn nested_visit_map(&mut self) -> Self::Map {
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 8bc2a56af99..311bbce14bd 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -308,12 +308,8 @@ enum LenOutput {
 
 fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
     if let ty::Alias(_, alias_ty) = ty.kind()
-        && let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(alias_ty.def_id)
-        && let Item {
-            kind: ItemKind::OpaqueTy(opaque),
-            ..
-        } = item
-        && let OpaqueTyOrigin::AsyncFn(_) = opaque.origin
+        && let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir().get_if_local(alias_ty.def_id)
+        && let OpaqueTyOrigin::AsyncFn { .. } = opaque.origin
         && let [GenericBound::Trait(trait_ref, _)] = &opaque.bounds
         && let Some(segment) = trait_ref.trait_ref.path.segments.last()
         && let Some(generic_args) = segment.args
@@ -460,7 +456,7 @@ fn check_for_is_empty(
     let is_empty = cx
         .tcx
         .inherent_impls(impl_ty)
-        .into_iter()
+        .iter()
         .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty))
         .find(|item| item.kind == AssocKind::Fn);
 
@@ -628,7 +624,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     /// Checks the inherent impl's items for an `is_empty(self)` method.
     fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
         let is_empty = sym!(is_empty);
-        cx.tcx.inherent_impls(id).into_iter().any(|imp| {
+        cx.tcx.inherent_impls(id).iter().any(|imp| {
             cx.tcx
                 .associated_items(*imp)
                 .filter_by_name_unhygienic(is_empty)
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 1d41f568f37..012aa689d4b 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -1,7 +1,6 @@
 #![feature(array_windows)]
 #![feature(binary_heap_into_iter_sorted)]
 #![feature(box_patterns)]
-#![feature(control_flow_enum)]
 #![feature(f128)]
 #![feature(f16)]
 #![feature(if_let_guard)]
@@ -609,7 +608,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |tcx| Box::new(await_holding_invalid::AwaitHolding::new(tcx, conf)));
     store.register_late_pass(|_| Box::new(serde_api::SerdeApi));
     store.register_late_pass(move |_| Box::new(types::Types::new(conf)));
-    store.register_late_pass(|_| Box::new(booleans::NonminimalBool));
+    store.register_late_pass(move |_| Box::new(booleans::NonminimalBool::new(conf)));
     store.register_late_pass(|_| Box::new(enum_clike::UnportableVariant));
     store.register_late_pass(|_| Box::new(float_literal::FloatLiteral));
     store.register_late_pass(|_| Box::new(ptr::Ptr));
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 755afe959b3..7c3ef98fd74 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -6,12 +6,12 @@ use rustc_errors::Applicability;
 use rustc_hir::FnRetTy::Return;
 use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter};
 use rustc_hir::intravisit::{
-    Visitor, walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound,
-    walk_poly_trait_ref, walk_trait_ref, walk_ty,
+    Visitor, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_param_bound,
+    walk_poly_trait_ref, walk_trait_ref, walk_ty, walk_where_predicate,
 };
 use rustc_hir::{
-    BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl,
-    ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef,
+    BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics,
+    Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef,
     PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, lang_items,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -21,7 +21,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
-use rustc_span::symbol::{Ident, Symbol, kw};
+use rustc_span::symbol::{Ident, kw};
 use std::ops::ControlFlow;
 
 declare_clippy_lint! {
@@ -191,45 +191,10 @@ fn check_fn_inner<'tcx>(
         if usages.iter().any(|usage| !usage.ident.span.eq_ctxt(span)) {
             return;
         }
-
-        let lts = elidable_lts
-            .iter()
-            // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
-            // `Node::GenericParam`.
-            .filter_map(|&def_id| cx.tcx.hir_node_by_def_id(def_id).ident())
-            .map(|ident| ident.to_string())
-            .collect::<Vec<_>>()
-            .join(", ");
-
-        span_lint_and_then(
-            cx,
-            NEEDLESS_LIFETIMES,
-            elidable_lts
-                .iter()
-                .map(|&lt| cx.tcx.def_span(lt))
-                .chain(usages.iter().filter_map(|usage| {
-                    if let LifetimeName::Param(def_id) = usage.res
-                        && elidable_lts.contains(&def_id)
-                    {
-                        return Some(usage.ident.span);
-                    }
-
-                    None
-                }))
-                .collect_vec(),
-            format!("the following explicit lifetimes could be elided: {lts}"),
-            |diag| {
-                if sig.header.is_async() {
-                    // async functions have usages whose spans point at the lifetime declaration which messes up
-                    // suggestions
-                    return;
-                };
-
-                if let Some(suggestions) = elision_suggestions(cx, generics, &elidable_lts, &usages) {
-                    diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable);
-                }
-            },
-        );
+        // async functions have usages whose spans point at the lifetime declaration which messes up
+        // suggestions
+        let include_suggestions = !sig.header.is_async();
+        report_elidable_lifetimes(cx, generics, &elidable_lts, &usages, include_suggestions);
     }
 
     if report_extra_lifetimes {
@@ -237,97 +202,6 @@ fn check_fn_inner<'tcx>(
     }
 }
 
-fn elision_suggestions(
-    cx: &LateContext<'_>,
-    generics: &Generics<'_>,
-    elidable_lts: &[LocalDefId],
-    usages: &[Lifetime],
-) -> Option<Vec<(Span, String)>> {
-    let explicit_params = generics
-        .params
-        .iter()
-        .filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait())
-        .collect::<Vec<_>>();
-
-    let mut suggestions = if elidable_lts.len() == explicit_params.len() {
-        // if all the params are elided remove the whole generic block
-        //
-        // fn x<'a>() {}
-        //     ^^^^
-        vec![(generics.span, String::new())]
-    } else {
-        elidable_lts
-            .iter()
-            .map(|&id| {
-                let pos = explicit_params.iter().position(|param| param.def_id == id)?;
-                let param = explicit_params.get(pos)?;
-
-                let span = if let Some(next) = explicit_params.get(pos + 1) {
-                    // fn x<'prev, 'a, 'next>() {}
-                    //             ^^^^
-                    param.span.until(next.span)
-                } else {
-                    // `pos` should be at least 1 here, because the param in position 0 would either have a `next`
-                    // param or would have taken the `elidable_lts.len() == explicit_params.len()` branch.
-                    let prev = explicit_params.get(pos - 1)?;
-
-                    // fn x<'prev, 'a>() {}
-                    //           ^^^^
-                    param.span.with_lo(prev.span.hi())
-                };
-
-                Some((span, String::new()))
-            })
-            .collect::<Option<Vec<_>>>()?
-    };
-
-    suggestions.extend(
-        usages
-            .iter()
-            .filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id)))
-            .map(|usage| {
-                match cx.tcx.parent_hir_node(usage.hir_id) {
-                    Node::Ty(Ty {
-                        kind: TyKind::Ref(..), ..
-                    }) => {
-                        // expand `&'a T` to `&'a T`
-                        //          ^^         ^^^
-                        let span = cx.sess().source_map().span_extend_while_whitespace(usage.ident.span);
-
-                        (span, String::new())
-                    },
-                    // `T<'a>` and `impl Foo + 'a` should be replaced by `'_`
-                    _ => (usage.ident.span, String::from("'_")),
-                }
-            }),
-    );
-
-    Some(suggestions)
-}
-
-// elision doesn't work for explicit self types, see rust-lang/rust#69064
-fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>) -> bool {
-    if let Some(ident) = ident
-        && ident.name == kw::SelfLower
-        && !func.implicit_self.has_implicit_self()
-        && let Some(self_ty) = func.inputs.first()
-    {
-        let mut visitor = RefVisitor::new(cx);
-        visitor.visit_ty(self_ty);
-
-        !visitor.all_lts().is_empty()
-    } else {
-        false
-    }
-}
-
-fn named_lifetime(lt: &Lifetime) -> Option<LocalDefId> {
-    match lt.res {
-        LifetimeName::Param(id) if !lt.is_anonymous() => Some(id),
-        _ => None,
-    }
-}
-
 fn could_use_elision<'tcx>(
     cx: &LateContext<'tcx>,
     func: &'tcx FnDecl<'_>,
@@ -450,6 +324,22 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<LocalDefId
         .collect()
 }
 
+// elision doesn't work for explicit self types, see rust-lang/rust#69064
+fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>) -> bool {
+    if let Some(ident) = ident
+        && ident.name == kw::SelfLower
+        && !func.implicit_self.has_implicit_self()
+        && let Some(self_ty) = func.inputs.first()
+    {
+        let mut visitor = RefVisitor::new(cx);
+        visitor.visit_ty(self_ty);
+
+        !visitor.all_lts().is_empty()
+    } else {
+        false
+    }
+}
+
 /// Number of times each named lifetime occurs in the given slice. Returns a vector to preserve
 /// relative order.
 #[must_use]
@@ -470,6 +360,13 @@ fn named_lifetime_occurrences(lts: &[Lifetime]) -> Vec<(LocalDefId, usize)> {
     occurrences
 }
 
+fn named_lifetime(lt: &Lifetime) -> Option<LocalDefId> {
+    match lt.res {
+        LifetimeName::Param(id) if !lt.is_anonymous() => Some(id),
+        _ => None,
+    }
+}
+
 struct RefVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     lts: Vec<Lifetime>,
@@ -500,7 +397,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> {
     // for lifetimes as parameters of generics
     fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
         self.lts.push(*lifetime);
@@ -523,11 +420,9 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
 
     fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
         match ty.kind {
-            TyKind::OpaqueDef(item, bounds, _) => {
-                let map = self.cx.tcx.hir();
-                let item = map.item(item);
+            TyKind::OpaqueDef(opaque, bounds) => {
                 let len = self.lts.len();
-                walk_item(self, item);
+                self.visit_opaque_ty(opaque);
                 self.lts.truncate(len);
                 self.lts.extend(bounds.iter().filter_map(|bound| match bound {
                     GenericArg::Lifetime(&l) => Some(l),
@@ -594,23 +489,43 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
     false
 }
 
+struct Usage {
+    lifetime: Lifetime,
+    in_where_predicate: bool,
+    in_generics_arg: bool,
+}
+
 struct LifetimeChecker<'cx, 'tcx, F> {
     cx: &'cx LateContext<'tcx>,
-    map: FxHashMap<Symbol, Span>,
+    map: FxHashMap<LocalDefId, Vec<Usage>>,
+    where_predicate_depth: usize,
+    generic_args_depth: usize,
     phantom: std::marker::PhantomData<F>,
 }
 
 impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F> {
-    fn new(cx: &'cx LateContext<'tcx>, map: FxHashMap<Symbol, Span>) -> LifetimeChecker<'cx, 'tcx, F> {
+    fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'_>) -> LifetimeChecker<'cx, 'tcx, F> {
+        let map = generics
+            .params
+            .iter()
+            .filter_map(|par| match par.kind {
+                GenericParamKind::Lifetime {
+                    kind: LifetimeParamKind::Explicit,
+                } => Some((par.def_id, Vec::new())),
+                _ => None,
+            })
+            .collect();
         Self {
             cx,
             map,
+            where_predicate_depth: 0,
+            generic_args_depth: 0,
             phantom: std::marker::PhantomData,
         }
     }
 }
 
-impl<'cx, 'tcx, F> Visitor<'tcx> for LifetimeChecker<'cx, 'tcx, F>
+impl<'tcx, F> Visitor<'tcx> for LifetimeChecker<'_, 'tcx, F>
 where
     F: NestedFilter<'tcx>,
 {
@@ -619,18 +534,27 @@ where
 
     // for lifetimes as parameters of generics
     fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
-        self.map.remove(&lifetime.ident.name);
+        if let LifetimeName::Param(def_id) = lifetime.res
+            && let Some(usages) = self.map.get_mut(&def_id)
+        {
+            usages.push(Usage {
+                lifetime: *lifetime,
+                in_where_predicate: self.where_predicate_depth != 0,
+                in_generics_arg: self.generic_args_depth != 0,
+            });
+        }
     }
 
-    fn visit_generic_param(&mut self, param: &'tcx GenericParam<'_>) {
-        // don't actually visit `<'a>` or `<'a: 'b>`
-        // we've already visited the `'a` declarations and
-        // don't want to spuriously remove them
-        // `'b` in `'a: 'b` is useless unless used elsewhere in
-        // a non-lifetime bound
-        if let GenericParamKind::Type { .. } = param.kind {
-            walk_generic_param(self, param);
-        }
+    fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) {
+        self.where_predicate_depth += 1;
+        walk_where_predicate(self, predicate);
+        self.where_predicate_depth -= 1;
+    }
+
+    fn visit_generic_args(&mut self, generic_args: &'tcx GenericArgs<'tcx>) -> Self::Result {
+        self.generic_args_depth += 1;
+        walk_generic_args(self, generic_args);
+        self.generic_args_depth -= 1;
     }
 
     fn nested_visit_map(&mut self) -> Self::Map {
@@ -639,44 +563,28 @@ where
 }
 
 fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, generics: &'tcx Generics<'_>) {
-    let hs = generics
-        .params
-        .iter()
-        .filter_map(|par| match par.kind {
-            GenericParamKind::Lifetime {
-                kind: LifetimeParamKind::Explicit,
-            } => Some((par.name.ident().name, par.span)),
-            _ => None,
-        })
-        .collect();
-    let mut checker = LifetimeChecker::<hir_nested_filter::None>::new(cx, hs);
+    let mut checker = LifetimeChecker::<hir_nested_filter::None>::new(cx, generics);
 
     walk_generics(&mut checker, generics);
     walk_fn_decl(&mut checker, func);
 
-    for &v in checker.map.values() {
-        span_lint(
-            cx,
-            EXTRA_UNUSED_LIFETIMES,
-            v,
-            "this lifetime isn't used in the function definition",
-        );
+    for (def_id, usages) in checker.map {
+        if usages
+            .iter()
+            .all(|usage| usage.in_where_predicate && !usage.in_generics_arg)
+        {
+            span_lint(
+                cx,
+                EXTRA_UNUSED_LIFETIMES,
+                cx.tcx.def_span(def_id),
+                "this lifetime isn't used in the function definition",
+            );
+        }
     }
 }
 
 fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'_>) {
-    let hs = impl_
-        .generics
-        .params
-        .iter()
-        .filter_map(|par| match par.kind {
-            GenericParamKind::Lifetime {
-                kind: LifetimeParamKind::Explicit,
-            } => Some((par.name.ident().name, par.span)),
-            _ => None,
-        })
-        .collect();
-    let mut checker = LifetimeChecker::<middle_nested_filter::All>::new(cx, hs);
+    let mut checker = LifetimeChecker::<middle_nested_filter::All>::new(cx, impl_.generics);
 
     walk_generics(&mut checker, impl_.generics);
     if let Some(ref trait_ref) = impl_.of_trait {
@@ -687,9 +595,176 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'
         walk_impl_item_ref(&mut checker, item);
     }
 
-    for &v in checker.map.values() {
-        span_lint(cx, EXTRA_UNUSED_LIFETIMES, v, "this lifetime isn't used in the impl");
+    for (&def_id, usages) in &checker.map {
+        if usages
+            .iter()
+            .all(|usage| usage.in_where_predicate && !usage.in_generics_arg)
+        {
+            span_lint(
+                cx,
+                EXTRA_UNUSED_LIFETIMES,
+                cx.tcx.def_span(def_id),
+                "this lifetime isn't used in the impl",
+            );
+        }
+    }
+
+    report_elidable_impl_lifetimes(cx, impl_, &checker.map);
+}
+
+// An `impl` lifetime is elidable if it satisfies the following conditions:
+// - It is used exactly once.
+// - That single use is not in `GenericArgs` in a `WherePredicate`. (Note that `GenericArgs` are
+//   different from `GenericParam`s.)
+fn report_elidable_impl_lifetimes<'tcx>(
+    cx: &LateContext<'tcx>,
+    impl_: &'tcx Impl<'_>,
+    map: &FxHashMap<LocalDefId, Vec<Usage>>,
+) {
+    let single_usages = map
+        .iter()
+        .filter_map(|(def_id, usages)| {
+            if let [
+                Usage {
+                    lifetime,
+                    in_where_predicate: false,
+                    ..
+                }
+                | Usage {
+                    lifetime,
+                    in_generics_arg: false,
+                    ..
+                },
+            ] = usages.as_slice()
+            {
+                Some((def_id, lifetime))
+            } else {
+                None
+            }
+        })
+        .collect::<Vec<_>>();
+
+    if single_usages.is_empty() {
+        return;
     }
+
+    let (elidable_lts, usages): (Vec<_>, Vec<_>) = single_usages.into_iter().unzip();
+
+    report_elidable_lifetimes(cx, impl_.generics, &elidable_lts, &usages, true);
+}
+
+/// Generate diagnostic messages for elidable lifetimes.
+fn report_elidable_lifetimes(
+    cx: &LateContext<'_>,
+    generics: &Generics<'_>,
+    elidable_lts: &[LocalDefId],
+    usages: &[Lifetime],
+    include_suggestions: bool,
+) {
+    let lts = elidable_lts
+        .iter()
+        // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
+        // `Node::GenericParam`.
+        .filter_map(|&def_id| cx.tcx.hir_node_by_def_id(def_id).ident())
+        .map(|ident| ident.to_string())
+        .collect::<Vec<_>>()
+        .join(", ");
+
+    span_lint_and_then(
+        cx,
+        NEEDLESS_LIFETIMES,
+        elidable_lts
+            .iter()
+            .map(|&lt| cx.tcx.def_span(lt))
+            .chain(usages.iter().filter_map(|usage| {
+                if let LifetimeName::Param(def_id) = usage.res
+                    && elidable_lts.contains(&def_id)
+                {
+                    return Some(usage.ident.span);
+                }
+
+                None
+            }))
+            .collect_vec(),
+        format!("the following explicit lifetimes could be elided: {lts}"),
+        |diag| {
+            if !include_suggestions {
+                return;
+            };
+
+            if let Some(suggestions) = elision_suggestions(cx, generics, elidable_lts, usages) {
+                diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable);
+            }
+        },
+    );
+}
+
+fn elision_suggestions(
+    cx: &LateContext<'_>,
+    generics: &Generics<'_>,
+    elidable_lts: &[LocalDefId],
+    usages: &[Lifetime],
+) -> Option<Vec<(Span, String)>> {
+    let explicit_params = generics
+        .params
+        .iter()
+        .filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait())
+        .collect::<Vec<_>>();
+
+    let mut suggestions = if elidable_lts.len() == explicit_params.len() {
+        // if all the params are elided remove the whole generic block
+        //
+        // fn x<'a>() {}
+        //     ^^^^
+        vec![(generics.span, String::new())]
+    } else {
+        elidable_lts
+            .iter()
+            .map(|&id| {
+                let pos = explicit_params.iter().position(|param| param.def_id == id)?;
+                let param = explicit_params.get(pos)?;
+
+                let span = if let Some(next) = explicit_params.get(pos + 1) {
+                    // fn x<'prev, 'a, 'next>() {}
+                    //             ^^^^
+                    param.span.until(next.span)
+                } else {
+                    // `pos` should be at least 1 here, because the param in position 0 would either have a `next`
+                    // param or would have taken the `elidable_lts.len() == explicit_params.len()` branch.
+                    let prev = explicit_params.get(pos - 1)?;
+
+                    // fn x<'prev, 'a>() {}
+                    //           ^^^^
+                    param.span.with_lo(prev.span.hi())
+                };
+
+                Some((span, String::new()))
+            })
+            .collect::<Option<Vec<_>>>()?
+    };
+
+    suggestions.extend(
+        usages
+            .iter()
+            .filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id)))
+            .map(|usage| {
+                match cx.tcx.parent_hir_node(usage.hir_id) {
+                    Node::Ty(Ty {
+                        kind: TyKind::Ref(..), ..
+                    }) => {
+                        // expand `&'a T` to `&'a T`
+                        //          ^^         ^^^
+                        let span = cx.sess().source_map().span_extend_while_whitespace(usage.ident.span);
+
+                        (span, String::new())
+                    },
+                    // `T<'a>` and `impl Foo + 'a` should be replaced by `'_`
+                    _ => (usage.ident.span, String::from("'_")),
+                }
+            }),
+    );
+
+    Some(suggestions)
 }
 
 struct BodyLifetimeChecker;
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index a7c1d1bd6cd..68d063ad5e5 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -209,7 +209,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
 #[derive(Clone)]
 struct MinifyingSugg<'a>(Sugg<'a>);
 
-impl<'a> Display for MinifyingSugg<'a> {
+impl Display for MinifyingSugg<'_> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         self.0.fmt(f)
     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
index e405829b2f4..a9944d64ce2 100644
--- a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
@@ -1,6 +1,6 @@
 use super::MISSING_SPIN_LOOP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_no_std_crate;
+use clippy_utils::std_or_core;
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Expr, ExprKind};
 use rustc_lint::LateContext;
@@ -41,6 +41,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'
         && [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name)
         && let ty::Adt(def, _args) = cx.typeck_results().expr_ty(callee).kind()
         && cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did())
+        && let Some(std_or_core) = std_or_core(cx)
     {
         span_lint_and_sugg(
             cx,
@@ -48,12 +49,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'
             body.span,
             "busy-waiting loop should at least have a spin loop hint",
             "try",
-            (if is_no_std_crate(cx) {
-                "{ core::hint::spin_loop() }"
-            } else {
-                "{ std::hint::spin_loop() }"
-            })
-            .into(),
+            format!("{{ {std_or_core}::hint::spin_loop() }}"),
             Applicability::MachineApplicable,
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index 20dd5a311dc..745f070a577 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -241,7 +241,7 @@ struct VarVisitor<'a, 'tcx> {
     prefer_mutable: bool,
 }
 
-impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
+impl<'tcx> VarVisitor<'_, 'tcx> {
     fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) -> bool {
         if let ExprKind::Path(ref seqpath) = seqexpr.kind
             // the indexed container is referenced by a name
@@ -292,7 +292,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for VarVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind
             // a range index op
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index 5662d3013e1..f8659897ffe 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -123,7 +123,7 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for SameItemPushVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         match &expr.kind {
             // Non-determinism may occur ... don't give a lint
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index 9a89a41d2b3..c4c504e1ae4 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -44,7 +44,7 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for IncrementVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         // If node is a variable
         if let Some(def_id) = path_to_local(expr) {
@@ -138,7 +138,7 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for InitializeVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_local(&mut self, l: &'tcx LetStmt<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
index eab096e9a22..1a1cde3c5bd 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
@@ -84,7 +84,7 @@ struct VarCollectorVisitor<'a, 'tcx> {
     skip: bool,
 }
 
-impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
+impl<'tcx> VarCollectorVisitor<'_, 'tcx> {
     fn insert_def_id(&mut self, ex: &'tcx Expr<'_>) {
         if let ExprKind::Path(ref qpath) = ex.kind
             && let QPath::Resolved(None, _) = *qpath
@@ -103,7 +103,7 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for VarCollectorVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for VarCollectorVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
         match ex.kind {
             ExprKind::Path(_) => self.insert_def_id(ex),
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
index 7d9fbaf3cea..74467522619 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -283,7 +283,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
         found_local: bool,
         used_after: bool,
     }
-    impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> {
+    impl<'tcx> Visitor<'tcx> for NestedLoopVisitor<'_, '_, 'tcx> {
         type NestedFilter = OnlyBodies;
         fn nested_visit_map(&mut self) -> Self::Map {
             self.cx.tcx.hir()
diff --git a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
index ccc554042d6..312bcb55a95 100644
--- a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
@@ -149,7 +149,7 @@ fn is_public_macro(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
         && !cx.tcx.is_doc_hidden(def_id)
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for BodyVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for BodyVisitor<'_, 'tcx> {
     fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) {
         let from_expn = s.span.from_expansion();
         if from_expn {
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index bd6b3f1a47b..50680331fbc 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -81,7 +81,7 @@ impl MacroUseImports {
     }
 }
 
-impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
+impl LateLintPass<'_> for MacroUseImports {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
         if cx.sess().opts.edition >= Edition::Edition2018
             && let hir::ItemKind::Use(path, _kind) = &item.kind
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index fc3bba9e512..81115cffdca 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -4,7 +4,7 @@ use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
     Block, Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl,
-    FnRetTy, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, TraitRef, Ty, TyKind,
+    FnRetTy, GenericArg, GenericBound, ImplItem, Item, LifetimeName, Node, TraitRef, Ty, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -105,9 +105,7 @@ fn future_trait_ref<'tcx>(
     cx: &LateContext<'tcx>,
     ty: &'tcx Ty<'tcx>,
 ) -> Option<(&'tcx TraitRef<'tcx>, Vec<LifetimeName>)> {
-    if let TyKind::OpaqueDef(item_id, bounds, false) = ty.kind
-        && let item = cx.tcx.hir().item(item_id)
-        && let ItemKind::OpaqueTy(opaque) = &item.kind
+    if let TyKind::OpaqueDef(opaque, bounds) = ty.kind
         && let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| {
             if let GenericBound::Trait(poly, _) = bound {
                 Some(&poly.trait_ref)
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
index 788649fd4f9..fd66cacdfe9 100644
--- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -741,7 +741,7 @@ enum MaybeBorrowedStmtKind<'a> {
     Owned(StmtKind<'a>),
 }
 
-impl<'a> Clone for MaybeBorrowedStmtKind<'a> {
+impl Clone for MaybeBorrowedStmtKind<'_> {
     fn clone(&self) -> Self {
         match self {
             Self::Borrowed(t) => Self::Borrowed(t),
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 9aceca66bf7..828c5a3f6ff 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -203,7 +203,7 @@ fn find_stripping<'tcx>(
         results: Vec<Span>,
     }
 
-    impl<'a, 'tcx> Visitor<'tcx> for StrippingFinder<'a, 'tcx> {
+    impl<'tcx> Visitor<'tcx> for StrippingFinder<'_, 'tcx> {
         fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
             if is_ref_str(self.cx, ex)
                 && let unref = peel_ref(ex)
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index a97dbbbc33f..3221a04d2d0 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -251,7 +251,7 @@ fn lint_map_unit_fn(
     }
 }
 
-impl<'tcx> LateLintPass<'tcx> for MapUnit {
+impl LateLintPass<'_> for MapUnit {
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) {
         if let hir::StmtKind::Semi(expr) = stmt.kind
             && !stmt.span.from_expansion()
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
index 40518ce2ca7..463aa602bc8 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
@@ -40,7 +40,7 @@ struct MatchExprVisitor<'a, 'tcx> {
     case_method: Option<CaseMethod>,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for MatchExprVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
         match ex.kind {
             ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
@@ -49,7 +49,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> MatchExprVisitor<'a, 'tcx> {
+impl MatchExprVisitor<'_, '_> {
     fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> bool {
         if let Some(case_method) = get_case_method(segment_ident) {
             let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs();
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index 686fc4a0fa0..28adcc2f227 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -1045,7 +1045,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
             if !from_expansion {
                 // These don't depend on a relationship between multiple arms
                 match_wild_err_arm::check(cx, ex, arms);
-                wild_in_or_pats::check(cx, arms);
+                wild_in_or_pats::check(cx, ex, arms);
             }
 
             if let MatchSource::TryDesugar(_) = source {
diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
index 6a4c553cee0..856311899f2 100644
--- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
@@ -96,13 +96,13 @@ where
     #[derive(Copy, Clone, Debug, Eq, PartialEq)]
     struct RangeBound<'a, T>(T, BoundKind, &'a SpannedRange<T>);
 
-    impl<'a, T: Copy + Ord> PartialOrd for RangeBound<'a, T> {
+    impl<T: Copy + Ord> PartialOrd for RangeBound<'_, T> {
         fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
             Some(self.cmp(other))
         }
     }
 
-    impl<'a, T: Copy + Ord> Ord for RangeBound<'a, T> {
+    impl<T: Copy + Ord> Ord for RangeBound<'_, T> {
         fn cmp(&self, RangeBound(other_value, other_kind, _): &Self) -> Ordering {
             let RangeBound(self_value, self_kind, _) = *self;
             (self_value, self_kind).cmp(&(*other_value, *other_kind))
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index 537f7272f7f..7372f52e1e5 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -424,7 +424,7 @@ fn ty_has_erased_regions(ty: Ty<'_>) -> bool {
     ty.visit_with(&mut V).is_break()
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for SigDropHelper<'_, 'tcx> {
     fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
         // We've emitted a lint on some neighborhood expression. That lint will suggest to move out the
         // _parent_ expression (not the expression itself). Since we decide to move out the parent
@@ -495,7 +495,7 @@ fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &[&'tcx Expr
     helper.found_sig_drop_spans
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for ArmSigDropHelper<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for ArmSigDropHelper<'_, 'tcx> {
     fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
         if self.sig_drop_checker.is_sig_drop_expr(ex) {
             self.found_sig_drop_spans.insert(ex.span);
diff --git a/src/tools/clippy/clippy_lints/src/matches/wild_in_or_pats.rs b/src/tools/clippy/clippy_lints/src/matches/wild_in_or_pats.rs
index 459513e65bf..390ba889fd2 100644
--- a/src/tools/clippy/clippy_lints/src/matches/wild_in_or_pats.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/wild_in_or_pats.rs
@@ -1,11 +1,19 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::is_wild;
-use rustc_hir::{Arm, PatKind};
+use clippy_utils::{has_non_exhaustive_attr, is_wild};
+use rustc_hir::{Arm, Expr, PatKind};
 use rustc_lint::LateContext;
+use rustc_middle::ty;
 
 use super::WILDCARD_IN_OR_PATTERNS;
 
-pub(crate) fn check(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
+pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arms: &[Arm<'_>]) {
+    // first check if we are matching on an enum that has the non_exhaustive attribute
+    let ty = cx.typeck_results().expr_ty(expr).peel_refs();
+    if let ty::Adt(adt_def, _) = ty.kind()
+        && has_non_exhaustive_attr(cx.tcx, *adt_def)
+    {
+        return;
+    };
     for arm in arms {
         if let PatKind::Or(fields) = arm.pat.kind {
             // look for multiple fields in this arm that contains at least one Wild pattern
diff --git a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
index 83e8370f939..320523aceb6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
@@ -1,17 +1,17 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::expr_custom_deref_adjustment;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Mutability};
 use rustc_lint::LateContext;
-use rustc_middle::ty;
 use rustc_span::{Span, sym};
 
 use super::MUT_MUTEX_LOCK;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) {
     if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut))
-        && let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind()
+        && let (_, ref_depth, Mutability::Mut) = peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(recv))
+        && ref_depth >= 1
         && let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id)
         && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
         && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Mutex)
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 421c7a5e070..c58e27e37ad 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -441,7 +441,7 @@ struct UsedCountVisitor<'a, 'tcx> {
     count: usize,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for UsedCountVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
index b160ab6de8e..528e2204cf8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -130,7 +130,7 @@ struct UnwrapVisitor<'a, 'tcx> {
     identifiers: FxHashSet<HirId>,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for UnwrapVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::All;
 
     fn visit_path(&mut self, path: &Path<'tcx>, _: HirId) {
@@ -154,7 +154,7 @@ struct ReferenceVisitor<'a, 'tcx> {
     unwrap_or_span: Span,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for ReferenceVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for ReferenceVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::All;
     type Result = ControlFlow<()>;
     fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'_>) -> ControlFlow<()> {
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index c60a839432c..b971f60d416 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -77,7 +77,7 @@ pub(super) fn check<'tcx>(
         let Some(suggested_method_def_id) = receiver_ty.ty_adt_def().and_then(|adt_def| {
             cx.tcx
                 .inherent_impls(adt_def.did())
-                .into_iter()
+                .iter()
                 .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg))
                 .find_map(|assoc| {
                     if assoc.fn_has_self_parameter
diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs
index 4e33dc1df54..cf0ee569f13 100644
--- a/src/tools/clippy/clippy_lints/src/methods/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs
@@ -86,7 +86,7 @@ struct CloneOrCopyVisitor<'cx, 'tcx> {
     references_to_binding: Vec<(Span, String)>,
 }
 
-impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
+impl<'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
     fn nested_visit_map(&mut self) -> Self::Map {
@@ -123,7 +123,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
     }
 }
 
-impl<'cx, 'tcx> CloneOrCopyVisitor<'cx, 'tcx> {
+impl<'tcx> CloneOrCopyVisitor<'_, 'tcx> {
     fn is_binding(&self, expr: &Expr<'tcx>) -> bool {
         self.binding_hir_ids
             .iter()
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 64fc1a8a1a5..007bcebdff6 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -193,8 +193,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             | hir::ItemKind::Trait(..)
             | hir::ItemKind::TraitAlias(..)
             | hir::ItemKind::TyAlias(..)
-            | hir::ItemKind::Union(..)
-            | hir::ItemKind::OpaqueTy(..) => {},
+            | hir::ItemKind::Union(..) => {}
             hir::ItemKind::ExternCrate(..)
             | hir::ItemKind::ForeignMod { .. }
             | hir::ItemKind::GlobalAsm(..)
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index d342be4545c..f95a0f63fab 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -130,7 +130,6 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
             | hir::ItemKind::GlobalAsm(..)
             | hir::ItemKind::TyAlias(..)
             | hir::ItemKind::Union(..)
-            | hir::ItemKind::OpaqueTy(..)
             | hir::ItemKind::ExternCrate(..)
             | hir::ItemKind::ForeignMod { .. }
             | hir::ItemKind::Impl { .. }
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index d333b71edb1..a7452c8a3c8 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -116,7 +116,7 @@ struct DivergenceVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
 }
 
-impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
+impl<'tcx> DivergenceVisitor<'_, 'tcx> {
     fn maybe_walk_expr(&mut self, e: &'tcx Expr<'_>) {
         match e.kind {
             ExprKind::Closure(..) | ExprKind::If(..) | ExprKind::Loop(..) => {},
@@ -148,7 +148,7 @@ fn stmt_might_diverge(stmt: &Stmt<'_>) -> bool {
     !matches!(stmt.kind, StmtKind::Item(..))
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for DivergenceVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         match e.kind {
             // fix #10776
@@ -321,7 +321,7 @@ struct ReadVisitor<'a, 'tcx> {
     last_expr: &'tcx Expr<'tcx>,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for ReadVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if expr.hir_id == self.last_expr.hir_id {
             return;
diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs
index 60372121a7a..6cddd7ea813 100644
--- a/src/tools/clippy/clippy_lints/src/mut_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs
@@ -55,7 +55,7 @@ pub struct MutVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
 }
 
-impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
+impl<'tcx> intravisit::Visitor<'tcx> for MutVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
         if in_external_macro(self.cx.sess(), expr.span) {
             return;
diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
index 785bf70a3ec..152635a5c35 100644
--- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
+++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
@@ -87,7 +87,7 @@ impl<'a, 'tcx> MutArgVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for MutArgVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index b54eb164e81..93e20f37ef8 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -133,7 +133,7 @@ struct RetCollector {
     loop_depth: u16,
 }
 
-impl<'tcx> Visitor<'tcx> for RetCollector {
+impl Visitor<'_> for RetCollector {
     fn visit_expr(&mut self, expr: &Expr<'_>) {
         match expr.kind {
             ExprKind::Ret(..) => {
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index 19cbf595908..c2facb2fcf6 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -311,7 +311,7 @@ struct MutablyUsedVariablesCtxt<'tcx> {
     tcx: TyCtxt<'tcx>,
 }
 
-impl<'tcx> MutablyUsedVariablesCtxt<'tcx> {
+impl MutablyUsedVariablesCtxt<'_> {
     fn add_mutably_used_var(&mut self, used_id: HirId) {
         self.mutably_used_vars.insert(used_id);
     }
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index d85032e9eee..2fee1c72a91 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -104,7 +104,7 @@ struct SimilarNamesLocalVisitor<'a, 'tcx> {
     single_char_names: Vec<Vec<Ident>>,
 }
 
-impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> {
+impl SimilarNamesLocalVisitor<'_, '_> {
     fn check_single_char_names(&self) {
         if self.single_char_names.last().map(Vec::len) == Some(0) {
             return;
@@ -152,7 +152,7 @@ fn chars_are_similar(a: char, b: char) -> bool {
 
 struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>);
 
-impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
+impl<'tcx> Visitor<'tcx> for SimilarNamesNameVisitor<'_, 'tcx, '_> {
     fn visit_pat(&mut self, pat: &'tcx Pat) {
         match pat.kind {
             PatKind::Ident(_, ident, _) => {
@@ -189,7 +189,7 @@ fn allowed_to_be_similar(interned_name: &str, list: &[&str]) -> bool {
         .any(|&name| interned_name.starts_with(name) || interned_name.ends_with(name))
 }
 
-impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
+impl SimilarNamesNameVisitor<'_, '_, '_> {
     fn check_short_ident(&mut self, ident: Ident) {
         // Ignore shadowing
         if self
@@ -329,7 +329,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
     }
 }
 
-impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> {
+impl SimilarNamesLocalVisitor<'_, '_> {
     /// ensure scoping rules work
     fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
         let n = self.names.len();
@@ -340,7 +340,7 @@ impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'_, 'tcx> {
     fn visit_local(&mut self, local: &'tcx Local) {
         if let Some((init, els)) = &local.kind.init_else_opt() {
             self.apply(|this| walk_expr(this, init));
diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
index a60988ac5db..793eb5d9456 100644
--- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -159,7 +159,7 @@ struct NonSendField<'tcx> {
     generic_params: Vec<Ty<'tcx>>,
 }
 
-impl<'tcx> NonSendField<'tcx> {
+impl NonSendField<'_> {
     fn generic_params_string(&self) -> String {
         self.generic_params
             .iter()
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 75d8c09f2b0..1bddfab39c6 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -110,7 +110,7 @@ pub struct PassByRefOrValue {
     avoid_breaking_exported_api: bool,
 }
 
-impl<'tcx> PassByRefOrValue {
+impl PassByRefOrValue {
     pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
         let ref_min_size = conf.trivial_copy_size_limit.unwrap_or_else(|| {
             let bit_width = u64::from(tcx.sess.target.pointer_width);
@@ -130,7 +130,7 @@ impl<'tcx> PassByRefOrValue {
         }
     }
 
-    fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option<Span>) {
+    fn check_poly_fn(&mut self, cx: &LateContext<'_>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option<Span>) {
         if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
index 1b9a5a44382..9f84686a0b1 100644
--- a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
@@ -60,7 +60,7 @@ struct PathbufPushSearcher<'tcx> {
     err_span: Span,
 }
 
-impl<'tcx> PathbufPushSearcher<'tcx> {
+impl PathbufPushSearcher<'_> {
     /// Try to generate a suggestion with `PathBuf::from`.
     /// Returns `None` if the suggestion would be invalid.
     fn gen_pathbuf_from(&self, cx: &LateContext<'_>) -> Option<String> {
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 807636bb642..bb8a9b6fca8 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -271,14 +271,18 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id()
         && let Some(name) = cx.tcx.get_diagnostic_name(fun_def_id)
     {
+        // TODO: `ptr_slice_from_raw_parts` and its mutable variant should probably still be linted
+        // conditionally based on how the return value is used, but not universally like the other
+        // functions since there are valid uses for null slice pointers.
+        //
+        // See: https://github.com/rust-lang/rust-clippy/pull/13452/files#r1773772034
+
         // `arg` positions where null would cause U.B.
         let arg_indices: &[_] = match name {
             sym::ptr_read
             | sym::ptr_read_unaligned
             | sym::ptr_read_volatile
             | sym::ptr_replace
-            | sym::ptr_slice_from_raw_parts
-            | sym::ptr_slice_from_raw_parts_mut
             | sym::ptr_write
             | sym::ptr_write_bytes
             | sym::ptr_write_unaligned
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index 6930a01d48b..41a44de536b 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -228,7 +228,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
                 path: &'tcx hir::Path<'tcx>,
                 count: usize,
             }
-            impl<'a, 'tcx> Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> {
+            impl<'tcx> Visitor<'tcx> for ClosureUsageCount<'_, 'tcx> {
                 type NestedFilter = nested_filter::OnlyBodies;
 
                 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 3754fdddedf..1f223048ce5 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -140,7 +140,7 @@ enum RetReplacement<'tcx> {
     Expr(Cow<'tcx, str>, Applicability),
 }
 
-impl<'tcx> RetReplacement<'tcx> {
+impl RetReplacement<'_> {
     fn sugg_help(&self) -> &'static str {
         match self {
             Self::Empty | Self::Expr(..) => "remove `return`",
@@ -158,7 +158,7 @@ impl<'tcx> RetReplacement<'tcx> {
     }
 }
 
-impl<'tcx> Display for RetReplacement<'tcx> {
+impl Display for RetReplacement<'_> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
             Self::Empty => write!(f, ""),
@@ -421,7 +421,7 @@ fn check_final_expr<'tcx>(
                     if matches!(Level::from_attr(attr), Some(Level::Expect(_)))
                         && let metas = attr.meta_item_list()
                         && let Some(lst) = metas
-                        && let [NestedMetaItem::MetaItem(meta_item)] = lst.as_slice()
+                        && let [NestedMetaItem::MetaItem(meta_item), ..] = lst.as_slice()
                         && let [tool, lint_name] = meta_item.path.segments.as_slice()
                         && tool.ident.name == sym::clippy
                         && matches!(
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
index d1114cb29f7..0eece922143 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -249,7 +249,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx
     }
 }
 
-impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx> {
+impl<'tcx> Visitor<'tcx> for StmtsChecker<'_, '_, '_, '_, 'tcx> {
     fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
         self.ap.curr_block_hir_id = block.hir_id;
         self.ap.curr_block_span = block.span;
diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
index c986c3e8aa6..9fdee8543a8 100644
--- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
@@ -102,7 +102,7 @@ struct ImportUsageVisitor {
     imports_referenced_with_self: Vec<Symbol>,
 }
 
-impl<'tcx> Visitor<'tcx> for ImportUsageVisitor {
+impl Visitor<'_> for ImportUsageVisitor {
     fn visit_expr(&mut self, expr: &Expr) {
         if let ExprKind::Path(_, path) = &expr.kind
             && path.segments.len() > 1
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index 5129bbf2665..fc799cad67e 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -229,7 +229,7 @@ struct VectorInitializationVisitor<'a, 'tcx> {
     initialization_found: bool,
 }
 
-impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
+impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
     /// Checks if the given expression is extending a vector with `repeat(0).take(..)`
     fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) {
         if self.initialization_found
@@ -299,7 +299,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for VectorInitializationVisitor<'_, 'tcx> {
     fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
         if self.initialization_found {
             match stmt.kind {
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index e05fa4095b8..a3145c4647c 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -332,7 +332,7 @@ struct IndexBinding<'a, 'tcx> {
     applicability: &'a mut Applicability,
 }
 
-impl<'a, 'tcx> IndexBinding<'a, 'tcx> {
+impl<'tcx> IndexBinding<'_, 'tcx> {
     fn snippet_index_bindings(&mut self, exprs: &[&'tcx Expr<'tcx>]) -> String {
         let mut bindings = FxHashSet::default();
         for expr in exprs {
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 104be63bb15..c7c837de505 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -275,12 +275,15 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
             |k, ps1, idx| matches!(
                 k,
                 TupleStruct(qself2, path2, ps2)
-                    if eq_maybe_qself(qself1, qself2) && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
+                    if eq_maybe_qself(qself1.as_ref(), qself2.as_ref())
+                       && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
             ),
             |k| always_pat!(k, TupleStruct(_, _, ps) => ps),
         ),
         // Transform a record pattern `S { fp_0, ..., fp_n }`.
-        Struct(qself1, path1, fps1, rest1) => extend_with_struct_pat(qself1, path1, fps1, *rest1, start, alternatives),
+        Struct(qself1, path1, fps1, rest1) => {
+            extend_with_struct_pat(qself1.as_ref(), path1, fps1, *rest1, start, alternatives)
+        },
     };
 
     alternatives[focus_idx].kind = focus_kind;
@@ -292,7 +295,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
 /// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern
 /// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal.
 fn extend_with_struct_pat(
-    qself1: &Option<P<ast::QSelf>>,
+    qself1: Option<&P<ast::QSelf>>,
     path1: &ast::Path,
     fps1: &mut [ast::PatField],
     rest1: ast::PatFieldsRest,
@@ -307,7 +310,7 @@ fn extend_with_struct_pat(
             |k| {
                 matches!(k, Struct(qself2, path2, fps2, rest2)
                 if rest1 == *rest2 // If one struct pattern has `..` so must the other.
-                && eq_maybe_qself(qself1, qself2)
+                && eq_maybe_qself(qself1, qself2.as_ref())
                 && eq_path(path1, path2)
                 && fps1.len() == fps2.len()
                 && fps1.iter().enumerate().all(|(idx_1, fp1)| {
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index a1f08cf6623..c899b1868a6 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::is_def_id_trait_method;
 use rustc_hir::def::DefKind;
 use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn};
-use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource};
+use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Node, YieldSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_session::impl_lint_pass;
@@ -67,7 +67,7 @@ struct AsyncFnVisitor<'a, 'tcx> {
     async_depth: usize,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for AsyncFnVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
@@ -137,17 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
         }
     }
 
-    fn check_path(&mut self, cx: &LateContext<'tcx>, path: &rustc_hir::Path<'tcx>, hir_id: rustc_hir::HirId) {
-        fn is_node_func_call(node: Node<'_>, expected_receiver: Span) -> bool {
-            matches!(
-                node,
-                Node::Expr(Expr {
-                    kind: ExprKind::Call(Expr { span, .. }, _) | ExprKind::MethodCall(_, Expr { span, .. }, ..),
-                    ..
-                }) if *span == expected_receiver
-            )
-        }
-
+    fn check_path(&mut self, cx: &LateContext<'tcx>, path: &rustc_hir::Path<'tcx>, hir_id: HirId) {
         // Find paths to local async functions that aren't immediately called.
         // E.g. `async fn f() {}; let x = f;`
         // Depending on how `x` is used, f's asyncness might be required despite not having any `await`
@@ -156,7 +146,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
             && let Some(local_def_id) = def_id.as_local()
             && cx.tcx.def_kind(def_id) == DefKind::Fn
             && cx.tcx.asyncness(def_id).is_async()
-            && !is_node_func_call(cx.tcx.parent_hir_node(hir_id), path.span)
+            && let parent = cx.tcx.parent_hir_node(hir_id)
+            && !matches!(
+                parent,
+                Node::Expr(Expr {
+                    kind: ExprKind::Call(Expr { span, .. }, _),
+                    ..
+                }) if *span == path.span
+            )
         {
             self.async_fns_as_value.insert(local_def_id);
         }
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index 596f0fd9c8b..6fe660b6a47 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -235,7 +235,7 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> {
     fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
 }
 
-impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> {
+impl<'tcx> UnwrappableVariablesVisitor<'_, 'tcx> {
     fn visit_branch(
         &mut self,
         if_expr: &'tcx Expr<'_>,
@@ -288,7 +288,7 @@ fn consume_option_as_ref<'tcx>(expr: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, Opt
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index e340b419bd0..f5cf4a586fd 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -85,10 +85,6 @@ const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";
 
 impl<'tcx> LateLintPass<'tcx> for UseSelf {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
-        if matches!(item.kind, ItemKind::OpaqueTy(_)) {
-            // skip over `ItemKind::OpaqueTy` in order to lint `foo() -> impl <..>`
-            return;
-        }
         // We push the self types of `impl`s on a stack here. Only the top type on the stack is
         // relevant for linting, since this is the self type of the `impl` we're currently in. To
         // avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal, that
@@ -130,10 +126,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
         self.stack.push(stack_item);
     }
 
-    fn check_item_post(&mut self, _: &LateContext<'_>, item: &Item<'_>) {
-        if !matches!(item.kind, ItemKind::OpaqueTy(_)) {
-            self.stack.pop();
-        }
+    fn check_item_post(&mut self, _: &LateContext<'_>, _: &Item<'_>) {
+        self.stack.pop();
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
@@ -280,7 +274,7 @@ struct SkipTyCollector {
     types_to_skip: Vec<HirId>,
 }
 
-impl<'tcx> Visitor<'tcx> for SkipTyCollector {
+impl Visitor<'_> for SkipTyCollector {
     fn visit_infer(&mut self, inf: &hir::InferArg) {
         self.types_to_skip.push(inf.hir_id);
 
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
index 7c2e23995c1..9e400d2391f 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
@@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
                         && let ty = cx.tcx.type_of(item_def_id).instantiate_identity()
                         && match_type(cx, ty, &paths::SYMBOL)
                         && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id)
-                        && let Ok(value) = value.to_u32()
+                        && let Some(value) = value.to_u32().discard_err()
                     {
                         self.symbol_map.insert(value, item_def_id);
                     }
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
index d444ad45087..96397375d5e 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -72,8 +72,7 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
         SimplifiedType::Bool,
     ]
     .iter()
-    .flat_map(|&ty| cx.tcx.incoherent_impls(ty).into_iter())
-    .flatten()
+    .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter())
     .copied();
     for item_def_id in lang_items.iter().map(|(_, def_id)| def_id).chain(incoherent_impls) {
         let lang_item_path = cx.get_def_path(item_def_id);
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
index 7c45a5b2f09..dd456022212 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
@@ -270,7 +270,7 @@ struct LintCollector<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for LintCollector<'_, 'tcx> {
     type NestedFilter = nested_filter::All;
 
     fn visit_path(&mut self, path: &Path<'_>, _: HirId) {
diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
index ba2a80ee66b..8d9241cc7d9 100644
--- a/src/tools/clippy/clippy_lints/src/zombie_processes.rs
+++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
@@ -6,6 +6,7 @@ use rustc_errors::Applicability;
 use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_local};
 use rustc_hir::{Expr, ExprKind, HirId, LetStmt, Node, PatKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::nested_filter;
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
 use std::ops::ControlFlow;
@@ -118,7 +119,8 @@ enum WaitFinder<'a, 'tcx> {
     Found(&'a LateContext<'tcx>, HirId),
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for WaitFinder<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> {
+    type NestedFilter = nested_filter::OnlyBodies;
     type Result = ControlFlow<BreakReason>;
 
     fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) -> Self::Result {
@@ -204,6 +206,11 @@ impl<'a, 'tcx> Visitor<'tcx> for WaitFinder<'a, 'tcx> {
 
         walk_expr(self, ex)
     }
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        let (Self::Found(cx, _) | Self::WalkUpTo(cx, _)) = self;
+        cx.tcx.hir()
+    }
 }
 
 /// This function has shared logic between the different kinds of nodes that can trigger the lint.
@@ -300,7 +307,7 @@ struct ExitPointFinder<'a, 'tcx> {
 
 struct ExitCallFound;
 
-impl<'a, 'tcx> Visitor<'tcx> for ExitPointFinder<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for ExitPointFinder<'_, 'tcx> {
     type Result = ControlFlow<ExitCallFound>;
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result {
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 49323492e12..68f74e52ed7 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -37,20 +37,27 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
         (_, Paren(r)) => eq_pat(l, r),
         (Wild, Wild) | (Rest, Rest) => true,
         (Lit(l), Lit(r)) => eq_expr(l, r),
-        (Ident(b1, i1, s1), Ident(b2, i2, s2)) => b1 == b2 && eq_id(*i1, *i2) && both(s1, s2, |l, r| eq_pat(l, r)),
+        (Ident(b1, i1, s1), Ident(b2, i2, s2)) => {
+            b1 == b2 && eq_id(*i1, *i2) && both(s1.as_deref(), s2.as_deref(), eq_pat)
+        },
         (Range(lf, lt, le), Range(rf, rt, re)) => {
-            eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt) && eq_range_end(&le.node, &re.node)
+            eq_expr_opt(lf.as_ref(), rf.as_ref())
+                && eq_expr_opt(lt.as_ref(), rt.as_ref())
+                && eq_range_end(&le.node, &re.node)
         },
         (Box(l), Box(r))
         | (Ref(l, Mutability::Not), Ref(r, Mutability::Not))
         | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r),
         (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)),
-        (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp),
+        (Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp),
         (TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => {
-            eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r))
+            eq_maybe_qself(lqself.as_ref(), rqself.as_ref()) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r))
         },
         (Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => {
-            lr == rr && eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && unordered_over(lfs, rfs, eq_field_pat)
+            lr == rr
+                && eq_maybe_qself(lqself.as_ref(), rqself.as_ref())
+                && eq_path(lp, rp)
+                && unordered_over(lfs, rfs, eq_field_pat)
         },
         (Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)),
         (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
@@ -79,7 +86,7 @@ pub fn eq_qself(l: &P<QSelf>, r: &P<QSelf>) -> bool {
     l.position == r.position && eq_ty(&l.ty, &r.ty)
 }
 
-pub fn eq_maybe_qself(l: &Option<P<QSelf>>, r: &Option<P<QSelf>>) -> bool {
+pub fn eq_maybe_qself(l: Option<&P<QSelf>>, r: Option<&P<QSelf>>) -> bool {
     match (l, r) {
         (Some(l), Some(r)) => eq_qself(l, r),
         (None, None) => true,
@@ -92,7 +99,7 @@ pub fn eq_path(l: &Path, r: &Path) -> bool {
 }
 
 pub fn eq_path_seg(l: &PathSegment, r: &PathSegment) -> bool {
-    eq_id(l.ident, r.ident) && both(&l.args, &r.args, |l, r| eq_generic_args(l, r))
+    eq_id(l.ident, r.ident) && both(l.args.as_ref(), r.args.as_ref(), |l, r| eq_generic_args(l, r))
 }
 
 pub fn eq_generic_args(l: &GenericArgs, r: &GenericArgs) -> bool {
@@ -122,7 +129,7 @@ pub fn eq_generic_arg(l: &GenericArg, r: &GenericArg) -> bool {
     }
 }
 
-pub fn eq_expr_opt(l: &Option<P<Expr>>, r: &Option<P<Expr>>) -> bool {
+pub fn eq_expr_opt(l: Option<&P<Expr>>, r: Option<&P<Expr>>) -> bool {
     both(l, r, |l, r| eq_expr(l, r))
 }
 
@@ -169,8 +176,12 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         (Lit(l), Lit(r)) => l == r,
         (Cast(l, lt), Cast(r, rt)) | (Type(l, lt), Type(r, rt)) => eq_expr(l, r) && eq_ty(lt, rt),
         (Let(lp, le, _, _), Let(rp, re, _, _)) => eq_pat(lp, rp) && eq_expr(le, re),
-        (If(lc, lt, le), If(rc, rt, re)) => eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le, re),
-        (While(lc, lt, ll), While(rc, rt, rl)) => eq_label(ll, rl) && eq_expr(lc, rc) && eq_block(lt, rt),
+        (If(lc, lt, le), If(rc, rt, re)) => {
+            eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref())
+        },
+        (While(lc, lt, ll), While(rc, rt, rl)) => {
+            eq_label(ll.as_ref(), rl.as_ref()) && eq_expr(lc, rc) && eq_block(lt, rt)
+        },
         (
             ForLoop {
                 pat: lp,
@@ -186,13 +197,13 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
                 label: rl,
                 kind: rk,
             },
-        ) => eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt) && lk == rk,
-        (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll, rl) && eq_block(lt, rt),
-        (Block(lb, ll), Block(rb, rl)) => eq_label(ll, rl) && eq_block(lb, rb),
+        ) => eq_label(ll.as_ref(), rl.as_ref()) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt) && lk == rk,
+        (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lt, rt),
+        (Block(lb, ll), Block(rb, rl)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lb, rb),
         (TryBlock(l), TryBlock(r)) => eq_block(l, r),
-        (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l, r),
-        (Break(ll, le), Break(rl, re)) => eq_label(ll, rl) && eq_expr_opt(le, re),
-        (Continue(ll), Continue(rl)) => eq_label(ll, rl),
+        (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l.as_ref(), r.as_ref()),
+        (Break(ll, le), Break(rl, re)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_expr_opt(le.as_ref(), re.as_ref()),
+        (Continue(ll), Continue(rl)) => eq_label(ll.as_ref(), rl.as_ref()),
         (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2, _), Index(r1, r2, _)) => {
             eq_expr(l1, r1) && eq_expr(l2, r2)
         },
@@ -227,12 +238,14 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
                 && eq_expr(le, re)
         },
         (Gen(lc, lb, lk, _), Gen(rc, rb, rk, _)) => lc == rc && eq_block(lb, rb) && lk == rk,
-        (Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt),
+        (Range(lf, lt, ll), Range(rf, rt, rl)) => {
+            ll == rl && eq_expr_opt(lf.as_ref(), rf.as_ref()) && eq_expr_opt(lt.as_ref(), rt.as_ref())
+        },
         (AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re),
-        (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp),
+        (Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp),
         (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
         (Struct(lse), Struct(rse)) => {
-            eq_maybe_qself(&lse.qself, &rse.qself)
+            eq_maybe_qself(lse.qself.as_ref(), rse.qself.as_ref())
                 && eq_path(&lse.path, &rse.path)
                 && eq_struct_rest(&lse.rest, &rse.rest)
                 && unordered_over(&lse.fields, &rse.fields, eq_field)
@@ -264,12 +277,12 @@ pub fn eq_field(l: &ExprField, r: &ExprField) -> bool {
 pub fn eq_arm(l: &Arm, r: &Arm) -> bool {
     l.is_placeholder == r.is_placeholder
         && eq_pat(&l.pat, &r.pat)
-        && eq_expr_opt(&l.body, &r.body)
-        && eq_expr_opt(&l.guard, &r.guard)
+        && eq_expr_opt(l.body.as_ref(), r.body.as_ref())
+        && eq_expr_opt(l.guard.as_ref(), r.guard.as_ref())
         && over(&l.attrs, &r.attrs, eq_attr)
 }
 
-pub fn eq_label(l: &Option<Label>, r: &Option<Label>) -> bool {
+pub fn eq_label(l: Option<&Label>, r: Option<&Label>) -> bool {
     both(l, r, |l, r| eq_id(l.ident, r.ident))
 }
 
@@ -282,7 +295,7 @@ pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool {
     match (&l.kind, &r.kind) {
         (Let(l), Let(r)) => {
             eq_pat(&l.pat, &r.pat)
-                && both(&l.ty, &r.ty, |l, r| eq_ty(l, r))
+                && both(l.ty.as_ref(), r.ty.as_ref(), |l, r| eq_ty(l, r))
                 && eq_local_kind(&l.kind, &r.kind)
                 && over(&l.attrs, &r.attrs, eq_attr)
         },
@@ -329,7 +342,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 expr: re,
                 safety: rs,
             }),
-        ) => lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le, re),
+        ) => lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()),
         (
             Const(box ConstItem {
                 defaultness: ld,
@@ -343,7 +356,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 ty: rt,
                 expr: re,
             }),
-        ) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le, re),
+        ) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()),
         (
             Fn(box ast::Fn {
                 defaultness: ld,
@@ -358,7 +371,10 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 body: rb,
             }),
         ) => {
-            eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
+            eq_defaultness(*ld, *rd)
+                && eq_fn_sig(lf, rf)
+                && eq_generics(lg, rg)
+                && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r))
         },
         (Mod(lu, lmk), Mod(ru, rmk)) => {
             lu == ru
@@ -371,7 +387,8 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 }
         },
         (ForeignMod(l), ForeignMod(r)) => {
-            both(&l.abi, &r.abi, eq_str_lit) && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))
+            both(l.abi.as_ref(), r.abi.as_ref(), eq_str_lit)
+                && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))
         },
         (
             TyAlias(box ast::TyAlias {
@@ -392,7 +409,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
             eq_defaultness(*ld, *rd)
                 && eq_generics(lg, rg)
                 && over(lb, rb, eq_generic_bound)
-                && both(lt, rt, |l, r| eq_ty(l, r))
+                && both(lt.as_ref(), rt.as_ref(), |l, r| eq_ty(l, r))
         },
         (Enum(le, lg), Enum(re, rg)) => over(&le.variants, &re.variants, eq_variant) && eq_generics(lg, rg),
         (Struct(lv, lg), Struct(rv, rg)) | (Union(lv, lg), Union(rv, rg)) => {
@@ -448,7 +465,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 && eq_defaultness(*ld, *rd)
                 && matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No)
                 && eq_generics(lg, rg)
-                && both(lot, rot, |l, r| eq_path(&l.path, &r.path))
+                && both(lot.as_ref(), rot.as_ref(), |l, r| eq_path(&l.path, &r.path))
                 && eq_ty(lst, rst)
                 && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind))
         },
@@ -474,7 +491,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
                 expr: re,
                 safety: rs,
             }),
-        ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re) && ls == rs,
+        ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()) && ls == rs,
         (
             Fn(box ast::Fn {
                 defaultness: ld,
@@ -489,7 +506,10 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
                 body: rb,
             }),
         ) => {
-            eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
+            eq_defaultness(*ld, *rd)
+                && eq_fn_sig(lf, rf)
+                && eq_generics(lg, rg)
+                && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r))
         },
         (
             TyAlias(box ast::TyAlias {
@@ -510,7 +530,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
             eq_defaultness(*ld, *rd)
                 && eq_generics(lg, rg)
                 && over(lb, rb, eq_generic_bound)
-                && both(lt, rt, |l, r| eq_ty(l, r))
+                && both(lt.as_ref(), rt.as_ref(), |l, r| eq_ty(l, r))
         },
         (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
         _ => false,
@@ -533,7 +553,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
                 ty: rt,
                 expr: re,
             }),
-        ) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le, re),
+        ) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()),
         (
             Fn(box ast::Fn {
                 defaultness: ld,
@@ -548,7 +568,10 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
                 body: rb,
             }),
         ) => {
-            eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
+            eq_defaultness(*ld, *rd)
+                && eq_fn_sig(lf, rf)
+                && eq_generics(lg, rg)
+                && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r))
         },
         (
             Type(box TyAlias {
@@ -569,7 +592,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
             eq_defaultness(*ld, *rd)
                 && eq_generics(lg, rg)
                 && over(lb, rb, eq_generic_bound)
-                && both(lt, rt, |l, r| eq_ty(l, r))
+                && both(lt.as_ref(), rt.as_ref(), |l, r| eq_ty(l, r))
         },
         (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
         _ => false,
@@ -582,7 +605,9 @@ pub fn eq_variant(l: &Variant, r: &Variant) -> bool {
         && eq_vis(&l.vis, &r.vis)
         && eq_id(l.ident, r.ident)
         && eq_variant_data(&l.data, &r.data)
-        && both(&l.disr_expr, &r.disr_expr, |l, r| eq_expr(&l.value, &r.value))
+        && both(l.disr_expr.as_ref(), r.disr_expr.as_ref(), |l, r| {
+            eq_expr(&l.value, &r.value)
+        })
 }
 
 pub fn eq_variant_data(l: &VariantData, r: &VariantData) -> bool {
@@ -600,7 +625,7 @@ pub fn eq_struct_field(l: &FieldDef, r: &FieldDef) -> bool {
     l.is_placeholder == r.is_placeholder
         && over(&l.attrs, &r.attrs, eq_attr)
         && eq_vis(&l.vis, &r.vis)
-        && both(&l.ident, &r.ident, |l, r| eq_id(*l, *r))
+        && both(l.ident.as_ref(), r.ident.as_ref(), |l, r| eq_id(*l, *r))
         && eq_ty(&l.ty, &r.ty)
 }
 
@@ -664,7 +689,7 @@ pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool {
     use UseTreeKind::*;
     match (l, r) {
         (Glob, Glob) => true,
-        (Simple(l), Simple(r)) => both(l, r, |l, r| eq_id(*l, *r)),
+        (Simple(l), Simple(r)) => both(l.as_ref(), r.as_ref(), |l, r| eq_id(*l, *r)),
         (Nested { items: l, .. }, Nested { items: r, .. }) => over(l, r, |(l, _), (r, _)| eq_use_tree(l, r)),
         _ => false,
     }
@@ -726,7 +751,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
         (Array(le, ls), Array(re, rs)) => eq_ty(le, re) && eq_expr(&ls.value, &rs.value),
         (Ptr(l), Ptr(r)) => l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty),
         (Ref(ll, l), Ref(rl, r)) => {
-            both(ll, rl, |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty)
+            both(ll.as_ref(), rl.as_ref(), |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty)
         },
         (BareFn(l), BareFn(r)) => {
             l.safety == r.safety
@@ -735,7 +760,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
                 && eq_fn_decl(&l.decl, &r.decl)
         },
         (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)),
-        (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp),
+        (Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp),
         (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound),
         (ImplTrait(_, lg), ImplTrait(_, rg)) => over(lg, rg, eq_generic_bound),
         (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value),
@@ -771,7 +796,7 @@ pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool {
         && over(&l.bounds, &r.bounds, eq_generic_bound)
         && match (&l.kind, &r.kind) {
             (Lifetime, Lifetime) => true,
-            (Type { default: l }, Type { default: r }) => both(l, r, |l, r| eq_ty(l, r)),
+            (Type { default: l }, Type { default: r }) => both(l.as_ref(), r.as_ref(), |l, r| eq_ty(l, r)),
             (
                 Const {
                     ty: lt,
@@ -783,7 +808,7 @@ pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool {
                     kw_span: _,
                     default: rd,
                 },
-            ) => eq_ty(lt, rt) && both(ld, rd, eq_anon_const),
+            ) => eq_ty(lt, rt) && both(ld.as_ref(), rd.as_ref(), eq_anon_const),
             _ => false,
         }
         && over(&l.attrs, &r.attrs, eq_attr)
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 9143d292f67..b18997e6ee4 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -220,7 +220,7 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) {
         ItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
         ItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
         ItemKind::ForeignMod { .. } => (Pat::Str("extern"), Pat::Str("}")),
-        ItemKind::TyAlias(..) | ItemKind::OpaqueTy(_) => (Pat::Str("type"), Pat::Str(";")),
+        ItemKind::TyAlias(..) => (Pat::Str("type"), Pat::Str(";")),
         ItemKind::Enum(..) => (Pat::Str("enum"), Pat::Str("}")),
         ItemKind::Struct(VariantData::Struct { .. }, _) => (Pat::Str("struct"), Pat::Str("}")),
         ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")),
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index bf47cf6d372..510034876e0 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -118,7 +118,7 @@ impl IntTypeBounds for IntTy {
     }
 }
 
-impl<'tcx> PartialEq for Constant<'tcx> {
+impl PartialEq for Constant<'_> {
     fn eq(&self, other: &Self) -> bool {
         match (self, other) {
             (Self::Str(ls), Self::Str(rs)) => ls == rs,
@@ -147,7 +147,7 @@ impl<'tcx> PartialEq for Constant<'tcx> {
     }
 }
 
-impl<'tcx> Hash for Constant<'tcx> {
+impl Hash for Constant<'_> {
     fn hash<H>(&self, state: &mut H)
     where
         H: Hasher,
@@ -203,7 +203,7 @@ impl<'tcx> Hash for Constant<'tcx> {
     }
 }
 
-impl<'tcx> Constant<'tcx> {
+impl Constant<'_> {
     pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self) -> Option<Ordering> {
         match (left, right) {
             (Self::Str(ls), Self::Str(rs)) => Some(ls.cmp(rs)),
@@ -870,10 +870,10 @@ pub fn mir_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option
                 let range = alloc_range(offset + size * idx, size);
                 let val = alloc.read_scalar(&tcx, range, /* read_provenance */ false).ok()?;
                 res.push(match flt {
-                    FloatTy::F16 => Constant::F16(f16::from_bits(val.to_u16().ok()?)),
-                    FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().ok()?)),
-                    FloatTy::F64 => Constant::F64(f64::from_bits(val.to_u64().ok()?)),
-                    FloatTy::F128 => Constant::F128(f128::from_bits(val.to_u128().ok()?)),
+                    FloatTy::F16 => Constant::F16(f16::from_bits(val.to_u16().discard_err()?)),
+                    FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().discard_err()?)),
+                    FloatTy::F64 => Constant::F64(f64::from_bits(val.to_u64().discard_err()?)),
+                    FloatTy::F128 => Constant::F128(f128::from_bits(val.to_u128().discard_err()?)),
                 });
             }
             Some(Constant::Vec(res))
@@ -903,7 +903,7 @@ fn mir_is_empty<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option<boo
                         .read_scalar(&tcx, alloc_range(offset + ptr_size, ptr_size), false)
                         .ok()?
                         .to_target_usize(&tcx)
-                        .ok()?;
+                        .discard_err()?;
                     Some(len == 0)
                 } else {
                     None
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 9420d84b959..a2e97919d04 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -118,7 +118,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
         eagerness: EagernessSuggestion,
     }
 
-    impl<'cx, 'tcx> Visitor<'tcx> for V<'cx, 'tcx> {
+    impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
         fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             use EagernessSuggestion::{ForceNoChange, Lazy, NoChange};
             if self.eagerness == ForceNoChange {
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 76900379ac7..a19c1555d16 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -121,9 +121,9 @@ impl HirEqInterExpr<'_, '_, '_> {
 
                 // eq_pat adds the HirIds to the locals map. We therefore call it last to make sure that
                 // these only get added if the init and type is equal.
-                both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
-                    && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r))
-                    && both(&l.els, &r.els, |l, r| self.eq_block(l, r))
+                both(l.init.as_ref(), r.init.as_ref(), |l, r| self.eq_expr(l, r))
+                    && both(l.ty.as_ref(), r.ty.as_ref(), |l, r| self.eq_ty(l, r))
+                    && both(l.els.as_ref(), r.els.as_ref(), |l, r| self.eq_block(l, r))
                     && self.eq_pat(l.pat, r.pat)
             },
             (&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r),
@@ -142,7 +142,9 @@ impl HirEqInterExpr<'_, '_, '_> {
         if lspan.ctxt != SyntaxContext::root() && rspan.ctxt != SyntaxContext::root() {
             // Don't try to check in between statements inside macros.
             return over(left.stmts, right.stmts, |left, right| self.eq_stmt(left, right))
-                && both(&left.expr, &right.expr, |left, right| self.eq_expr(left, right));
+                && both(left.expr.as_ref(), right.expr.as_ref(), |left, right| {
+                    self.eq_expr(left, right)
+                });
         }
         if lspan.ctxt != rspan.ctxt {
             return false;
@@ -285,8 +287,8 @@ impl HirEqInterExpr<'_, '_, '_> {
                     })
             },
             (&ExprKind::Break(li, ref le), &ExprKind::Break(ri, ref re)) => {
-                both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
-                    && both(le, re, |l, r| self.eq_expr(l, r))
+                both(li.label.as_ref(), ri.label.as_ref(), |l, r| l.ident.name == r.ident.name)
+                    && both(le.as_ref(), re.as_ref(), |l, r| self.eq_expr(l, r))
             },
             (&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => {
                 self.inner.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
@@ -297,7 +299,7 @@ impl HirEqInterExpr<'_, '_, '_> {
             (&ExprKind::Closure(_l), &ExprKind::Closure(_r)) => false,
             (&ExprKind::ConstBlock(lb), &ExprKind::ConstBlock(rb)) => self.eq_body(lb.body, rb.body),
             (&ExprKind::Continue(li), &ExprKind::Continue(ri)) => {
-                both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
+                both(li.label.as_ref(), ri.label.as_ref(), |l, r| l.ident.name == r.ident.name)
             },
             (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re),
             (&ExprKind::Field(l_f_exp, ref l_f_ident), &ExprKind::Field(r_f_exp, ref r_f_ident)) => {
@@ -305,21 +307,25 @@ impl HirEqInterExpr<'_, '_, '_> {
             },
             (&ExprKind::Index(la, li, _), &ExprKind::Index(ra, ri, _)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
             (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
-                self.eq_expr(lc, rc) && self.eq_expr(lt, rt) && both(le, re, |l, r| self.eq_expr(l, r))
+                self.eq_expr(lc, rc) && self.eq_expr(lt, rt)
+                    && both(le.as_ref(), re.as_ref(), |l, r| self.eq_expr(l, r))
             },
             (&ExprKind::Let(l), &ExprKind::Let(r)) => {
-                self.eq_pat(l.pat, r.pat) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && self.eq_expr(l.init, r.init)
+                self.eq_pat(l.pat, r.pat)
+                    && both(l.ty.as_ref(), r.ty.as_ref(), |l, r| self.eq_ty(l, r))
+                    && self.eq_expr(l.init, r.init)
             },
             (ExprKind::Lit(l), ExprKind::Lit(r)) => l.node == r.node,
             (&ExprKind::Loop(lb, ref ll, ref lls, _), &ExprKind::Loop(rb, ref rl, ref rls, _)) => {
-                lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
+                lls == rls && self.eq_block(lb, rb)
+                    && both(ll.as_ref(), rl.as_ref(), |l, r| l.ident.name == r.ident.name)
             },
             (&ExprKind::Match(le, la, ref ls), &ExprKind::Match(re, ra, ref rs)) => {
                 (ls == rs || (matches!((ls, rs), (TryDesugar(_), TryDesugar(_)))))
                     && self.eq_expr(le, re)
                     && over(la, ra, |l, r| {
                         self.eq_pat(l.pat, r.pat)
-                            && both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r))
+                            && both(l.guard.as_ref(), r.guard.as_ref(), |l, r| self.eq_expr(l, r))
                             && self.eq_expr(l.body, r.body)
                     })
             },
@@ -339,10 +345,10 @@ impl HirEqInterExpr<'_, '_, '_> {
             (&ExprKind::Repeat(le, ll), &ExprKind::Repeat(re, rl)) => {
                 self.eq_expr(le, re) && self.eq_array_length(ll, rl)
             },
-            (ExprKind::Ret(l), ExprKind::Ret(r)) => both(l, r, |l, r| self.eq_expr(l, r)),
+            (ExprKind::Ret(l), ExprKind::Ret(r)) => both(l.as_ref(), r.as_ref(), |l, r| self.eq_expr(l, r)),
             (&ExprKind::Struct(l_path, lf, ref lo), &ExprKind::Struct(r_path, rf, ref ro)) => {
                 self.eq_qpath(l_path, r_path)
-                    && both(lo, ro, |l, r| self.eq_expr(l, r))
+                    && both(lo.as_ref(), ro.as_ref(), |l, r| self.eq_expr(l, r))
                     && over(lf, rf, |l, r| self.eq_expr_field(l, r))
             },
             (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup),
@@ -450,7 +456,7 @@ impl HirEqInterExpr<'_, '_, '_> {
                 self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
             },
             (&PatKind::Binding(lb, li, _, ref lp), &PatKind::Binding(rb, ri, _, ref rp)) => {
-                let eq = lb == rb && both(lp, rp, |l, r| self.eq_pat(l, r));
+                let eq = lb == rb && both(lp.as_ref(), rp.as_ref(), |l, r| self.eq_pat(l, r));
                 if eq {
                     self.locals.insert(li, ri);
                 }
@@ -460,13 +466,15 @@ impl HirEqInterExpr<'_, '_, '_> {
             (&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_expr(l, r),
             (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
             (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
-                both(ls, rs, |a, b| self.eq_expr(a, b)) && both(le, re, |a, b| self.eq_expr(a, b)) && (li == ri)
+                both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_expr(a, b))
+                    && both(le.as_ref(), re.as_ref(), |a, b| self.eq_expr(a, b))
+                    && (li == ri)
             },
             (&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re),
             (&PatKind::Slice(ls, ref li, le), &PatKind::Slice(rs, ref ri, re)) => {
                 over(ls, rs, |l, r| self.eq_pat(l, r))
                     && over(le, re, |l, r| self.eq_pat(l, r))
-                    && both(li, ri, |l, r| self.eq_pat(l, r))
+                    && both(li.as_ref(), ri.as_ref(), |l, r| self.eq_pat(l, r))
             },
             (&PatKind::Wild, &PatKind::Wild) => true,
             _ => false,
@@ -476,7 +484,7 @@ impl HirEqInterExpr<'_, '_, '_> {
     fn eq_qpath(&mut self, left: &QPath<'_>, right: &QPath<'_>) -> bool {
         match (left, right) {
             (&QPath::Resolved(ref lty, lpath), &QPath::Resolved(ref rty, rpath)) => {
-                both(lty, rty, |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath)
+                both(lty.as_ref(), rty.as_ref(), |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath)
             },
             (&QPath::TypeRelative(lty, lseg), &QPath::TypeRelative(rty, rseg)) => {
                 self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
@@ -510,7 +518,10 @@ impl HirEqInterExpr<'_, '_, '_> {
     pub fn eq_path_segment(&mut self, left: &PathSegment<'_>, right: &PathSegment<'_>) -> bool {
         // The == of idents doesn't work with different contexts,
         // we have to be explicit about hygiene
-        left.ident.name == right.ident.name && both(&left.args, &right.args, |l, r| self.eq_path_parameters(l, r))
+        left.ident.name == right.ident.name
+            && both(left.args.as_ref(), right.args.as_ref(), |l, r| {
+                self.eq_path_parameters(l, r)
+            })
     }
 
     pub fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
@@ -649,7 +660,7 @@ fn swap_binop<'a>(
 
 /// Checks if the two `Option`s are both `None` or some equal values as per
 /// `eq_fn`.
-pub fn both<X>(l: &Option<X>, r: &Option<X>, mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
+pub fn both<X>(l: Option<&X>, r: Option<&X>, mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
     l.as_ref()
         .map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y)))
 }
@@ -1115,9 +1126,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 }
             },
             TyKind::Path(ref qpath) => self.hash_qpath(qpath),
-            TyKind::OpaqueDef(_, arg_list, in_trait) => {
+            TyKind::OpaqueDef(_, arg_list) => {
                 self.hash_generic_args(arg_list);
-                in_trait.hash(&mut self.s);
             },
             TyKind::TraitObject(_, lifetime, _) => {
                 self.hash_lifetime(lifetime);
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 6dbc3334157..10e258444a6 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1,6 +1,5 @@
 #![feature(array_chunks)]
 #![feature(box_patterns)]
-#![feature(control_flow_enum)]
 #![feature(f128)]
 #![feature(f16)]
 #![feature(if_let_guard)]
@@ -597,7 +596,7 @@ fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<It
         },
     };
 
-    tcx.incoherent_impls(ty).into_iter().copied()
+    tcx.incoherent_impls(ty).iter().copied()
 }
 
 fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
@@ -731,7 +730,7 @@ pub fn def_path_res_with_base(tcx: TyCtxt<'_>, mut base: Vec<Res>, mut path: &[&
                 // `impl S { ... }`
                 let inherent_impl_children = tcx
                     .inherent_impls(def_id)
-                    .into_iter()
+                    .iter()
                     .flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment));
 
                 let direct_children = item_children_by_name(tcx, def_id, segment);
@@ -1341,7 +1340,7 @@ pub struct ContainsName<'a, 'tcx> {
     pub result: bool,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for ContainsName<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for ContainsName<'_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_name(&mut self, name: Symbol) {
@@ -3111,7 +3110,7 @@ pub fn is_never_expr<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<
         is_never: bool,
     }
 
-    impl<'tcx> V<'_, 'tcx> {
+    impl V<'_, '_> {
         fn push_break_target(&mut self, id: HirId) {
             self.break_targets.push(BreakTarget { id, unused: true });
             self.break_targets_for_result_ty += u32::from(self.in_final_expr);
diff --git a/src/tools/clippy/clippy_utils/src/mir/mod.rs b/src/tools/clippy/clippy_utils/src/mir/mod.rs
index 59bb5e35cda..3924e384c37 100644
--- a/src/tools/clippy/clippy_utils/src/mir/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/mod.rs
@@ -58,7 +58,7 @@ struct V<'a> {
     results: Vec<LocalUsage>,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for V<'a> {
+impl<'tcx> Visitor<'tcx> for V<'_> {
     fn visit_place(&mut self, place: &Place<'tcx>, ctx: PlaceContext, loc: Location) {
         if loc.block == self.location.block && loc.statement_index <= self.location.statement_index {
             return;
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
index 07e6705cd3d..6bb434a466f 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
@@ -65,7 +65,7 @@ impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> {
     }
 }
 
-impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, 'tcx> {
+impl<'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'_, '_, 'tcx> {
     fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
         let lhs = place.local;
         match rvalue {
@@ -177,8 +177,8 @@ pub struct PossibleBorrowerMap<'b, 'tcx> {
     pub bitset: (BitSet<mir::Local>, BitSet<mir::Local>),
 }
 
-impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
-    pub fn new(cx: &'a LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
+impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
+    pub fn new(cx: &LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
         let possible_origin = {
             let mut vis = PossibleOriginVisitor::new(mir);
             vis.visit_body(mir);
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs b/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
index da04266863f..4157b3f4930 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
@@ -39,7 +39,7 @@ impl<'a, 'tcx> PossibleOriginVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'a, 'tcx> {
+impl<'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'_, 'tcx> {
     fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
         let lhs = place.local;
         match rvalue {
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 7a6107cfe53..5f12b6bf99e 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -131,7 +131,8 @@ fn check_rvalue<'tcx>(
             CastKind::PointerCoercion(
                 PointerCoercion::UnsafeFnPointer
                 | PointerCoercion::ClosureFnPointer(_)
-                | PointerCoercion::ReifyFnPointer, _
+                | PointerCoercion::ReifyFnPointer,
+                _,
             ),
             _,
             _,
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index 4ad7575e720..eecbfb3936a 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -287,6 +287,7 @@ impl SourceFileRange {
         self.sf
             .src
             .as_ref()
+            .map(|src| src.as_str())
             .or_else(|| self.sf.external_src.get().and_then(|src| src.get_source()))
             .and_then(|x| x.get(self.range.clone()))
     }
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 4e3a61a1aa5..21c2b19f4bd 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -1319,7 +1319,7 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl
 /// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`.
 pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> {
     if let Some(ty_did) = ty.ty_adt_def().map(AdtDef::did) {
-        cx.tcx.inherent_impls(ty_did).into_iter().find_map(|&did| {
+        cx.tcx.inherent_impls(ty_did).iter().find_map(|&did| {
             cx.tcx
                 .associated_items(did)
                 .filter_by_name_unhygienic(method_name)
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index e612e9c6cb6..91ec120adbf 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -108,7 +108,7 @@ impl<'cx, 'tcx> CertaintyVisitor<'cx, 'tcx> {
     }
 }
 
-impl<'cx, 'tcx> Visitor<'cx> for CertaintyVisitor<'cx, 'tcx> {
+impl<'cx> Visitor<'cx> for CertaintyVisitor<'cx, '_> {
     fn visit_qpath(&mut self, qpath: &'cx QPath<'_>, hir_id: HirId, _: Span) {
         self.certainty = self.certainty.meet(qpath_certainty(self.cx, qpath, true));
         if self.certainty != Certainty::Uncertain {
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 1230b60c3a6..8af3bdccaa1 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -46,8 +46,8 @@ struct MutVarsDelegate {
     skip: bool,
 }
 
-impl<'tcx> MutVarsDelegate {
-    fn update(&mut self, cat: &PlaceWithHirId<'tcx>) {
+impl MutVarsDelegate {
+    fn update(&mut self, cat: &PlaceWithHirId<'_>) {
         match cat.place.base {
             PlaceBase::Local(id) => {
                 self.used_mutably.insert(id);
@@ -122,7 +122,7 @@ impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> {
         finder.usage_found
     }
 }
-impl<'a, 'tcx> Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for BindingUsageFinder<'_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 6d9a85a1181..02931306f16 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -552,7 +552,7 @@ pub fn for_each_local_use_after_expr<'tcx, B>(
         res: ControlFlow<B>,
         f: F,
     }
-    impl<'cx, 'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B>, B> Visitor<'tcx> for V<'cx, 'tcx, F, B> {
+    impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B>, B> Visitor<'tcx> for V<'_, 'tcx, F, B> {
         type NestedFilter = nested_filter::OnlyBodies;
         fn nested_visit_map(&mut self) -> Self::Map {
             self.cx.tcx.hir()
@@ -734,7 +734,7 @@ pub fn for_each_local_assignment<'tcx, B>(
         res: ControlFlow<B>,
         f: F,
     }
-    impl<'cx, 'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B>, B> Visitor<'tcx> for V<'cx, 'tcx, F, B> {
+    impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B>, B> Visitor<'tcx> for V<'_, 'tcx, F, B> {
         type NestedFilter = nested_filter::OnlyBodies;
         fn nested_visit_map(&mut self) -> Self::Map {
             self.cx.tcx.hir()
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index acb6eaa5278..8c62dd3ed38 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -68,7 +68,7 @@ impl Crate {
         total_crates_to_lint: usize,
         config: &LintcheckConfig,
         lint_levels_args: &[String],
-        server: &Option<LintcheckServer>,
+        server: Option<&LintcheckServer>,
     ) -> Vec<ClippyCheckOutput> {
         // advance the atomic index by one
         let index = target_dir_index.fetch_add(1, Ordering::SeqCst);
@@ -359,7 +359,7 @@ fn lintcheck(config: LintcheckConfig) {
                 crates.len(),
                 &config,
                 &lint_level_args,
-                &server,
+                server.as_ref(),
             )
         })
         .collect();
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index b431599c224..f0c8651efce 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,4 +1,4 @@
 [toolchain]
-channel = "nightly-2024-09-22"
+channel = "nightly-2024-10-03"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 324f754e615..c66837dc998 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -22,7 +22,6 @@ use rustc_span::symbol::Symbol;
 
 use std::env;
 use std::fs::read_to_string;
-use std::ops::Deref;
 use std::path::Path;
 use std::process::exit;
 
@@ -30,12 +29,8 @@ use anstream::println;
 
 /// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
 /// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
-fn arg_value<'a, T: Deref<Target = str>>(
-    args: &'a [T],
-    find_arg: &str,
-    pred: impl Fn(&str) -> bool,
-) -> Option<&'a str> {
-    let mut args = args.iter().map(Deref::deref);
+fn arg_value<'a>(args: &'a [String], find_arg: &str, pred: impl Fn(&str) -> bool) -> Option<&'a str> {
+    let mut args = args.iter().map(String::as_str);
     while let Some(arg) = args.next() {
         let mut arg = arg.splitn(2, '=');
         if arg.next() != Some(find_arg) {
@@ -50,11 +45,15 @@ fn arg_value<'a, T: Deref<Target = str>>(
     None
 }
 
+fn has_arg(args: &[String], find_arg: &str) -> bool {
+    args.iter().any(|arg| find_arg == arg.split('=').next().unwrap())
+}
+
 #[test]
 fn test_arg_value() {
-    let args = &["--bar=bar", "--foobar", "123", "--foo"];
+    let args = &["--bar=bar", "--foobar", "123", "--foo"].map(String::from);
 
-    assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None);
+    assert_eq!(arg_value(&[], "--foobar", |_| true), None);
     assert_eq!(arg_value(args, "--bar", |_| false), None);
     assert_eq!(arg_value(args, "--bar", |_| true), Some("bar"));
     assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar"));
@@ -65,11 +64,21 @@ fn test_arg_value() {
     assert_eq!(arg_value(args, "--foo", |_| true), None);
 }
 
-fn track_clippy_args(psess: &mut ParseSess, args_env_var: &Option<String>) {
-    psess.env_depinfo.get_mut().insert((
-        Symbol::intern("CLIPPY_ARGS"),
-        args_env_var.as_deref().map(Symbol::intern),
-    ));
+#[test]
+fn test_has_arg() {
+    let args = &["--foo=bar", "-vV", "--baz"].map(String::from);
+    assert!(has_arg(args, "--foo"));
+    assert!(has_arg(args, "--baz"));
+    assert!(has_arg(args, "-vV"));
+
+    assert!(!has_arg(args, "--bar"));
+}
+
+fn track_clippy_args(psess: &mut ParseSess, args_env_var: Option<&str>) {
+    psess
+        .env_depinfo
+        .get_mut()
+        .insert((Symbol::intern("CLIPPY_ARGS"), args_env_var.map(Symbol::intern)));
 }
 
 /// Track files that may be accessed at runtime in `file_depinfo` so that cargo will re-run clippy
@@ -113,7 +122,7 @@ impl rustc_driver::Callbacks for RustcCallbacks {
     fn config(&mut self, config: &mut interface::Config) {
         let clippy_args_var = self.clippy_args_var.take();
         config.psess_created = Some(Box::new(move |psess| {
-            track_clippy_args(psess, &clippy_args_var);
+            track_clippy_args(psess, clippy_args_var.as_deref());
         }));
     }
 }
@@ -130,7 +139,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
         let previous = config.register_lints.take();
         let clippy_args_var = self.clippy_args_var.take();
         config.psess_created = Some(Box::new(move |psess| {
-            track_clippy_args(psess, &clippy_args_var);
+            track_clippy_args(psess, clippy_args_var.as_deref());
             track_files(psess);
 
             // Trigger a rebuild if CLIPPY_CONF_DIR changes. The value must be a valid string so
@@ -189,7 +198,7 @@ pub fn main() {
         let mut orig_args = rustc_driver::args::raw_args(&early_dcx)?;
 
         let has_sysroot_arg = |args: &mut [String]| -> bool {
-            if arg_value(args, "--sysroot", |_| true).is_some() {
+            if has_arg(args, "--sysroot") {
                 return true;
             }
             // https://doc.rust-lang.org/rustc/command-line-arguments.html#path-load-command-line-flags-from-a-path
@@ -199,7 +208,7 @@ pub fn main() {
                 if let Some(arg_file_path) = arg.strip_prefix('@') {
                     if let Ok(arg_file) = read_to_string(arg_file_path) {
                         let split_arg_file: Vec<String> = arg_file.lines().map(ToString::to_string).collect();
-                        if arg_value(&split_arg_file, "--sysroot", |_| true).is_some() {
+                        if has_arg(&split_arg_file, "--sysroot") {
                             return true;
                         }
                     }
@@ -271,16 +280,18 @@ pub fn main() {
             .chain(vec!["--cfg".into(), "clippy".into()])
             .collect::<Vec<String>>();
 
-        // We enable Clippy if one of the following conditions is met
-        // - IF Clippy is run on its test suite OR
-        // - IF Clippy is run on the main crate, not on deps (`!cap_lints_allow`) THEN
-        //    - IF `--no-deps` is not set (`!no_deps`) OR
-        //    - IF `--no-deps` is set and Clippy is run on the specified primary package
+        // If no Clippy lints will be run we do not need to run Clippy
         let cap_lints_allow = arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_some()
             && arg_value(&orig_args, "--force-warn", |val| val.contains("clippy::")).is_none();
-        let in_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok();
 
-        let clippy_enabled = !cap_lints_allow && (!no_deps || in_primary_package);
+        // If `--no-deps` is enabled only lint the primary pacakge
+        let relevant_package = !no_deps || env::var("CARGO_PRIMARY_PACKAGE").is_ok();
+
+        // Do not run Clippy for Cargo's info queries so that invalid CLIPPY_ARGS are not cached
+        // https://github.com/rust-lang/cargo/issues/14385
+        let info_query = has_arg(&orig_args, "-vV") || has_arg(&orig_args, "--print");
+
+        let clippy_enabled = !cap_lints_allow && relevant_package && !info_query;
         if clippy_enabled {
             args.extend(clippy_args);
             rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var })
diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs
index 232bccf6a15..4613a74b85d 100644
--- a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs
+++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs
@@ -7,7 +7,8 @@
     clippy::no_effect,
     clippy::unnecessary_operation,
     clippy::useless_vec,
-    clippy::out_of_bounds_indexing
+    clippy::out_of_bounds_indexing,
+    clippy::needless_lifetimes
 )]
 
 const ARR: [i32; 2] = [1, 2];
diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr
index 5ce2ed2ffae..120f5c35cb0 100644
--- a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr
+++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr
@@ -1,5 +1,5 @@
 error: indexing may panic
-  --> tests/ui-toml/suppress_lint_in_const/test.rs:26:5
+  --> tests/ui-toml/suppress_lint_in_const/test.rs:27:5
    |
 LL |     x[index];
    |     ^^^^^^^^
@@ -9,7 +9,7 @@ LL |     x[index];
    = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]`
 
 error: indexing may panic
-  --> tests/ui-toml/suppress_lint_in_const/test.rs:41:5
+  --> tests/ui-toml/suppress_lint_in_const/test.rs:42:5
    |
 LL |     v[0];
    |     ^^^^
@@ -17,7 +17,7 @@ LL |     v[0];
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
 error: indexing may panic
-  --> tests/ui-toml/suppress_lint_in_const/test.rs:42:5
+  --> tests/ui-toml/suppress_lint_in_const/test.rs:43:5
    |
 LL |     v[10];
    |     ^^^^^
@@ -25,7 +25,7 @@ LL |     v[10];
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
 error: indexing may panic
-  --> tests/ui-toml/suppress_lint_in_const/test.rs:43:5
+  --> tests/ui-toml/suppress_lint_in_const/test.rs:44:5
    |
 LL |     v[1 << 3];
    |     ^^^^^^^^^
@@ -33,7 +33,7 @@ LL |     v[1 << 3];
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
 error: indexing may panic
-  --> tests/ui-toml/suppress_lint_in_const/test.rs:49:5
+  --> tests/ui-toml/suppress_lint_in_const/test.rs:50:5
    |
 LL |     v[N];
    |     ^^^^
@@ -41,7 +41,7 @@ LL |     v[N];
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
 error: indexing may panic
-  --> tests/ui-toml/suppress_lint_in_const/test.rs:50:5
+  --> tests/ui-toml/suppress_lint_in_const/test.rs:51:5
    |
 LL |     v[M];
    |     ^^^^
diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed
index baf939af24e..cdb8fa0454c 100644
--- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed
+++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed
@@ -86,6 +86,7 @@ mod issue9612 {
         util();
     }
 
+    #[allow(unconditional_panic)]
     fn util() {
         let _a: u8 = 4.try_into().unwrap();
         let _a: u8 = 5.try_into().expect("");
diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs
index e300ba18c33..e53d53db5f7 100644
--- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs
+++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs
@@ -86,6 +86,7 @@ mod issue9612 {
         util();
     }
 
+    #[allow(unconditional_panic)]
     fn util() {
         let _a: u8 = 4.try_into().unwrap();
         let _a: u8 = 5.try_into().expect("");
diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
index 320578bfabc..b58ce9b8af3 100644
--- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
+++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
@@ -274,7 +274,7 @@ LL |     let _ = &boxed_slice[1];
    |             ~~~~~~~~~~~~~~~
 
 error: called `.get().unwrap()` on a slice
-  --> tests/ui-toml/unwrap_used/unwrap_used.rs:93:17
+  --> tests/ui-toml/unwrap_used/unwrap_used.rs:94:17
    |
 LL |         let _ = Box::new([0]).get(1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs b/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs
index 297a53b1bbf..9e862320f4e 100644
--- a/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs
+++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs
@@ -1,7 +1,7 @@
 #![allow(unused)]
 #![warn(clippy::as_ptr_cast_mut)]
 #![allow(clippy::wrong_self_convention, clippy::unnecessary_cast)]
-//@no-rustfix
+//@no-rustfix: incorrect suggestion
 
 struct MutPtrWrapper(Vec<u8>);
 impl MutPtrWrapper {
diff --git a/src/tools/clippy/tests/ui/borrow_box.fixed b/src/tools/clippy/tests/ui/borrow_box.fixed
new file mode 100644
index 00000000000..08ea60583ea
--- /dev/null
+++ b/src/tools/clippy/tests/ui/borrow_box.fixed
@@ -0,0 +1,133 @@
+#![deny(clippy::borrowed_box)]
+#![allow(dead_code, unused_variables)]
+#![allow(
+    clippy::uninlined_format_args,
+    clippy::disallowed_names,
+    clippy::needless_pass_by_ref_mut,
+    clippy::needless_lifetimes
+)]
+
+use std::fmt::Display;
+
+pub fn test1(foo: &mut Box<bool>) {
+    // Although this function could be changed to "&mut bool",
+    // avoiding the Box, mutable references to boxes are not
+    // flagged by this lint.
+    //
+    // This omission is intentional: By passing a mutable Box,
+    // the memory location of the pointed-to object could be
+    // modified. By passing a mutable reference, the contents
+    // could change, but not the location.
+    println!("{:?}", foo)
+}
+
+pub fn test2() {
+    let foo: &bool;
+    //~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+}
+
+struct Test3<'a> {
+    foo: &'a bool,
+    //~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+}
+
+trait Test4 {
+    fn test4(a: &bool);
+    //~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+}
+
+use std::any::Any;
+
+pub fn test5(foo: &mut Box<dyn Any>) {
+    println!("{:?}", foo)
+}
+
+pub fn test6() {
+    let foo: &Box<dyn Any>;
+}
+
+struct Test7<'a> {
+    foo: &'a Box<dyn Any>,
+}
+
+trait Test8 {
+    fn test8(a: &Box<dyn Any>);
+}
+
+impl<'a> Test8 for Test7<'a> {
+    fn test8(a: &Box<dyn Any>) {
+        unimplemented!();
+    }
+}
+
+pub fn test9(foo: &mut Box<dyn Any + Send + Sync>) {
+    let _ = foo;
+}
+
+pub fn test10() {
+    let foo: &Box<dyn Any + Send + 'static>;
+}
+
+struct Test11<'a> {
+    foo: &'a Box<dyn Any + Send>,
+}
+
+trait Test12 {
+    fn test4(a: &Box<dyn Any + 'static>);
+}
+
+impl<'a> Test12 for Test11<'a> {
+    fn test4(a: &Box<dyn Any + 'static>) {
+        unimplemented!();
+    }
+}
+
+pub fn test13(boxed_slice: &mut Box<[i32]>) {
+    // Unconditionally replaces the box pointer.
+    //
+    // This cannot be accomplished if "&mut [i32]" is passed,
+    // and provides a test case where passing a reference to
+    // a Box is valid.
+    let mut data = vec![12];
+    *boxed_slice = data.into_boxed_slice();
+}
+
+// The suggestion should include proper parentheses to avoid a syntax error.
+pub fn test14(_display: &dyn Display) {}
+//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+pub fn test15(_display: &(dyn Display + Send)) {}
+//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+pub fn test16<'a>(_display: &'a (dyn Display + 'a)) {}
+//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+
+pub fn test17(_display: &impl Display) {}
+//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+pub fn test18(_display: &(impl Display + Send)) {}
+//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+pub fn test19<'a>(_display: &'a (impl Display + 'a)) {}
+//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+
+// This exists only to check what happens when parentheses are already present.
+// Even though the current implementation doesn't put extra parentheses,
+// it's fine that unnecessary parentheses appear in the future for some reason.
+pub fn test20(_display: &(dyn Display + Send)) {}
+//~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+
+#[allow(clippy::borrowed_box)]
+trait Trait {
+    fn f(b: &Box<bool>);
+}
+
+// Trait impls are not linted
+impl Trait for () {
+    fn f(_: &Box<bool>) {}
+}
+
+fn main() {
+    test1(&mut Box::new(false));
+    test2();
+    test5(&mut (Box::new(false) as Box<dyn Any>));
+    test6();
+    test9(&mut (Box::new(false) as Box<dyn Any + Send + Sync>));
+    test10();
+}
diff --git a/src/tools/clippy/tests/ui/borrow_box.rs b/src/tools/clippy/tests/ui/borrow_box.rs
index e9994aac845..b55de1701da 100644
--- a/src/tools/clippy/tests/ui/borrow_box.rs
+++ b/src/tools/clippy/tests/ui/borrow_box.rs
@@ -3,9 +3,9 @@
 #![allow(
     clippy::uninlined_format_args,
     clippy::disallowed_names,
-    clippy::needless_pass_by_ref_mut
+    clippy::needless_pass_by_ref_mut,
+    clippy::needless_lifetimes
 )]
-//@no-rustfix
 
 use std::fmt::Display;
 
@@ -36,12 +36,6 @@ trait Test4 {
     //~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
 }
 
-impl<'a> Test4 for Test3<'a> {
-    fn test4(a: &Box<bool>) {
-        unimplemented!();
-    }
-}
-
 use std::any::Any;
 
 pub fn test5(foo: &mut Box<dyn Any>) {
@@ -119,6 +113,16 @@ pub fn test19<'a>(_display: &'a Box<impl Display + 'a>) {}
 pub fn test20(_display: &Box<(dyn Display + Send)>) {}
 //~^ ERROR: you seem to be trying to use `&Box<T>`. Consider using just `&T`
 
+#[allow(clippy::borrowed_box)]
+trait Trait {
+    fn f(b: &Box<bool>);
+}
+
+// Trait impls are not linted
+impl Trait for () {
+    fn f(_: &Box<bool>) {}
+}
+
 fn main() {
     test1(&mut Box::new(false));
     test2();
diff --git a/src/tools/clippy/tests/ui/borrow_box.stderr b/src/tools/clippy/tests/ui/borrow_box.stderr
index 34e8f11dfd7..6f80f86c3b3 100644
--- a/src/tools/clippy/tests/ui/borrow_box.stderr
+++ b/src/tools/clippy/tests/ui/borrow_box.stderr
@@ -23,43 +23,43 @@ LL |     fn test4(a: &Box<bool>);
    |                 ^^^^^^^^^^ help: try: `&bool`
 
 error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
-  --> tests/ui/borrow_box.rs:102:25
+  --> tests/ui/borrow_box.rs:96:25
    |
 LL | pub fn test14(_display: &Box<dyn Display>) {}
    |                         ^^^^^^^^^^^^^^^^^ help: try: `&dyn Display`
 
 error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
-  --> tests/ui/borrow_box.rs:104:25
+  --> tests/ui/borrow_box.rs:98:25
    |
 LL | pub fn test15(_display: &Box<dyn Display + Send>) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)`
 
 error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
-  --> tests/ui/borrow_box.rs:106:29
+  --> tests/ui/borrow_box.rs:100:29
    |
 LL | pub fn test16<'a>(_display: &'a Box<dyn Display + 'a>) {}
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (dyn Display + 'a)`
 
 error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
-  --> tests/ui/borrow_box.rs:109:25
+  --> tests/ui/borrow_box.rs:103:25
    |
 LL | pub fn test17(_display: &Box<impl Display>) {}
    |                         ^^^^^^^^^^^^^^^^^^ help: try: `&impl Display`
 
 error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
-  --> tests/ui/borrow_box.rs:111:25
+  --> tests/ui/borrow_box.rs:105:25
    |
 LL | pub fn test18(_display: &Box<impl Display + Send>) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(impl Display + Send)`
 
 error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
-  --> tests/ui/borrow_box.rs:113:29
+  --> tests/ui/borrow_box.rs:107:29
    |
 LL | pub fn test19<'a>(_display: &'a Box<impl Display + 'a>) {}
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (impl Display + 'a)`
 
 error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
-  --> tests/ui/borrow_box.rs:119:25
+  --> tests/ui/borrow_box.rs:113:25
    |
 LL | pub fn test20(_display: &Box<(dyn Display + Send)>) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)`
diff --git a/src/tools/clippy/tests/ui/boxed_local.rs b/src/tools/clippy/tests/ui/boxed_local.rs
index fbd9e12fc18..e2c27e585fc 100644
--- a/src/tools/clippy/tests/ui/boxed_local.rs
+++ b/src/tools/clippy/tests/ui/boxed_local.rs
@@ -3,7 +3,8 @@
     clippy::needless_pass_by_value,
     clippy::unused_unit,
     clippy::redundant_clone,
-    clippy::match_single_binding
+    clippy::match_single_binding,
+    clippy::needless_lifetimes
 )]
 #![warn(clippy::boxed_local)]
 
diff --git a/src/tools/clippy/tests/ui/boxed_local.stderr b/src/tools/clippy/tests/ui/boxed_local.stderr
index 7710233fa4d..d3156c820b2 100644
--- a/src/tools/clippy/tests/ui/boxed_local.stderr
+++ b/src/tools/clippy/tests/ui/boxed_local.stderr
@@ -1,5 +1,5 @@
 error: local variable doesn't need to be boxed here
-  --> tests/ui/boxed_local.rs:39:13
+  --> tests/ui/boxed_local.rs:40:13
    |
 LL | fn warn_arg(x: Box<A>) {
    |             ^
@@ -8,19 +8,19 @@ LL | fn warn_arg(x: Box<A>) {
    = help: to override `-D warnings` add `#[allow(clippy::boxed_local)]`
 
 error: local variable doesn't need to be boxed here
-  --> tests/ui/boxed_local.rs:122:12
+  --> tests/ui/boxed_local.rs:123:12
    |
 LL | pub fn new(_needs_name: Box<PeekableSeekable<&()>>) -> () {}
    |            ^^^^^^^^^^^
 
 error: local variable doesn't need to be boxed here
-  --> tests/ui/boxed_local.rs:187:44
+  --> tests/ui/boxed_local.rs:188:44
    |
 LL |         fn default_impl_x(self: Box<Self>, x: Box<u32>) -> u32 {
    |                                            ^
 
 error: local variable doesn't need to be boxed here
-  --> tests/ui/boxed_local.rs:195:16
+  --> tests/ui/boxed_local.rs:196:16
    |
 LL |         fn foo(x: Box<u32>) {}
    |                ^
diff --git a/src/tools/clippy/tests/ui/bytecount.rs b/src/tools/clippy/tests/ui/bytecount.rs
index 3794fc5d441..f3b02fda8a8 100644
--- a/src/tools/clippy/tests/ui/bytecount.rs
+++ b/src/tools/clippy/tests/ui/bytecount.rs
@@ -1,4 +1,4 @@
-//@no-rustfix
+//@no-rustfix: suggests external crate
 
 #![allow(clippy::needless_borrow, clippy::useless_vec)]
 
diff --git a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.fixed b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.fixed
index 8bd9eea75bb..837069cae6d 100644
--- a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.fixed
+++ b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.fixed
@@ -9,7 +9,7 @@ struct Baz<'a> {
     bar: &'a Bar,
 }
 
-impl<'a> Foo for Baz<'a> {}
+impl Foo for Baz<'_> {}
 
 impl Bar {
     fn baz(&self) -> impl Foo + '_ {
diff --git a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr
index 3a2d1f4410e..bed6aab25c4 100644
--- a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr
+++ b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr
@@ -1,8 +1,8 @@
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/crashes/needless_lifetimes_impl_trait.rs:15:12
+  --> tests/ui/crashes/needless_lifetimes_impl_trait.rs:12:6
    |
-LL |     fn baz<'a>(&'a self) -> impl Foo + 'a {
-   |            ^^   ^^                     ^^
+LL | impl<'a> Foo for Baz<'a> {}
+   |      ^^              ^^
    |
 note: the lint level is defined here
   --> tests/ui/crashes/needless_lifetimes_impl_trait.rs:1:9
@@ -11,9 +11,21 @@ LL | #![deny(clippy::needless_lifetimes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: elide the lifetimes
    |
+LL - impl<'a> Foo for Baz<'a> {}
+LL + impl Foo for Baz<'_> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'a
+  --> tests/ui/crashes/needless_lifetimes_impl_trait.rs:15:12
+   |
+LL |     fn baz<'a>(&'a self) -> impl Foo + 'a {
+   |            ^^   ^^                     ^^
+   |
+help: elide the lifetimes
+   |
 LL -     fn baz<'a>(&'a self) -> impl Foo + 'a {
 LL +     fn baz(&self) -> impl Foo + '_ {
    |
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/deref_addrof_double_trigger.rs b/src/tools/clippy/tests/ui/deref_addrof_double_trigger.rs
index 32582a3a8bf..6f997875777 100644
--- a/src/tools/clippy/tests/ui/deref_addrof_double_trigger.rs
+++ b/src/tools/clippy/tests/ui/deref_addrof_double_trigger.rs
@@ -1,5 +1,5 @@
-// This test can't work with run-rustfix because it needs two passes of test+fix
-//@no-rustfix
+//@no-rustfix: this test can't work with run-rustfix because it needs two passes of test+fix
+
 #[warn(clippy::deref_addrof)]
 #[allow(unused_variables, unused_mut)]
 fn main() {
diff --git a/src/tools/clippy/tests/ui/derive.rs b/src/tools/clippy/tests/ui/derive.rs
index 20ac8a6e6be..b06dd78608f 100644
--- a/src/tools/clippy/tests/ui/derive.rs
+++ b/src/tools/clippy/tests/ui/derive.rs
@@ -1,4 +1,9 @@
-#![allow(clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, dead_code)]
+#![allow(
+    clippy::non_canonical_clone_impl,
+    clippy::non_canonical_partial_ord_impl,
+    clippy::needless_lifetimes,
+    dead_code
+)]
 #![warn(clippy::expl_impl_clone_on_copy)]
 
 
diff --git a/src/tools/clippy/tests/ui/derive.stderr b/src/tools/clippy/tests/ui/derive.stderr
index d5f9d7cf2a2..0eb4b3c1ada 100644
--- a/src/tools/clippy/tests/ui/derive.stderr
+++ b/src/tools/clippy/tests/ui/derive.stderr
@@ -1,5 +1,5 @@
 error: you are implementing `Clone` explicitly on a `Copy` type
-  --> tests/ui/derive.rs:8:1
+  --> tests/ui/derive.rs:13:1
    |
 LL | / impl Clone for Qux {
 LL | |
@@ -10,7 +10,7 @@ LL | | }
    | |_^
    |
 note: consider deriving `Clone` or removing `Copy`
-  --> tests/ui/derive.rs:8:1
+  --> tests/ui/derive.rs:13:1
    |
 LL | / impl Clone for Qux {
 LL | |
@@ -23,7 +23,7 @@ LL | | }
    = help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]`
 
 error: you are implementing `Clone` explicitly on a `Copy` type
-  --> tests/ui/derive.rs:33:1
+  --> tests/ui/derive.rs:38:1
    |
 LL | / impl<'a> Clone for Lt<'a> {
 LL | |
@@ -34,7 +34,7 @@ LL | | }
    | |_^
    |
 note: consider deriving `Clone` or removing `Copy`
-  --> tests/ui/derive.rs:33:1
+  --> tests/ui/derive.rs:38:1
    |
 LL | / impl<'a> Clone for Lt<'a> {
 LL | |
@@ -45,7 +45,7 @@ LL | | }
    | |_^
 
 error: you are implementing `Clone` explicitly on a `Copy` type
-  --> tests/ui/derive.rs:45:1
+  --> tests/ui/derive.rs:50:1
    |
 LL | / impl Clone for BigArray {
 LL | |
@@ -56,7 +56,7 @@ LL | | }
    | |_^
    |
 note: consider deriving `Clone` or removing `Copy`
-  --> tests/ui/derive.rs:45:1
+  --> tests/ui/derive.rs:50:1
    |
 LL | / impl Clone for BigArray {
 LL | |
@@ -67,7 +67,7 @@ LL | | }
    | |_^
 
 error: you are implementing `Clone` explicitly on a `Copy` type
-  --> tests/ui/derive.rs:57:1
+  --> tests/ui/derive.rs:62:1
    |
 LL | / impl Clone for FnPtr {
 LL | |
@@ -78,7 +78,7 @@ LL | | }
    | |_^
    |
 note: consider deriving `Clone` or removing `Copy`
-  --> tests/ui/derive.rs:57:1
+  --> tests/ui/derive.rs:62:1
    |
 LL | / impl Clone for FnPtr {
 LL | |
@@ -89,7 +89,7 @@ LL | | }
    | |_^
 
 error: you are implementing `Clone` explicitly on a `Copy` type
-  --> tests/ui/derive.rs:78:1
+  --> tests/ui/derive.rs:83:1
    |
 LL | / impl<T: Clone> Clone for Generic2<T> {
 LL | |
@@ -100,7 +100,7 @@ LL | | }
    | |_^
    |
 note: consider deriving `Clone` or removing `Copy`
-  --> tests/ui/derive.rs:78:1
+  --> tests/ui/derive.rs:83:1
    |
 LL | / impl<T: Clone> Clone for Generic2<T> {
 LL | |
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index ca422ee29c1..f1baf28200e 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -9,7 +9,8 @@
     clippy::redundant_closure_call,
     clippy::uninlined_format_args,
     clippy::useless_vec,
-    clippy::unnecessary_map_on_constructor
+    clippy::unnecessary_map_on_constructor,
+    clippy::needless_lifetimes
 )]
 
 use std::path::{Path, PathBuf};
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index c0db91c03ef..c52a51880bf 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -9,7 +9,8 @@
     clippy::redundant_closure_call,
     clippy::uninlined_format_args,
     clippy::useless_vec,
-    clippy::unnecessary_map_on_constructor
+    clippy::unnecessary_map_on_constructor,
+    clippy::needless_lifetimes
 )]
 
 use std::path::{Path, PathBuf};
diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr
index 5540261fc57..1731a4377f5 100644
--- a/src/tools/clippy/tests/ui/eta.stderr
+++ b/src/tools/clippy/tests/ui/eta.stderr
@@ -1,5 +1,5 @@
 error: redundant closure
-  --> tests/ui/eta.rs:30:27
+  --> tests/ui/eta.rs:31:27
    |
 LL |     let a = Some(1u8).map(|a| foo(a));
    |                           ^^^^^^^^^^ help: replace the closure with the function itself: `foo`
@@ -8,31 +8,31 @@ LL |     let a = Some(1u8).map(|a| foo(a));
    = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]`
 
 error: redundant closure
-  --> tests/ui/eta.rs:34:40
+  --> tests/ui/eta.rs:35:40
    |
 LL |     let _: Option<Vec<u8>> = true.then(|| vec![]); // special case vec!
    |                                        ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new`
 
 error: redundant closure
-  --> tests/ui/eta.rs:35:35
+  --> tests/ui/eta.rs:36:35
    |
 LL |     let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted?
    |                                   ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2`
 
 error: redundant closure
-  --> tests/ui/eta.rs:36:26
+  --> tests/ui/eta.rs:37:26
    |
 LL |     all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
    |                          ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below`
 
 error: redundant closure
-  --> tests/ui/eta.rs:43:27
+  --> tests/ui/eta.rs:44:27
    |
 LL |     let e = Some(1u8).map(|a| generic(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic`
 
 error: redundant closure
-  --> tests/ui/eta.rs:95:51
+  --> tests/ui/eta.rs:96:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
    |                                                   ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo`
@@ -41,169 +41,169 @@ LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
    = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_for_method_calls)]`
 
 error: redundant closure
-  --> tests/ui/eta.rs:96:51
+  --> tests/ui/eta.rs:97:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
    |                                                   ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo`
 
 error: redundant closure
-  --> tests/ui/eta.rs:98:42
+  --> tests/ui/eta.rs:99:42
    |
 LL |     let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
    |                                          ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear`
 
 error: redundant closure
-  --> tests/ui/eta.rs:102:29
+  --> tests/ui/eta.rs:103:29
    |
 LL |     let e = Some("str").map(|s| s.to_string());
    |                             ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string`
 
 error: redundant closure
-  --> tests/ui/eta.rs:103:27
+  --> tests/ui/eta.rs:104:27
    |
 LL |     let e = Some('a').map(|s| s.to_uppercase());
    |                           ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase`
 
 error: redundant closure
-  --> tests/ui/eta.rs:105:65
+  --> tests/ui/eta.rs:106:65
    |
 LL |     let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase`
 
 error: redundant closure
-  --> tests/ui/eta.rs:168:22
+  --> tests/ui/eta.rs:169:22
    |
 LL |     requires_fn_once(|| x());
    |                      ^^^^^^ help: replace the closure with the function itself: `x`
 
 error: redundant closure
-  --> tests/ui/eta.rs:175:27
+  --> tests/ui/eta.rs:176:27
    |
 LL |     let a = Some(1u8).map(|a| foo_ptr(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr`
 
 error: redundant closure
-  --> tests/ui/eta.rs:180:27
+  --> tests/ui/eta.rs:181:27
    |
 LL |     let a = Some(1u8).map(|a| closure(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure`
 
 error: redundant closure
-  --> tests/ui/eta.rs:212:28
+  --> tests/ui/eta.rs:213:28
    |
 LL |     x.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:213:28
+  --> tests/ui/eta.rs:214:28
    |
 LL |     y.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:214:28
+  --> tests/ui/eta.rs:215:28
    |
 LL |     z.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:221:21
+  --> tests/ui/eta.rs:222:21
    |
 LL |         Some(1).map(|n| closure(n));
    |                     ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure`
 
 error: redundant closure
-  --> tests/ui/eta.rs:225:21
+  --> tests/ui/eta.rs:226:21
    |
 LL |         Some(1).map(|n| in_loop(n));
    |                     ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop`
 
 error: redundant closure
-  --> tests/ui/eta.rs:318:18
+  --> tests/ui/eta.rs:319:18
    |
 LL |     takes_fn_mut(|| f());
    |                  ^^^^^^ help: replace the closure with the function itself: `&mut f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:321:19
+  --> tests/ui/eta.rs:322:19
    |
 LL |     takes_fn_once(|| f());
    |                   ^^^^^^ help: replace the closure with the function itself: `&mut f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:325:26
+  --> tests/ui/eta.rs:326:26
    |
 LL |     move || takes_fn_mut(|| f_used_once())
    |                          ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once`
 
 error: redundant closure
-  --> tests/ui/eta.rs:337:19
+  --> tests/ui/eta.rs:338:19
    |
 LL |     array_opt.map(|a| a.as_slice());
    |                   ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice`
 
 error: redundant closure
-  --> tests/ui/eta.rs:340:19
+  --> tests/ui/eta.rs:341:19
    |
 LL |     slice_opt.map(|s| s.len());
    |                   ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len`
 
 error: redundant closure
-  --> tests/ui/eta.rs:343:17
+  --> tests/ui/eta.rs:344:17
    |
 LL |     ptr_opt.map(|p| p.is_null());
    |                 ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null`
 
 error: redundant closure
-  --> tests/ui/eta.rs:347:17
+  --> tests/ui/eta.rs:348:17
    |
 LL |     dyn_opt.map(|d| d.method_on_dyn());
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn`
 
 error: redundant closure
-  --> tests/ui/eta.rs:407:19
+  --> tests/ui/eta.rs:408:19
    |
 LL |     let _ = f(&0, |x, y| f2(x, y));
    |                   ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2`
 
 error: redundant closure
-  --> tests/ui/eta.rs:435:22
+  --> tests/ui/eta.rs:436:22
    |
 LL |             test.map(|t| t.method())
    |                      ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:439:22
+  --> tests/ui/eta.rs:440:22
    |
 LL |             test.map(|t| t.method())
    |                      ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `super::Outer::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:452:18
+  --> tests/ui/eta.rs:453:18
    |
 LL |         test.map(|t| t.method())
    |                  ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `test_mod::Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:459:30
+  --> tests/ui/eta.rs:460:30
    |
 LL |                     test.map(|t| t.method())
    |                              ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `crate::issue_10854::d::Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:478:38
+  --> tests/ui/eta.rs:479:38
    |
 LL |         let x = Box::new(|| None.map(|x| f(x)));
    |                                      ^^^^^^^^ help: replace the closure with the function itself: `&f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:482:38
+  --> tests/ui/eta.rs:483:38
    |
 LL |         let x = Box::new(|| None.map(|x| f(x)));
    |                                      ^^^^^^^^ help: replace the closure with the function itself: `f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:499:35
+  --> tests/ui/eta.rs:500:35
    |
 LL |         let _field = bind.or_else(|| get_default()).unwrap();
    |                                   ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default`
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
index 255b2c5a220..9d476259b87 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
@@ -10,7 +10,8 @@
     clippy::redundant_field_names,
     clippy::too_many_arguments,
     clippy::borrow_deref_ref,
-    clippy::let_unit_value
+    clippy::let_unit_value,
+    clippy::needless_lifetimes
 )]
 
 trait CallableStr {
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.rs b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
index 99906999f01..23307c837f0 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.rs
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
@@ -10,7 +10,8 @@
     clippy::redundant_field_names,
     clippy::too_many_arguments,
     clippy::borrow_deref_ref,
-    clippy::let_unit_value
+    clippy::let_unit_value,
+    clippy::needless_lifetimes
 )]
 
 trait CallableStr {
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
index 53784934f63..0b05a554eb1 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
@@ -1,5 +1,5 @@
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:68:19
+  --> tests/ui/explicit_auto_deref.rs:69:19
    |
 LL |     let _: &str = &*s;
    |                   ^^^ help: try: `&s`
@@ -8,271 +8,271 @@ LL |     let _: &str = &*s;
    = help: to override `-D warnings` add `#[allow(clippy::explicit_auto_deref)]`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:69:19
+  --> tests/ui/explicit_auto_deref.rs:70:19
    |
 LL |     let _: &str = &*{ String::new() };
    |                   ^^^^^^^^^^^^^^^^^^^ help: try: `&{ String::new() }`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:70:19
+  --> tests/ui/explicit_auto_deref.rs:71:19
    |
 LL |     let _: &str = &mut *{ String::new() };
    |                   ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut { String::new() }`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:74:11
+  --> tests/ui/explicit_auto_deref.rs:75:11
    |
 LL |     f_str(&*s);
    |           ^^^ help: try: `&s`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:78:13
+  --> tests/ui/explicit_auto_deref.rs:79:13
    |
 LL |     f_str_t(&*s, &*s); // Don't lint second param.
    |             ^^^ help: try: `&s`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:81:24
+  --> tests/ui/explicit_auto_deref.rs:82:24
    |
 LL |     let _: &Box<i32> = &**b;
    |                        ^^^^ help: try: `&b`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:87:7
+  --> tests/ui/explicit_auto_deref.rs:88:7
    |
 LL |     c(&*s);
    |       ^^^ help: try: `&s`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:93:9
+  --> tests/ui/explicit_auto_deref.rs:94:9
    |
 LL |         &**x
    |         ^^^^ help: try: `x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:97:11
+  --> tests/ui/explicit_auto_deref.rs:98:11
    |
 LL |         { &**x }
    |           ^^^^ help: try: `x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:101:9
+  --> tests/ui/explicit_auto_deref.rs:102:9
    |
 LL |         &**{ x }
    |         ^^^^^^^^ help: try: `{ x }`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:105:9
+  --> tests/ui/explicit_auto_deref.rs:106:9
    |
 LL |         &***x
    |         ^^^^^ help: try: `x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:122:12
+  --> tests/ui/explicit_auto_deref.rs:123:12
    |
 LL |         f1(&*x);
    |            ^^^ help: try: `&x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:123:12
+  --> tests/ui/explicit_auto_deref.rs:124:12
    |
 LL |         f2(&*x);
    |            ^^^ help: try: `&x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:124:12
+  --> tests/ui/explicit_auto_deref.rs:125:12
    |
 LL |         f3(&*x);
    |            ^^^ help: try: `&x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:125:27
+  --> tests/ui/explicit_auto_deref.rs:126:27
    |
 LL |         f4.callable_str()(&*x);
    |                           ^^^ help: try: `&x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:126:12
+  --> tests/ui/explicit_auto_deref.rs:127:12
    |
 LL |         f5(&*x);
    |            ^^^ help: try: `&x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:127:12
+  --> tests/ui/explicit_auto_deref.rs:128:12
    |
 LL |         f6(&*x);
    |            ^^^ help: try: `&x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:128:27
+  --> tests/ui/explicit_auto_deref.rs:129:27
    |
 LL |         f7.callable_str()(&*x);
    |                           ^^^ help: try: `&x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:129:25
+  --> tests/ui/explicit_auto_deref.rs:130:25
    |
 LL |         f8.callable_t()(&*x);
    |                         ^^^ help: try: `&x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:130:12
+  --> tests/ui/explicit_auto_deref.rs:131:12
    |
 LL |         f9(&*x);
    |            ^^^ help: try: `&x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:131:13
+  --> tests/ui/explicit_auto_deref.rs:132:13
    |
 LL |         f10(&*x);
    |             ^^^ help: try: `&x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:132:26
+  --> tests/ui/explicit_auto_deref.rs:133:26
    |
 LL |         f11.callable_t()(&*x);
    |                          ^^^ help: try: `&x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:136:16
+  --> tests/ui/explicit_auto_deref.rs:137:16
    |
 LL |     let _ = S1(&*s);
    |                ^^^ help: try: `&s`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:141:21
+  --> tests/ui/explicit_auto_deref.rs:142:21
    |
 LL |     let _ = S2 { s: &*s };
    |                     ^^^ help: try: `&s`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:157:30
+  --> tests/ui/explicit_auto_deref.rs:158:30
    |
 LL |             let _ = Self::S1(&**s);
    |                              ^^^^ help: try: `s`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:158:35
+  --> tests/ui/explicit_auto_deref.rs:159:35
    |
 LL |             let _ = Self::S2 { s: &**s };
    |                                   ^^^^ help: try: `s`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:161:20
+  --> tests/ui/explicit_auto_deref.rs:162:20
    |
 LL |     let _ = E1::S1(&*s);
    |                    ^^^ help: try: `&s`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:162:25
+  --> tests/ui/explicit_auto_deref.rs:163:25
    |
 LL |     let _ = E1::S2 { s: &*s };
    |                         ^^^ help: try: `&s`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:180:13
+  --> tests/ui/explicit_auto_deref.rs:181:13
    |
 LL |     let _ = (*b).foo;
    |             ^^^^ help: try: `b`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:181:13
+  --> tests/ui/explicit_auto_deref.rs:182:13
    |
 LL |     let _ = (**b).foo;
    |             ^^^^^ help: try: `b`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:196:19
+  --> tests/ui/explicit_auto_deref.rs:197:19
    |
 LL |     let _ = f_str(*ref_str);
    |                   ^^^^^^^^ help: try: `ref_str`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:198:19
+  --> tests/ui/explicit_auto_deref.rs:199:19
    |
 LL |     let _ = f_str(**ref_ref_str);
    |                   ^^^^^^^^^^^^^ help: try: `ref_ref_str`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:208:12
+  --> tests/ui/explicit_auto_deref.rs:209:12
    |
 LL |     f_str(&&*ref_str); // `needless_borrow` will suggest removing both references
    |            ^^^^^^^^^ help: try: `ref_str`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:209:12
+  --> tests/ui/explicit_auto_deref.rs:210:12
    |
 LL |     f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference
    |            ^^^^^^^^^^ help: try: `ref_str`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:218:41
+  --> tests/ui/explicit_auto_deref.rs:219:41
    |
 LL |     let _ = || -> &'static str { return *s };
    |                                         ^^ help: try: `s`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:237:9
+  --> tests/ui/explicit_auto_deref.rs:238:9
    |
 LL |         &**x
    |         ^^^^ help: try: `x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:260:8
+  --> tests/ui/explicit_auto_deref.rs:261:8
    |
 LL |     c1(*x);
    |        ^^ help: try: `x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:263:20
+  --> tests/ui/explicit_auto_deref.rs:264:20
    |
 LL |             return *x;
    |                    ^^ help: try: `x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:265:9
+  --> tests/ui/explicit_auto_deref.rs:266:9
    |
 LL |         *x
    |         ^^ help: try: `x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:299:20
+  --> tests/ui/explicit_auto_deref.rs:300:20
    |
 LL |         Some(x) => &mut *x,
    |                    ^^^^^^^ help: try: `x`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:332:22
+  --> tests/ui/explicit_auto_deref.rs:333:22
    |
 LL |         let _ = &mut (*{ x.u }).x;
    |                      ^^^^^^^^^^ help: try: `{ x.u }`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:338:22
+  --> tests/ui/explicit_auto_deref.rs:339:22
    |
 LL |         let _ = &mut (**x.u).x;
    |                      ^^^^^^^ help: try: `(*x.u)`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:339:22
+  --> tests/ui/explicit_auto_deref.rs:340:22
    |
 LL |         let _ = &mut (**{ x.u }).x;
    |                      ^^^^^^^^^^^ help: try: `{ x.u }`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:343:22
+  --> tests/ui/explicit_auto_deref.rs:344:22
    |
 LL |         let _ = &mut (*x.u).x;
    |                      ^^^^^^ help: try: `x.u`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:344:22
+  --> tests/ui/explicit_auto_deref.rs:345:22
    |
 LL |         let _ = &mut (*{ x.u }).x;
    |                      ^^^^^^^^^^ help: try: `{ x.u }`
 
 error: deref which would be done by auto-deref
-  --> tests/ui/explicit_auto_deref.rs:367:13
+  --> tests/ui/explicit_auto_deref.rs:368:13
    |
 LL |         foo(&*wrapped_bar);
    |             ^^^^^^^^^^^^^ help: try: `&wrapped_bar`
diff --git a/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs b/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs
index cdfaf8d3afe..17d2ed9f50c 100644
--- a/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs
+++ b/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs
@@ -114,9 +114,17 @@ mod second_case {
         fn hey();
     }
 
+    // Should lint. The response to the above comment incorrectly called this a false positive. The
+    // lifetime `'a` can be removed, as demonstrated below.
     impl<'a, T: Source + ?Sized + 'a> Source for Box<T> {
         fn hey() {}
     }
+
+    struct OtherBox<T: ?Sized>(Box<T>);
+
+    impl<T: Source + ?Sized> Source for OtherBox<T> {
+        fn hey() {}
+    }
 }
 
 // Should not lint
diff --git a/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr b/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr
index 56292cb5d1a..85fbb7568ff 100644
--- a/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr
+++ b/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr
@@ -37,5 +37,11 @@ error: this lifetime isn't used in the function definition
 LL |         pub fn something<'c>() -> Self {
    |                          ^^
 
-error: aborting due to 6 previous errors
+error: this lifetime isn't used in the impl
+  --> tests/ui/extra_unused_lifetimes.rs:119:10
+   |
+LL |     impl<'a, T: Source + ?Sized + 'a> Source for Box<T> {
+   |          ^^
+
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/float_cmp.rs b/src/tools/clippy/tests/ui/float_cmp.rs
index 78dd2c6c01c..a1dfd1954fc 100644
--- a/src/tools/clippy/tests/ui/float_cmp.rs
+++ b/src/tools/clippy/tests/ui/float_cmp.rs
@@ -8,7 +8,7 @@
     clippy::unnecessary_operation,
     clippy::cast_lossless
 )]
-//@no-rustfix
+//@no-rustfix: suggestions have an error margin placeholder
 use std::ops::Add;
 
 const ZERO: f32 = 0.0;
diff --git a/src/tools/clippy/tests/ui/float_cmp_const.rs b/src/tools/clippy/tests/ui/float_cmp_const.rs
index 08180556437..ba760a18f28 100644
--- a/src/tools/clippy/tests/ui/float_cmp_const.rs
+++ b/src/tools/clippy/tests/ui/float_cmp_const.rs
@@ -1,5 +1,4 @@
-// does not test any rustfixable lints
-//@no-rustfix
+//@no-rustfix: suggestions have an error margin placeholder
 #![warn(clippy::float_cmp_const)]
 #![allow(clippy::float_cmp)]
 #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
diff --git a/src/tools/clippy/tests/ui/float_cmp_const.stderr b/src/tools/clippy/tests/ui/float_cmp_const.stderr
index 4f88746e958..e0cd6faf4b3 100644
--- a/src/tools/clippy/tests/ui/float_cmp_const.stderr
+++ b/src/tools/clippy/tests/ui/float_cmp_const.stderr
@@ -1,5 +1,5 @@
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:16:5
+  --> tests/ui/float_cmp_const.rs:15:5
    |
 LL |     1f32 == ONE;
    |     ^^^^^^^^^^^ help: consider comparing them within some margin of error: `(1f32 - ONE).abs() < error_margin`
@@ -8,43 +8,43 @@ LL |     1f32 == ONE;
    = help: to override `-D warnings` add `#[allow(clippy::float_cmp_const)]`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:18:5
+  --> tests/ui/float_cmp_const.rs:17:5
    |
 LL |     TWO == ONE;
    |     ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() < error_margin`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:20:5
+  --> tests/ui/float_cmp_const.rs:19:5
    |
 LL |     TWO != ONE;
    |     ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() > error_margin`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:22:5
+  --> tests/ui/float_cmp_const.rs:21:5
    |
 LL |     ONE + ONE == TWO;
    |     ^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE + ONE - TWO).abs() < error_margin`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:25:5
+  --> tests/ui/float_cmp_const.rs:24:5
    |
 LL |     x as f32 == ONE;
    |     ^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(x as f32 - ONE).abs() < error_margin`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:29:5
+  --> tests/ui/float_cmp_const.rs:28:5
    |
 LL |     v == ONE;
    |     ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() < error_margin`
 
 error: strict comparison of `f32` or `f64` constant
-  --> tests/ui/float_cmp_const.rs:31:5
+  --> tests/ui/float_cmp_const.rs:30:5
    |
 LL |     v != ONE;
    |     ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() > error_margin`
 
 error: strict comparison of `f32` or `f64` constant arrays
-  --> tests/ui/float_cmp_const.rs:64:5
+  --> tests/ui/float_cmp_const.rs:63:5
    |
 LL |     NON_ZERO_ARRAY == NON_ZERO_ARRAY2;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/float_equality_without_abs.rs b/src/tools/clippy/tests/ui/float_equality_without_abs.rs
index 2b67c8bec10..500b3035390 100644
--- a/src/tools/clippy/tests/ui/float_equality_without_abs.rs
+++ b/src/tools/clippy/tests/ui/float_equality_without_abs.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::float_equality_without_abs)]
-//@no-rustfix
+//@no-rustfix: suggestions cause type ambiguity
 
 // FIXME(f16_f128): add tests for these types when abs is available
 
diff --git a/src/tools/clippy/tests/ui/get_unwrap.fixed b/src/tools/clippy/tests/ui/get_unwrap.fixed
index 62beb195939..2dd3c30a4e2 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.fixed
+++ b/src/tools/clippy/tests/ui/get_unwrap.fixed
@@ -70,6 +70,7 @@ fn main() {
 mod issue9909 {
     #![allow(clippy::identity_op, clippy::unwrap_used, dead_code)]
 
+    #[allow(unconditional_panic)]
     fn reduced() {
         let f = &[1, 2, 3];
 
diff --git a/src/tools/clippy/tests/ui/get_unwrap.rs b/src/tools/clippy/tests/ui/get_unwrap.rs
index 1e09ff5c67e..94226564cac 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.rs
+++ b/src/tools/clippy/tests/ui/get_unwrap.rs
@@ -70,6 +70,7 @@ fn main() {
 mod issue9909 {
     #![allow(clippy::identity_op, clippy::unwrap_used, dead_code)]
 
+    #[allow(unconditional_panic)]
     fn reduced() {
         let f = &[1, 2, 3];
 
diff --git a/src/tools/clippy/tests/ui/get_unwrap.stderr b/src/tools/clippy/tests/ui/get_unwrap.stderr
index 0f8b279da1e..8eacb249c60 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/get_unwrap.stderr
@@ -266,7 +266,7 @@ LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a slice
-  --> tests/ui/get_unwrap.rs:77:24
+  --> tests/ui/get_unwrap.rs:78:24
    |
 LL |         let _x: &i32 = f.get(1 + 2).unwrap();
    |                        ^^^^^^^^^^^^^^^^^^^^^
@@ -277,7 +277,7 @@ LL |         let _x: &i32 = &f[1 + 2];
    |                        ~~~~~~~~~
 
 error: called `.get().unwrap()` on a slice
-  --> tests/ui/get_unwrap.rs:80:18
+  --> tests/ui/get_unwrap.rs:81:18
    |
 LL |         let _x = f.get(1 + 2).unwrap().to_string();
    |                  ^^^^^^^^^^^^^^^^^^^^^
@@ -288,7 +288,7 @@ LL |         let _x = f[1 + 2].to_string();
    |                  ~~~~~~~~
 
 error: called `.get().unwrap()` on a slice
-  --> tests/ui/get_unwrap.rs:83:18
+  --> tests/ui/get_unwrap.rs:84:18
    |
 LL |         let _x = f.get(1 + 2).unwrap().abs();
    |                  ^^^^^^^^^^^^^^^^^^^^^
@@ -299,7 +299,7 @@ LL |         let _x = f[1 + 2].abs();
    |                  ~~~~~~~~
 
 error: called `.get_mut().unwrap()` on a slice
-  --> tests/ui/get_unwrap.rs:100:33
+  --> tests/ui/get_unwrap.rs:101:33
    |
 LL |                         let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap();
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs
index 5bbdabcaad1..a4cb50bd682 100644
--- a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs
+++ b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs
@@ -1,5 +1,5 @@
 #![deny(clippy::index_refutable_slice)]
-#![allow(clippy::uninlined_format_args)]
+#![allow(clippy::uninlined_format_args, clippy::needless_lifetimes)]
 
 //@no-rustfix: need to change the suggestion to a multipart suggestion
 
diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed
index eeddc2349a1..092e875a255 100644
--- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed
+++ b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed
@@ -24,11 +24,8 @@ fn main() {
         let _a: A = std::ptr::read_volatile(core::ptr::NonNull::dangling().as_ptr());
 
         let _a: A = std::ptr::replace(core::ptr::NonNull::dangling().as_ptr(), A);
-
-        let _slice: *const [usize] = std::ptr::slice_from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0);
-        let _slice: *const [usize] = std::ptr::slice_from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0);
-
-        let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(core::ptr::NonNull::dangling().as_ptr(), 0);
+        let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null_mut(), 0); // shouldn't lint
+        let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(std::ptr::null_mut(), 0);
 
         std::ptr::swap::<A>(core::ptr::NonNull::dangling().as_ptr(), &mut A);
         std::ptr::swap::<A>(&mut A, core::ptr::NonNull::dangling().as_ptr());
diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs
index 8569b774084..480b6642a3e 100644
--- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs
+++ b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs
@@ -24,10 +24,7 @@ fn main() {
         let _a: A = std::ptr::read_volatile(std::ptr::null_mut());
 
         let _a: A = std::ptr::replace(std::ptr::null_mut(), A);
-
-        let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null(), 0);
-        let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null_mut(), 0);
-
+        let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null_mut(), 0); // shouldn't lint
         let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(std::ptr::null_mut(), 0);
 
         std::ptr::swap::<A>(std::ptr::null_mut(), &mut A);
diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.stderr b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.stderr
index 54d79ba1aeb..a0be2c0ad75 100644
--- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.stderr
+++ b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.stderr
@@ -85,70 +85,52 @@ LL |         let _a: A = std::ptr::replace(std::ptr::null_mut(), A);
    |                                       ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
 
 error: pointer must be non-null
-  --> tests/ui/invalid_null_ptr_usage.rs:28:69
-   |
-LL |         let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null(), 0);
-   |                                                                     ^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
-
-error: pointer must be non-null
-  --> tests/ui/invalid_null_ptr_usage.rs:29:69
-   |
-LL |         let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null_mut(), 0);
-   |                                                                     ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
-
-error: pointer must be non-null
-  --> tests/ui/invalid_null_ptr_usage.rs:31:73
-   |
-LL |         let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(std::ptr::null_mut(), 0);
-   |                                                                         ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
-
-error: pointer must be non-null
-  --> tests/ui/invalid_null_ptr_usage.rs:33:29
+  --> tests/ui/invalid_null_ptr_usage.rs:30:29
    |
 LL |         std::ptr::swap::<A>(std::ptr::null_mut(), &mut A);
    |                             ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
 
 error: pointer must be non-null
-  --> tests/ui/invalid_null_ptr_usage.rs:34:37
+  --> tests/ui/invalid_null_ptr_usage.rs:31:37
    |
 LL |         std::ptr::swap::<A>(&mut A, std::ptr::null_mut());
    |                                     ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
 
 error: pointer must be non-null
-  --> tests/ui/invalid_null_ptr_usage.rs:36:44
+  --> tests/ui/invalid_null_ptr_usage.rs:33:44
    |
 LL |         std::ptr::swap_nonoverlapping::<A>(std::ptr::null_mut(), &mut A, 0);
    |                                            ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
 
 error: pointer must be non-null
-  --> tests/ui/invalid_null_ptr_usage.rs:37:52
+  --> tests/ui/invalid_null_ptr_usage.rs:34:52
    |
 LL |         std::ptr::swap_nonoverlapping::<A>(&mut A, std::ptr::null_mut(), 0);
    |                                                    ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
 
 error: pointer must be non-null
-  --> tests/ui/invalid_null_ptr_usage.rs:39:25
+  --> tests/ui/invalid_null_ptr_usage.rs:36:25
    |
 LL |         std::ptr::write(std::ptr::null_mut(), A);
    |                         ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
 
 error: pointer must be non-null
-  --> tests/ui/invalid_null_ptr_usage.rs:41:35
+  --> tests/ui/invalid_null_ptr_usage.rs:38:35
    |
 LL |         std::ptr::write_unaligned(std::ptr::null_mut(), A);
    |                                   ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
 
 error: pointer must be non-null
-  --> tests/ui/invalid_null_ptr_usage.rs:43:34
+  --> tests/ui/invalid_null_ptr_usage.rs:40:34
    |
 LL |         std::ptr::write_volatile(std::ptr::null_mut(), A);
    |                                  ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
 
 error: pointer must be non-null
-  --> tests/ui/invalid_null_ptr_usage.rs:45:40
+  --> tests/ui/invalid_null_ptr_usage.rs:42:40
    |
 LL |         std::ptr::write_bytes::<usize>(std::ptr::null_mut(), 42, 0);
    |                                        ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
 
-error: aborting due to 25 previous errors
+error: aborting due to 22 previous errors
 
diff --git a/src/tools/clippy/tests/ui/iter_without_into_iter.rs b/src/tools/clippy/tests/ui/iter_without_into_iter.rs
index 3054d848efb..d5b28e45453 100644
--- a/src/tools/clippy/tests/ui/iter_without_into_iter.rs
+++ b/src/tools/clippy/tests/ui/iter_without_into_iter.rs
@@ -1,6 +1,7 @@
 //@no-rustfix
 //@aux-build:proc_macros.rs
 #![warn(clippy::iter_without_into_iter)]
+#![allow(clippy::needless_lifetimes)]
 extern crate proc_macros;
 
 pub struct S1;
diff --git a/src/tools/clippy/tests/ui/iter_without_into_iter.stderr b/src/tools/clippy/tests/ui/iter_without_into_iter.stderr
index 382a7606f48..7c42fa1dd89 100644
--- a/src/tools/clippy/tests/ui/iter_without_into_iter.stderr
+++ b/src/tools/clippy/tests/ui/iter_without_into_iter.stderr
@@ -1,5 +1,5 @@
 error: `iter` method without an `IntoIterator` impl for `&S1`
-  --> tests/ui/iter_without_into_iter.rs:8:5
+  --> tests/ui/iter_without_into_iter.rs:9:5
    |
 LL | /     pub fn iter(&self) -> std::slice::Iter<'_, u8> {
 LL | |
@@ -22,7 +22,7 @@ LL + }
    |
 
 error: `iter_mut` method without an `IntoIterator` impl for `&mut S1`
-  --> tests/ui/iter_without_into_iter.rs:12:5
+  --> tests/ui/iter_without_into_iter.rs:13:5
    |
 LL | /     pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> {
 LL | |
@@ -43,7 +43,7 @@ LL + }
    |
 
 error: `iter` method without an `IntoIterator` impl for `&S3<'a>`
-  --> tests/ui/iter_without_into_iter.rs:28:5
+  --> tests/ui/iter_without_into_iter.rs:29:5
    |
 LL | /     pub fn iter(&self) -> std::slice::Iter<'_, u8> {
 LL | |
@@ -64,7 +64,7 @@ LL + }
    |
 
 error: `iter_mut` method without an `IntoIterator` impl for `&mut S3<'a>`
-  --> tests/ui/iter_without_into_iter.rs:32:5
+  --> tests/ui/iter_without_into_iter.rs:33:5
    |
 LL | /     pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> {
 LL | |
@@ -85,7 +85,7 @@ LL + }
    |
 
 error: `iter` method without an `IntoIterator` impl for `&S8<T>`
-  --> tests/ui/iter_without_into_iter.rs:69:5
+  --> tests/ui/iter_without_into_iter.rs:70:5
    |
 LL | /     pub fn iter(&self) -> std::slice::Iter<'static, T> {
 LL | |         todo!()
@@ -105,7 +105,7 @@ LL + }
    |
 
 error: `iter` method without an `IntoIterator` impl for `&S9<T>`
-  --> tests/ui/iter_without_into_iter.rs:77:5
+  --> tests/ui/iter_without_into_iter.rs:78:5
    |
 LL | /     pub fn iter(&self) -> std::slice::Iter<'_, T> {
 LL | |
@@ -126,7 +126,7 @@ LL + }
    |
 
 error: `iter_mut` method without an `IntoIterator` impl for `&mut S9<T>`
-  --> tests/ui/iter_without_into_iter.rs:81:5
+  --> tests/ui/iter_without_into_iter.rs:82:5
    |
 LL | /     pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
 LL | |
@@ -147,7 +147,7 @@ LL + }
    |
 
 error: `iter` method without an `IntoIterator` impl for `&Issue12037`
-  --> tests/ui/iter_without_into_iter.rs:130:13
+  --> tests/ui/iter_without_into_iter.rs:131:13
    |
 LL | /             fn iter(&self) -> std::slice::Iter<'_, u8> {
 LL | |                 todo!()
diff --git a/src/tools/clippy/tests/ui/mem_replace.fixed b/src/tools/clippy/tests/ui/mem_replace.fixed
index 78d8b3e9bce..4210dbbe82d 100644
--- a/src/tools/clippy/tests/ui/mem_replace.fixed
+++ b/src/tools/clippy/tests/ui/mem_replace.fixed
@@ -1,6 +1,5 @@
-#![allow(unused)]
+#![allow(unused, clippy::needless_lifetimes)]
 #![warn(
-    clippy::all,
     clippy::style,
     clippy::mem_replace_option_with_none,
     clippy::mem_replace_with_default
diff --git a/src/tools/clippy/tests/ui/mem_replace.rs b/src/tools/clippy/tests/ui/mem_replace.rs
index 28915bf6dae..bd7ad78b2af 100644
--- a/src/tools/clippy/tests/ui/mem_replace.rs
+++ b/src/tools/clippy/tests/ui/mem_replace.rs
@@ -1,6 +1,5 @@
-#![allow(unused)]
+#![allow(unused, clippy::needless_lifetimes)]
 #![warn(
-    clippy::all,
     clippy::style,
     clippy::mem_replace_option_with_none,
     clippy::mem_replace_with_default
diff --git a/src/tools/clippy/tests/ui/mem_replace.stderr b/src/tools/clippy/tests/ui/mem_replace.stderr
index 44be2c9b63d..c33f80b01b8 100644
--- a/src/tools/clippy/tests/ui/mem_replace.stderr
+++ b/src/tools/clippy/tests/ui/mem_replace.stderr
@@ -1,5 +1,5 @@
 error: replacing an `Option` with `None`
-  --> tests/ui/mem_replace.rs:14:13
+  --> tests/ui/mem_replace.rs:13:13
    |
 LL |     let _ = mem::replace(&mut an_option, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
@@ -8,13 +8,13 @@ LL |     let _ = mem::replace(&mut an_option, None);
    = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_none)]`
 
 error: replacing an `Option` with `None`
-  --> tests/ui/mem_replace.rs:16:13
+  --> tests/ui/mem_replace.rs:15:13
    |
 LL |     let _ = mem::replace(an_option, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:21:13
+  --> tests/ui/mem_replace.rs:20:13
    |
 LL |     let _ = std::mem::replace(&mut s, String::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)`
@@ -23,127 +23,127 @@ LL |     let _ = std::mem::replace(&mut s, String::default());
    = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_default)]`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:24:13
+  --> tests/ui/mem_replace.rs:23:13
    |
 LL |     let _ = std::mem::replace(s, String::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:25:13
+  --> tests/ui/mem_replace.rs:24:13
    |
 LL |     let _ = std::mem::replace(s, Default::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:28:13
+  --> tests/ui/mem_replace.rs:27:13
    |
 LL |     let _ = std::mem::replace(&mut v, Vec::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:29:13
+  --> tests/ui/mem_replace.rs:28:13
    |
 LL |     let _ = std::mem::replace(&mut v, Default::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:30:13
+  --> tests/ui/mem_replace.rs:29:13
    |
 LL |     let _ = std::mem::replace(&mut v, Vec::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:31:13
+  --> tests/ui/mem_replace.rs:30:13
    |
 LL |     let _ = std::mem::replace(&mut v, vec![]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:34:13
+  --> tests/ui/mem_replace.rs:33:13
    |
 LL |     let _ = std::mem::replace(&mut hash_map, HashMap::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_map)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:37:13
+  --> tests/ui/mem_replace.rs:36:13
    |
 LL |     let _ = std::mem::replace(&mut btree_map, BTreeMap::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_map)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:40:13
+  --> tests/ui/mem_replace.rs:39:13
    |
 LL |     let _ = std::mem::replace(&mut vd, VecDeque::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut vd)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:43:13
+  --> tests/ui/mem_replace.rs:42:13
    |
 LL |     let _ = std::mem::replace(&mut hash_set, HashSet::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_set)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:46:13
+  --> tests/ui/mem_replace.rs:45:13
    |
 LL |     let _ = std::mem::replace(&mut btree_set, BTreeSet::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_set)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:49:13
+  --> tests/ui/mem_replace.rs:48:13
    |
 LL |     let _ = std::mem::replace(&mut list, LinkedList::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut list)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:52:13
+  --> tests/ui/mem_replace.rs:51:13
    |
 LL |     let _ = std::mem::replace(&mut binary_heap, BinaryHeap::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut binary_heap)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:55:13
+  --> tests/ui/mem_replace.rs:54:13
    |
 LL |     let _ = std::mem::replace(&mut tuple, (vec![], BinaryHeap::new()));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut tuple)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:58:13
+  --> tests/ui/mem_replace.rs:57:13
    |
 LL |     let _ = std::mem::replace(&mut refstr, "");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut refstr)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:61:13
+  --> tests/ui/mem_replace.rs:60:13
    |
 LL |     let _ = std::mem::replace(&mut slice, &[]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut slice)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:97:13
+  --> tests/ui/mem_replace.rs:96:13
    |
 LL |     let _ = std::mem::replace(&mut s, String::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)`
 
 error: replacing an `Option` with `None`
-  --> tests/ui/mem_replace.rs:127:13
+  --> tests/ui/mem_replace.rs:126:13
    |
 LL |     let _ = std::mem::replace(&mut f.0, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `f.0.take()`
 
 error: replacing an `Option` with `None`
-  --> tests/ui/mem_replace.rs:128:13
+  --> tests/ui/mem_replace.rs:127:13
    |
 LL |     let _ = std::mem::replace(&mut *f, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `(*f).take()`
 
 error: replacing an `Option` with `None`
-  --> tests/ui/mem_replace.rs:129:13
+  --> tests/ui/mem_replace.rs:128:13
    |
 LL |     let _ = std::mem::replace(&mut b.opt, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `b.opt.take()`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:131:13
+  --> tests/ui/mem_replace.rs:130:13
    |
 LL |     let _ = std::mem::replace(&mut b.val, String::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut b.val)`
diff --git a/src/tools/clippy/tests/ui/mem_replace_no_std.fixed b/src/tools/clippy/tests/ui/mem_replace_no_std.fixed
index c970f2ba281..60f523c8ef1 100644
--- a/src/tools/clippy/tests/ui/mem_replace_no_std.fixed
+++ b/src/tools/clippy/tests/ui/mem_replace_no_std.fixed
@@ -1,6 +1,5 @@
-#![allow(unused)]
+#![allow(unused, clippy::needless_lifetimes)]
 #![warn(
-    clippy::all,
     clippy::style,
     clippy::mem_replace_option_with_none,
     clippy::mem_replace_with_default
diff --git a/src/tools/clippy/tests/ui/mem_replace_no_std.rs b/src/tools/clippy/tests/ui/mem_replace_no_std.rs
index 673d5c7b4f4..d1cb9a5817b 100644
--- a/src/tools/clippy/tests/ui/mem_replace_no_std.rs
+++ b/src/tools/clippy/tests/ui/mem_replace_no_std.rs
@@ -1,6 +1,5 @@
-#![allow(unused)]
+#![allow(unused, clippy::needless_lifetimes)]
 #![warn(
-    clippy::all,
     clippy::style,
     clippy::mem_replace_option_with_none,
     clippy::mem_replace_with_default
diff --git a/src/tools/clippy/tests/ui/mem_replace_no_std.stderr b/src/tools/clippy/tests/ui/mem_replace_no_std.stderr
index eea538da427..6ba6d2162a7 100644
--- a/src/tools/clippy/tests/ui/mem_replace_no_std.stderr
+++ b/src/tools/clippy/tests/ui/mem_replace_no_std.stderr
@@ -1,5 +1,5 @@
 error: replacing an `Option` with `None`
-  --> tests/ui/mem_replace_no_std.rs:24:13
+  --> tests/ui/mem_replace_no_std.rs:23:13
    |
 LL |     let _ = mem::replace(&mut an_option, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
@@ -8,13 +8,13 @@ LL |     let _ = mem::replace(&mut an_option, None);
    = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_none)]`
 
 error: replacing an `Option` with `None`
-  --> tests/ui/mem_replace_no_std.rs:26:13
+  --> tests/ui/mem_replace_no_std.rs:25:13
    |
 LL |     let _ = mem::replace(an_option, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `core::mem::take`
-  --> tests/ui/mem_replace_no_std.rs:31:13
+  --> tests/ui/mem_replace_no_std.rs:30:13
    |
 LL |     let _ = mem::replace(&mut refstr, "");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::mem::take(&mut refstr)`
@@ -23,25 +23,25 @@ LL |     let _ = mem::replace(&mut refstr, "");
    = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_default)]`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `core::mem::take`
-  --> tests/ui/mem_replace_no_std.rs:34:13
+  --> tests/ui/mem_replace_no_std.rs:33:13
    |
 LL |     let _ = mem::replace(&mut slice, &[]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::mem::take(&mut slice)`
 
 error: replacing an `Option` with `None`
-  --> tests/ui/mem_replace_no_std.rs:77:13
+  --> tests/ui/mem_replace_no_std.rs:76:13
    |
 LL |     let _ = mem::replace(&mut f.0, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `f.0.take()`
 
 error: replacing an `Option` with `None`
-  --> tests/ui/mem_replace_no_std.rs:78:13
+  --> tests/ui/mem_replace_no_std.rs:77:13
    |
 LL |     let _ = mem::replace(&mut *f, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `(*f).take()`
 
 error: replacing an `Option` with `None`
-  --> tests/ui/mem_replace_no_std.rs:79:13
+  --> tests/ui/mem_replace_no_std.rs:78:13
    |
 LL |     let _ = mem::replace(&mut b.opt, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `b.opt.take()`
diff --git a/src/tools/clippy/tests/ui/mismatching_type_param_order.rs b/src/tools/clippy/tests/ui/mismatching_type_param_order.rs
index af2882e41fb..a4560f9e9a9 100644
--- a/src/tools/clippy/tests/ui/mismatching_type_param_order.rs
+++ b/src/tools/clippy/tests/ui/mismatching_type_param_order.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::mismatching_type_param_order)]
-#![allow(clippy::disallowed_names)]
+#![allow(clippy::disallowed_names, clippy::needless_lifetimes)]
 
 fn main() {
     struct Foo<A, B> {
diff --git a/src/tools/clippy/tests/ui/mut_mutex_lock.fixed b/src/tools/clippy/tests/ui/mut_mutex_lock.fixed
index bbedbb2bed2..29c5a27cb62 100644
--- a/src/tools/clippy/tests/ui/mut_mutex_lock.fixed
+++ b/src/tools/clippy/tests/ui/mut_mutex_lock.fixed
@@ -9,6 +9,11 @@ fn mut_mutex_lock() {
 
     let mut value = value_mutex.get_mut().unwrap();
     *value += 1;
+
+    let mut value_mutex = Mutex::new(42_u8);
+    let mut_ref_mut_ref_mutex = &mut &mut value_mutex;
+    let mut value = mut_ref_mut_ref_mutex.get_mut().unwrap();
+    *value += 1;
 }
 
 fn no_owned_mutex_lock() {
@@ -24,4 +29,11 @@ fn issue9415() {
     *guard += 1;
 }
 
+fn mut_ref_ref_mutex_lock() {
+    let mutex = Mutex::new(42_u8);
+    let mut_ref_ref_mutex = &mut &mutex;
+    let mut guard = mut_ref_ref_mutex.lock().unwrap();
+    *guard += 1;
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/mut_mutex_lock.rs b/src/tools/clippy/tests/ui/mut_mutex_lock.rs
index 74116100e82..fcdb3ff97db 100644
--- a/src/tools/clippy/tests/ui/mut_mutex_lock.rs
+++ b/src/tools/clippy/tests/ui/mut_mutex_lock.rs
@@ -9,6 +9,11 @@ fn mut_mutex_lock() {
 
     let mut value = value_mutex.lock().unwrap();
     *value += 1;
+
+    let mut value_mutex = Mutex::new(42_u8);
+    let mut_ref_mut_ref_mutex = &mut &mut value_mutex;
+    let mut value = mut_ref_mut_ref_mutex.lock().unwrap();
+    *value += 1;
 }
 
 fn no_owned_mutex_lock() {
@@ -24,4 +29,11 @@ fn issue9415() {
     *guard += 1;
 }
 
+fn mut_ref_ref_mutex_lock() {
+    let mutex = Mutex::new(42_u8);
+    let mut_ref_ref_mutex = &mut &mutex;
+    let mut guard = mut_ref_ref_mutex.lock().unwrap();
+    *guard += 1;
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/mut_mutex_lock.stderr b/src/tools/clippy/tests/ui/mut_mutex_lock.stderr
index a3d4905c04c..92601c4c612 100644
--- a/src/tools/clippy/tests/ui/mut_mutex_lock.stderr
+++ b/src/tools/clippy/tests/ui/mut_mutex_lock.stderr
@@ -7,5 +7,11 @@ LL |     let mut value = value_mutex.lock().unwrap();
    = note: `-D clippy::mut-mutex-lock` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::mut_mutex_lock)]`
 
-error: aborting due to 1 previous error
+error: calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference
+  --> tests/ui/mut_mutex_lock.rs:15:43
+   |
+LL |     let mut value = mut_ref_mut_ref_mutex.lock().unwrap();
+   |                                           ^^^^ help: change this to: `get_mut`
+
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed
index cabdc22bda8..2763830e09c 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrow.fixed
@@ -4,7 +4,8 @@
     clippy::uninlined_format_args,
     clippy::unnecessary_mut_passed,
     clippy::unnecessary_to_owned,
-    clippy::unnecessary_literal_unwrap
+    clippy::unnecessary_literal_unwrap,
+    clippy::needless_lifetimes
 )]
 #![warn(clippy::needless_borrow)]
 
diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs
index 50062589645..b46f82b18c6 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.rs
+++ b/src/tools/clippy/tests/ui/needless_borrow.rs
@@ -4,7 +4,8 @@
     clippy::uninlined_format_args,
     clippy::unnecessary_mut_passed,
     clippy::unnecessary_to_owned,
-    clippy::unnecessary_literal_unwrap
+    clippy::unnecessary_literal_unwrap,
+    clippy::needless_lifetimes
 )]
 #![warn(clippy::needless_borrow)]
 
diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr
index bf0e265c250..4b2b17e7e57 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrow.stderr
@@ -1,5 +1,5 @@
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:15:15
+  --> tests/ui/needless_borrow.rs:16:15
    |
 LL |     let _ = x(&&a); // warn
    |               ^^^ help: change this to: `&a`
@@ -8,163 +8,163 @@ LL |     let _ = x(&&a); // warn
    = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:19:13
+  --> tests/ui/needless_borrow.rs:20:13
    |
 LL |     mut_ref(&mut &mut b); // warn
    |             ^^^^^^^^^^^ help: change this to: `&mut b`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:31:13
+  --> tests/ui/needless_borrow.rs:32:13
    |
 LL |             &&a
    |             ^^^ help: change this to: `&a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:33:15
+  --> tests/ui/needless_borrow.rs:34:15
    |
 LL |         46 => &&a,
    |               ^^^ help: change this to: `&a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:39:27
+  --> tests/ui/needless_borrow.rs:40:27
    |
 LL |                     break &ref_a;
    |                           ^^^^^^ help: change this to: `ref_a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:46:15
+  --> tests/ui/needless_borrow.rs:47:15
    |
 LL |     let _ = x(&&&a);
    |               ^^^^ help: change this to: `&a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:47:15
+  --> tests/ui/needless_borrow.rs:48:15
    |
 LL |     let _ = x(&mut &&a);
    |               ^^^^^^^^ help: change this to: `&a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:48:15
+  --> tests/ui/needless_borrow.rs:49:15
    |
 LL |     let _ = x(&&&mut b);
    |               ^^^^^^^^ help: change this to: `&mut b`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:49:15
+  --> tests/ui/needless_borrow.rs:50:15
    |
 LL |     let _ = x(&&ref_a);
    |               ^^^^^^^ help: change this to: `ref_a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:52:11
+  --> tests/ui/needless_borrow.rs:53:11
    |
 LL |         x(&b);
    |           ^^ help: change this to: `b`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:59:13
+  --> tests/ui/needless_borrow.rs:60:13
    |
 LL |     mut_ref(&mut x);
    |             ^^^^^^ help: change this to: `x`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:60:13
+  --> tests/ui/needless_borrow.rs:61:13
    |
 LL |     mut_ref(&mut &mut x);
    |             ^^^^^^^^^^^ help: change this to: `x`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:61:23
+  --> tests/ui/needless_borrow.rs:62:23
    |
 LL |     let y: &mut i32 = &mut x;
    |                       ^^^^^^ help: change this to: `x`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:62:23
+  --> tests/ui/needless_borrow.rs:63:23
    |
 LL |     let y: &mut i32 = &mut &mut x;
    |                       ^^^^^^^^^^^ help: change this to: `x`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:71:14
+  --> tests/ui/needless_borrow.rs:72:14
    |
 LL |         0 => &mut x,
    |              ^^^^^^ help: change this to: `x`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:77:14
+  --> tests/ui/needless_borrow.rs:78:14
    |
 LL |         0 => &mut x,
    |              ^^^^^^ help: change this to: `x`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:89:13
+  --> tests/ui/needless_borrow.rs:90:13
    |
 LL |     let _ = (&x).0;
    |             ^^^^ help: change this to: `x`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:91:22
+  --> tests/ui/needless_borrow.rs:92:22
    |
 LL |     let _ = unsafe { (&*x).0 };
    |                      ^^^^^ help: change this to: `(*x)`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:101:5
+  --> tests/ui/needless_borrow.rs:102:5
    |
 LL |     (&&()).foo();
    |     ^^^^^^ help: change this to: `(&())`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:110:5
+  --> tests/ui/needless_borrow.rs:111:5
    |
 LL |     (&&5).foo();
    |     ^^^^^ help: change this to: `(&5)`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:136:23
+  --> tests/ui/needless_borrow.rs:137:23
    |
 LL |     let x: (&str,) = (&"",);
    |                       ^^^ help: change this to: `""`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:178:13
+  --> tests/ui/needless_borrow.rs:179:13
    |
 LL |             (&self.f)()
    |             ^^^^^^^^^ help: change this to: `(self.f)`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:187:13
+  --> tests/ui/needless_borrow.rs:188:13
    |
 LL |             (&mut self.f)()
    |             ^^^^^^^^^^^^^ help: change this to: `(self.f)`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:224:22
+  --> tests/ui/needless_borrow.rs:225:22
    |
 LL |         let _ = &mut (&mut { x.u }).x;
    |                      ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:231:22
+  --> tests/ui/needless_borrow.rs:232:22
    |
 LL |         let _ = &mut (&mut { x.u }).x;
    |                      ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:235:22
+  --> tests/ui/needless_borrow.rs:236:22
    |
 LL |         let _ = &mut (&mut x.u).x;
    |                      ^^^^^^^^^^ help: change this to: `x.u`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:236:22
+  --> tests/ui/needless_borrow.rs:237:22
    |
 LL |         let _ = &mut (&mut { x.u }).x;
    |                      ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:257:23
+  --> tests/ui/needless_borrow.rs:258:23
    |
 LL |     option.unwrap_or((&x.0,));
    |                       ^^^^ help: change this to: `x.0`
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.fixed b/src/tools/clippy/tests/ui/needless_lifetimes.fixed
index d1787b35abd..cfa4cf9da3c 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.fixed
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.fixed
@@ -329,7 +329,7 @@ mod issue2944 {
         bar: &'a Bar,
     }
 
-    impl<'a> Foo for Baz<'a> {}
+    impl Foo for Baz<'_> {}
     impl Bar {
         fn baz(&self) -> impl Foo + '_ {
             Baz { bar: self }
@@ -384,7 +384,7 @@ mod nested_elision_sites {
         f()
     }
     // lint
-    fn where_clause_elidadable<T>(i: &i32, f: T) -> &i32
+    fn where_clause_elidable<T>(i: &i32, f: T) -> &i32
     where
         T: Fn(&i32) -> &i32,
     {
@@ -543,4 +543,23 @@ mod issue5787 {
     }
 }
 
+// https://github.com/rust-lang/rust-clippy/pull/13286#issuecomment-2374245772
+mod rayon {
+    trait ParallelIterator {
+        type Item;
+    }
+
+    struct Copied<I: ParallelIterator> {
+        base: I,
+    }
+
+    impl<'a, T, I> ParallelIterator for Copied<I>
+    where
+        I: ParallelIterator<Item = &'a T>,
+        T: 'a + Copy + Send + Sync,
+    {
+        type Item = T;
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs
index 03d6f201358..5e9d5116426 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.rs
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs
@@ -384,7 +384,7 @@ mod nested_elision_sites {
         f()
     }
     // lint
-    fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
+    fn where_clause_elidable<'a, T>(i: &'a i32, f: T) -> &'a i32
     where
         T: Fn(&i32) -> &i32,
     {
@@ -543,4 +543,23 @@ mod issue5787 {
     }
 }
 
+// https://github.com/rust-lang/rust-clippy/pull/13286#issuecomment-2374245772
+mod rayon {
+    trait ParallelIterator {
+        type Item;
+    }
+
+    struct Copied<I: ParallelIterator> {
+        base: I,
+    }
+
+    impl<'a, T, I> ParallelIterator for Copied<I>
+    where
+        I: ParallelIterator<Item = &'a T>,
+        T: 'a + Copy + Send + Sync,
+    {
+        type Item = T;
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
index 50f845e2d92..e56c914cc86 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.stderr
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
@@ -336,6 +336,18 @@ LL +         fn needless_lt(_x: &u8) {}
    |
 
 error: the following explicit lifetimes could be elided: 'a
+  --> tests/ui/needless_lifetimes.rs:332:10
+   |
+LL |     impl<'a> Foo for Baz<'a> {}
+   |          ^^              ^^
+   |
+help: elide the lifetimes
+   |
+LL -     impl<'a> Foo for Baz<'a> {}
+LL +     impl Foo for Baz<'_> {}
+   |
+
+error: the following explicit lifetimes could be elided: 'a
   --> tests/ui/needless_lifetimes.rs:334:16
    |
 LL |         fn baz<'a>(&'a self) -> impl Foo + 'a {
@@ -372,15 +384,15 @@ LL +     fn generics_elidable<T: Fn(&i32) -> &i32>(i: &i32, f: T) -> &i32 {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:387:32
+  --> tests/ui/needless_lifetimes.rs:387:30
    |
-LL |     fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
-   |                                ^^         ^^                ^^
+LL |     fn where_clause_elidable<'a, T>(i: &'a i32, f: T) -> &'a i32
+   |                              ^^         ^^                ^^
    |
 help: elide the lifetimes
    |
-LL -     fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
-LL +     fn where_clause_elidadable<T>(i: &i32, f: T) -> &i32
+LL -     fn where_clause_elidable<'a, T>(i: &'a i32, f: T) -> &'a i32
+LL +     fn where_clause_elidable<T>(i: &i32, f: T) -> &i32
    |
 
 error: the following explicit lifetimes could be elided: 'a
@@ -564,5 +576,5 @@ LL -         fn one_input<'a>(x: &'a u8) -> &'a u8 {
 LL +         fn one_input(x: &u8) -> &u8 {
    |
 
-error: aborting due to 47 previous errors
+error: aborting due to 48 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_value.rs b/src/tools/clippy/tests/ui/needless_pass_by_value.rs
index 9408b8c948f..a8d9db95dcc 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_value.rs
+++ b/src/tools/clippy/tests/ui/needless_pass_by_value.rs
@@ -5,7 +5,8 @@
     clippy::redundant_clone,
     clippy::redundant_pattern_matching,
     clippy::single_match,
-    clippy::uninlined_format_args
+    clippy::uninlined_format_args,
+    clippy::needless_lifetimes
 )]
 //@no-rustfix
 use std::borrow::Borrow;
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_value.stderr b/src/tools/clippy/tests/ui/needless_pass_by_value.stderr
index 46ef8f3e8da..2587d3f8c52 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_value.stderr
+++ b/src/tools/clippy/tests/ui/needless_pass_by_value.stderr
@@ -1,5 +1,5 @@
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:18:23
+  --> tests/ui/needless_pass_by_value.rs:19:23
    |
 LL | fn foo<T: Default>(v: Vec<T>, w: Vec<T>, mut x: Vec<T>, y: Vec<T>) -> Vec<T> {
    |                       ^^^^^^ help: consider changing the type to: `&[T]`
@@ -8,55 +8,55 @@ LL | fn foo<T: Default>(v: Vec<T>, w: Vec<T>, mut x: Vec<T>, y: Vec<T>) -> Vec<T
    = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_value)]`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:34:11
+  --> tests/ui/needless_pass_by_value.rs:35:11
    |
 LL | fn bar(x: String, y: Wrapper) {
    |           ^^^^^^ help: consider changing the type to: `&str`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:34:22
+  --> tests/ui/needless_pass_by_value.rs:35:22
    |
 LL | fn bar(x: String, y: Wrapper) {
    |                      ^^^^^^^ help: consider taking a reference instead: `&Wrapper`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:42:71
+  --> tests/ui/needless_pass_by_value.rs:43:71
    |
 LL | fn test_borrow_trait<T: Borrow<str>, U: AsRef<str>, V>(t: T, u: U, v: V) {
    |                                                                       ^ help: consider taking a reference instead: `&V`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:55:18
+  --> tests/ui/needless_pass_by_value.rs:56:18
    |
 LL | fn test_match(x: Option<Option<String>>, y: Option<Option<String>>) {
    |                  ^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&Option<Option<String>>`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:69:24
+  --> tests/ui/needless_pass_by_value.rs:70:24
    |
 LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) {
    |                        ^^^^^^^ help: consider taking a reference instead: `&Wrapper`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:69:36
+  --> tests/ui/needless_pass_by_value.rs:70:36
    |
 LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) {
    |                                    ^^^^^^^ help: consider taking a reference instead: `&Wrapper`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:87:49
+  --> tests/ui/needless_pass_by_value.rs:88:49
    |
 LL | fn test_blanket_ref<T: Foo, S: Serialize>(vals: T, serializable: S) {}
    |                                                 ^ help: consider taking a reference instead: `&T`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:90:18
+  --> tests/ui/needless_pass_by_value.rs:91:18
    |
 LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
    |                  ^^^^^^ help: consider taking a reference instead: `&String`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:90:29
+  --> tests/ui/needless_pass_by_value.rs:91:29
    |
 LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
    |                             ^^^^^^
@@ -71,13 +71,13 @@ LL |     let _ = t.to_string();
    |             ~~~~~~~~~~~~~
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:90:40
+  --> tests/ui/needless_pass_by_value.rs:91:40
    |
 LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
    |                                        ^^^^^^^^ help: consider taking a reference instead: `&Vec<i32>`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:90:53
+  --> tests/ui/needless_pass_by_value.rs:91:53
    |
 LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
    |                                                     ^^^^^^^^
@@ -92,85 +92,85 @@ LL |     let _ = v.to_owned();
    |             ~~~~~~~~~~~~
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:107:12
+  --> tests/ui/needless_pass_by_value.rs:108:12
    |
 LL |         s: String,
    |            ^^^^^^ help: consider changing the type to: `&str`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:109:12
+  --> tests/ui/needless_pass_by_value.rs:110:12
    |
 LL |         t: String,
    |            ^^^^^^ help: consider taking a reference instead: `&String`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:119:23
+  --> tests/ui/needless_pass_by_value.rs:120:23
    |
 LL |     fn baz(&self, uu: U, ss: Self) {}
    |                       ^ help: consider taking a reference instead: `&U`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:119:30
+  --> tests/ui/needless_pass_by_value.rs:120:30
    |
 LL |     fn baz(&self, uu: U, ss: Self) {}
    |                              ^^^^ help: consider taking a reference instead: `&Self`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:143:24
+  --> tests/ui/needless_pass_by_value.rs:144:24
    |
 LL | fn bar_copy(x: u32, y: CopyWrapper) {
    |                        ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper`
    |
 help: or consider marking this type as `Copy`
-  --> tests/ui/needless_pass_by_value.rs:141:1
+  --> tests/ui/needless_pass_by_value.rs:142:1
    |
 LL | struct CopyWrapper(u32);
    | ^^^^^^^^^^^^^^^^^^
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:150:29
+  --> tests/ui/needless_pass_by_value.rs:151:29
    |
 LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
    |                             ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper`
    |
 help: or consider marking this type as `Copy`
-  --> tests/ui/needless_pass_by_value.rs:141:1
+  --> tests/ui/needless_pass_by_value.rs:142:1
    |
 LL | struct CopyWrapper(u32);
    | ^^^^^^^^^^^^^^^^^^
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:150:45
+  --> tests/ui/needless_pass_by_value.rs:151:45
    |
 LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
    |                                             ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper`
    |
 help: or consider marking this type as `Copy`
-  --> tests/ui/needless_pass_by_value.rs:141:1
+  --> tests/ui/needless_pass_by_value.rs:142:1
    |
 LL | struct CopyWrapper(u32);
    | ^^^^^^^^^^^^^^^^^^
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:150:61
+  --> tests/ui/needless_pass_by_value.rs:151:61
    |
 LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
    |                                                             ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper`
    |
 help: or consider marking this type as `Copy`
-  --> tests/ui/needless_pass_by_value.rs:141:1
+  --> tests/ui/needless_pass_by_value.rs:142:1
    |
 LL | struct CopyWrapper(u32);
    | ^^^^^^^^^^^^^^^^^^
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:165:40
+  --> tests/ui/needless_pass_by_value.rs:166:40
    |
 LL | fn some_fun<'b, S: Bar<'b, ()>>(items: S) {}
    |                                        ^ help: consider taking a reference instead: `&S`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> tests/ui/needless_pass_by_value.rs:171:20
+  --> tests/ui/needless_pass_by_value.rs:172:20
    |
 LL | fn more_fun(items: impl Club<'static, i32>) {}
    |                    ^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&impl Club<'static, i32>`
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index c5c570690b4..ca422e605d6 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -360,3 +360,23 @@ fn issue12907() -> String {
 }
 
 fn main() {}
+
+fn a(x: Option<u8>) -> Option<u8> {
+    match x {
+        Some(_) => None,
+        None => {
+            #[expect(clippy::needless_return, reason = "Use early return for errors.")]
+            return None;
+        },
+    }
+}
+
+fn b(x: Option<u8>) -> Option<u8> {
+    match x {
+        Some(_) => None,
+        None => {
+            #[expect(clippy::needless_return)]
+            return None;
+        },
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index 738611391df..aad6e13136f 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -370,3 +370,23 @@ fn issue12907() -> String {
 }
 
 fn main() {}
+
+fn a(x: Option<u8>) -> Option<u8> {
+    match x {
+        Some(_) => None,
+        None => {
+            #[expect(clippy::needless_return, reason = "Use early return for errors.")]
+            return None;
+        },
+    }
+}
+
+fn b(x: Option<u8>) -> Option<u8> {
+    match x {
+        Some(_) => None,
+        None => {
+            #[expect(clippy::needless_return)]
+            return None;
+        },
+    }
+}
diff --git a/src/tools/clippy/tests/ui/new_without_default.fixed b/src/tools/clippy/tests/ui/new_without_default.fixed
index 85408c4e17f..5a6a92394a7 100644
--- a/src/tools/clippy/tests/ui/new_without_default.fixed
+++ b/src/tools/clippy/tests/ui/new_without_default.fixed
@@ -2,7 +2,8 @@
     dead_code,
     clippy::missing_safety_doc,
     clippy::extra_unused_lifetimes,
-    clippy::extra_unused_type_parameters
+    clippy::extra_unused_type_parameters,
+    clippy::needless_lifetimes
 )]
 #![warn(clippy::new_without_default)]
 
diff --git a/src/tools/clippy/tests/ui/new_without_default.rs b/src/tools/clippy/tests/ui/new_without_default.rs
index 3ac7292c236..12ea729253a 100644
--- a/src/tools/clippy/tests/ui/new_without_default.rs
+++ b/src/tools/clippy/tests/ui/new_without_default.rs
@@ -2,7 +2,8 @@
     dead_code,
     clippy::missing_safety_doc,
     clippy::extra_unused_lifetimes,
-    clippy::extra_unused_type_parameters
+    clippy::extra_unused_type_parameters,
+    clippy::needless_lifetimes
 )]
 #![warn(clippy::new_without_default)]
 
diff --git a/src/tools/clippy/tests/ui/new_without_default.stderr b/src/tools/clippy/tests/ui/new_without_default.stderr
index a30830ae7b2..57bf4bd847c 100644
--- a/src/tools/clippy/tests/ui/new_without_default.stderr
+++ b/src/tools/clippy/tests/ui/new_without_default.stderr
@@ -1,5 +1,5 @@
 error: you should consider adding a `Default` implementation for `Foo`
-  --> tests/ui/new_without_default.rs:12:5
+  --> tests/ui/new_without_default.rs:13:5
    |
 LL | /     pub fn new() -> Foo {
 LL | |
@@ -20,7 +20,7 @@ LL + }
    |
 
 error: you should consider adding a `Default` implementation for `Bar`
-  --> tests/ui/new_without_default.rs:22:5
+  --> tests/ui/new_without_default.rs:23:5
    |
 LL | /     pub fn new() -> Self {
 LL | |
@@ -38,7 +38,7 @@ LL + }
    |
 
 error: you should consider adding a `Default` implementation for `LtKo<'c>`
-  --> tests/ui/new_without_default.rs:87:5
+  --> tests/ui/new_without_default.rs:88:5
    |
 LL | /     pub fn new() -> LtKo<'c> {
 LL | |
@@ -56,7 +56,7 @@ LL + }
    |
 
 error: you should consider adding a `Default` implementation for `Const`
-  --> tests/ui/new_without_default.rs:120:5
+  --> tests/ui/new_without_default.rs:121:5
    |
 LL | /     pub const fn new() -> Const {
 LL | |         Const
@@ -73,7 +73,7 @@ LL + }
    |
 
 error: you should consider adding a `Default` implementation for `NewNotEqualToDerive`
-  --> tests/ui/new_without_default.rs:180:5
+  --> tests/ui/new_without_default.rs:181:5
    |
 LL | /     pub fn new() -> Self {
 LL | |
@@ -91,7 +91,7 @@ LL + }
    |
 
 error: you should consider adding a `Default` implementation for `FooGenerics<T>`
-  --> tests/ui/new_without_default.rs:189:5
+  --> tests/ui/new_without_default.rs:190:5
    |
 LL | /     pub fn new() -> Self {
 LL | |
@@ -109,7 +109,7 @@ LL + }
    |
 
 error: you should consider adding a `Default` implementation for `BarGenerics<T>`
-  --> tests/ui/new_without_default.rs:197:5
+  --> tests/ui/new_without_default.rs:198:5
    |
 LL | /     pub fn new() -> Self {
 LL | |
@@ -127,7 +127,7 @@ LL + }
    |
 
 error: you should consider adding a `Default` implementation for `Foo<T>`
-  --> tests/ui/new_without_default.rs:209:9
+  --> tests/ui/new_without_default.rs:210:9
    |
 LL | /         pub fn new() -> Self {
 LL | |
@@ -147,7 +147,7 @@ LL ~     impl<T> Foo<T> {
    |
 
 error: you should consider adding a `Default` implementation for `MyStruct<K, V>`
-  --> tests/ui/new_without_default.rs:255:5
+  --> tests/ui/new_without_default.rs:256:5
    |
 LL | /     pub fn new() -> Self {
 LL | |         Self { _kv: None }
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed b/src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed
index cc91ba6ec66..a23310c1ad9 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed
+++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed
@@ -115,4 +115,66 @@ fn issue_12625() {
     if a as u64 > b {} //~ ERROR: this boolean expression can be simplified
 }
 
+fn issue_13436() {
+    fn not_zero(x: i32) -> bool {
+        x != 0
+    }
+
+    let opt = Some(500);
+    _ = opt.is_some_and(|x| x < 1000);
+    _ = opt.is_some_and(|x| x <= 1000);
+    _ = opt.is_some_and(|x| x > 1000);
+    _ = opt.is_some_and(|x| x >= 1000);
+    _ = opt.is_some_and(|x| x == 1000);
+    _ = opt.is_some_and(|x| x != 1000);
+    _ = opt.is_some_and(not_zero);
+    _ = opt.is_none_or(|x| x >= 1000); //~ ERROR: this boolean expression can be simplified
+    _ = opt.is_none_or(|x| x > 1000); //~ ERROR: this boolean expression can be simplified
+    _ = opt.is_none_or(|x| x <= 1000); //~ ERROR: this boolean expression can be simplified
+    _ = opt.is_none_or(|x| x < 1000); //~ ERROR: this boolean expression can be simplified
+    _ = opt.is_none_or(|x| x != 1000); //~ ERROR: this boolean expression can be simplified
+    _ = opt.is_none_or(|x| x == 1000); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_some_and(not_zero);
+    _ = opt.is_none_or(|x| x < 1000);
+    _ = opt.is_none_or(|x| x <= 1000);
+    _ = opt.is_none_or(|x| x > 1000);
+    _ = opt.is_none_or(|x| x >= 1000);
+    _ = opt.is_none_or(|x| x == 1000);
+    _ = opt.is_none_or(|x| x != 1000);
+    _ = opt.is_none_or(not_zero);
+    _ = opt.is_some_and(|x| x >= 1000); //~ ERROR: this boolean expression can be simplified
+    _ = opt.is_some_and(|x| x > 1000); //~ ERROR: this boolean expression can be simplified
+    _ = opt.is_some_and(|x| x <= 1000); //~ ERROR: this boolean expression can be simplified
+    _ = opt.is_some_and(|x| x < 1000); //~ ERROR: this boolean expression can be simplified
+    _ = opt.is_some_and(|x| x != 1000); //~ ERROR: this boolean expression can be simplified
+    _ = opt.is_some_and(|x| x == 1000); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_none_or(not_zero);
+
+    let opt = Some(true);
+    _ = opt.is_some_and(|x| x);
+    _ = opt.is_some_and(|x| !x);
+    _ = !opt.is_some_and(|x| x);
+    _ = opt.is_none_or(|x| x); //~ ERROR: this boolean expression can be simplified
+    _ = opt.is_none_or(|x| x);
+    _ = opt.is_none_or(|x| !x);
+    _ = !opt.is_none_or(|x| x);
+    _ = opt.is_some_and(|x| x); //~ ERROR: this boolean expression can be simplified
+
+    let opt: Option<Result<i32, i32>> = Some(Ok(123));
+    _ = opt.is_some_and(|x| x.is_ok());
+    _ = opt.is_some_and(|x| x.is_err());
+    _ = opt.is_none_or(|x| x.is_ok());
+    _ = opt.is_none_or(|x| x.is_err());
+    _ = opt.is_none_or(|x| x.is_err()); //~ ERROR: this boolean expression can be simplified
+    _ = opt.is_none_or(|x| x.is_ok()); //~ ERROR: this boolean expression can be simplified
+    _ = opt.is_some_and(|x| x.is_err()); //~ ERROR: this boolean expression can be simplified
+    _ = opt.is_some_and(|x| x.is_ok()); //~ ERROR: this boolean expression can be simplified
+
+    #[clippy::msrv = "1.81"]
+    fn before_stabilization() {
+        let opt = Some(500);
+        _ = !opt.is_some_and(|x| x < 1000);
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs b/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs
index c812f6f0ca4..6c844373af7 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs
+++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs
@@ -115,4 +115,66 @@ fn issue_12625() {
     if !(a as u64 <= b) {} //~ ERROR: this boolean expression can be simplified
 }
 
+fn issue_13436() {
+    fn not_zero(x: i32) -> bool {
+        x != 0
+    }
+
+    let opt = Some(500);
+    _ = opt.is_some_and(|x| x < 1000);
+    _ = opt.is_some_and(|x| x <= 1000);
+    _ = opt.is_some_and(|x| x > 1000);
+    _ = opt.is_some_and(|x| x >= 1000);
+    _ = opt.is_some_and(|x| x == 1000);
+    _ = opt.is_some_and(|x| x != 1000);
+    _ = opt.is_some_and(not_zero);
+    _ = !opt.is_some_and(|x| x < 1000); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_some_and(|x| x <= 1000); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_some_and(|x| x > 1000); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_some_and(|x| x >= 1000); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_some_and(|x| x == 1000); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_some_and(|x| x != 1000); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_some_and(not_zero);
+    _ = opt.is_none_or(|x| x < 1000);
+    _ = opt.is_none_or(|x| x <= 1000);
+    _ = opt.is_none_or(|x| x > 1000);
+    _ = opt.is_none_or(|x| x >= 1000);
+    _ = opt.is_none_or(|x| x == 1000);
+    _ = opt.is_none_or(|x| x != 1000);
+    _ = opt.is_none_or(not_zero);
+    _ = !opt.is_none_or(|x| x < 1000); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_none_or(|x| x <= 1000); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_none_or(|x| x > 1000); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_none_or(|x| x >= 1000); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_none_or(|x| x == 1000); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_none_or(|x| x != 1000); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_none_or(not_zero);
+
+    let opt = Some(true);
+    _ = opt.is_some_and(|x| x);
+    _ = opt.is_some_and(|x| !x);
+    _ = !opt.is_some_and(|x| x);
+    _ = !opt.is_some_and(|x| !x); //~ ERROR: this boolean expression can be simplified
+    _ = opt.is_none_or(|x| x);
+    _ = opt.is_none_or(|x| !x);
+    _ = !opt.is_none_or(|x| x);
+    _ = !opt.is_none_or(|x| !x); //~ ERROR: this boolean expression can be simplified
+
+    let opt: Option<Result<i32, i32>> = Some(Ok(123));
+    _ = opt.is_some_and(|x| x.is_ok());
+    _ = opt.is_some_and(|x| x.is_err());
+    _ = opt.is_none_or(|x| x.is_ok());
+    _ = opt.is_none_or(|x| x.is_err());
+    _ = !opt.is_some_and(|x| x.is_ok()); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_some_and(|x| x.is_err()); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_none_or(|x| x.is_ok()); //~ ERROR: this boolean expression can be simplified
+    _ = !opt.is_none_or(|x| x.is_err()); //~ ERROR: this boolean expression can be simplified
+
+    #[clippy::msrv = "1.81"]
+    fn before_stabilization() {
+        let opt = Some(500);
+        _ = !opt.is_some_and(|x| x < 1000);
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr b/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr
index d7adc0638b3..52803e828ae 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr
+++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr
@@ -97,5 +97,113 @@ error: this boolean expression can be simplified
 LL |     if !(a as u64 <= b) {}
    |        ^^^^^^^^^^^^^^^^ help: try: `a as u64 > b`
 
-error: aborting due to 16 previous errors
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:131:9
+   |
+LL |     _ = !opt.is_some_and(|x| x < 1000);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x >= 1000)`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:132:9
+   |
+LL |     _ = !opt.is_some_and(|x| x <= 1000);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x > 1000)`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:133:9
+   |
+LL |     _ = !opt.is_some_and(|x| x > 1000);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x <= 1000)`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:134:9
+   |
+LL |     _ = !opt.is_some_and(|x| x >= 1000);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x < 1000)`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:135:9
+   |
+LL |     _ = !opt.is_some_and(|x| x == 1000);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x != 1000)`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:136:9
+   |
+LL |     _ = !opt.is_some_and(|x| x != 1000);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x == 1000)`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:145:9
+   |
+LL |     _ = !opt.is_none_or(|x| x < 1000);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x >= 1000)`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:146:9
+   |
+LL |     _ = !opt.is_none_or(|x| x <= 1000);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x > 1000)`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:147:9
+   |
+LL |     _ = !opt.is_none_or(|x| x > 1000);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x <= 1000)`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:148:9
+   |
+LL |     _ = !opt.is_none_or(|x| x >= 1000);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x < 1000)`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:149:9
+   |
+LL |     _ = !opt.is_none_or(|x| x == 1000);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x != 1000)`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:150:9
+   |
+LL |     _ = !opt.is_none_or(|x| x != 1000);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x == 1000)`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:157:9
+   |
+LL |     _ = !opt.is_some_and(|x| !x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x)`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:161:9
+   |
+LL |     _ = !opt.is_none_or(|x| !x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x)`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:168:9
+   |
+LL |     _ = !opt.is_some_and(|x| x.is_ok());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x.is_err())`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:169:9
+   |
+LL |     _ = !opt.is_some_and(|x| x.is_err());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x.is_ok())`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:170:9
+   |
+LL |     _ = !opt.is_none_or(|x| x.is_ok());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x.is_err())`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods.rs:171:9
+   |
+LL |     _ = !opt.is_none_or(|x| x.is_err());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x.is_ok())`
+
+error: aborting due to 34 previous errors
 
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods_unfixable.rs b/src/tools/clippy/tests/ui/nonminimal_bool_methods_unfixable.rs
new file mode 100644
index 00000000000..60b8da30a2f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods_unfixable.rs
@@ -0,0 +1,9 @@
+#![warn(clippy::nonminimal_bool)]
+//@no-rustfix
+
+fn issue_13436() {
+    let opt_opt = Some(Some(500));
+    _ = !opt_opt.is_some_and(|x| !x.is_some_and(|y| y != 1000)); //~ ERROR: this boolean expression can be simplified
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods_unfixable.stderr b/src/tools/clippy/tests/ui/nonminimal_bool_methods_unfixable.stderr
new file mode 100644
index 00000000000..5a90155844c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods_unfixable.stderr
@@ -0,0 +1,17 @@
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods_unfixable.rs:6:9
+   |
+LL |     _ = !opt_opt.is_some_and(|x| !x.is_some_and(|y| y != 1000));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt_opt.is_none_or(|x| x.is_some_and(|y| y != 1000))`
+   |
+   = note: `-D clippy::nonminimal-bool` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]`
+
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool_methods_unfixable.rs:6:34
+   |
+LL |     _ = !opt_opt.is_some_and(|x| !x.is_some_and(|y| y != 1000));
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_none_or(|y| y == 1000)`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/ref_as_ptr.fixed b/src/tools/clippy/tests/ui/ref_as_ptr.fixed
index 466a628a002..6048267092f 100644
--- a/src/tools/clippy/tests/ui/ref_as_ptr.fixed
+++ b/src/tools/clippy/tests/ui/ref_as_ptr.fixed
@@ -1,5 +1,5 @@
 #![warn(clippy::ref_as_ptr)]
-#![allow(clippy::unnecessary_mut_passed)]
+#![allow(clippy::unnecessary_mut_passed, clippy::needless_lifetimes)]
 
 fn f<T>(_: T) {}
 
diff --git a/src/tools/clippy/tests/ui/ref_as_ptr.rs b/src/tools/clippy/tests/ui/ref_as_ptr.rs
index 0fdc753dc22..7f1d59b856e 100644
--- a/src/tools/clippy/tests/ui/ref_as_ptr.rs
+++ b/src/tools/clippy/tests/ui/ref_as_ptr.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::ref_as_ptr)]
-#![allow(clippy::unnecessary_mut_passed)]
+#![allow(clippy::unnecessary_mut_passed, clippy::needless_lifetimes)]
 
 fn f<T>(_: T) {}
 
diff --git a/src/tools/clippy/tests/ui/ref_option/all/clippy.toml b/src/tools/clippy/tests/ui/ref_option/all/clippy.toml
new file mode 100644
index 00000000000..cda8d17eed4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_option/all/clippy.toml
@@ -0,0 +1 @@
+avoid-breaking-exported-api = false
diff --git a/src/tools/clippy/tests/ui/ref_option/private/clippy.toml b/src/tools/clippy/tests/ui/ref_option/private/clippy.toml
new file mode 100644
index 00000000000..5f304987aa9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_option/private/clippy.toml
@@ -0,0 +1 @@
+avoid-breaking-exported-api = true
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.all.fixed b/src/tools/clippy/tests/ui/ref_option/ref_option.all.fixed
new file mode 100644
index 00000000000..47781a97c98
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_option/ref_option.all.fixed
@@ -0,0 +1,62 @@
+//@revisions: private all
+//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private
+//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all
+
+#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)]
+#![warn(clippy::ref_option)]
+
+fn opt_u8(a: Option<&u8>) {}
+fn opt_gen<T>(a: Option<&T>) {}
+fn opt_string(a: std::option::Option<&String>) {}
+fn ret_string<'a>(p: &'a str) -> Option<&'a u8> {
+    panic!()
+}
+fn ret_string_static() -> Option<&'static u8> {
+    panic!()
+}
+fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
+fn ret_box<'a>() -> Option<&'a Box<u8>> {
+    panic!()
+}
+
+pub fn pub_opt_string(a: Option<&String>) {}
+pub fn pub_mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
+
+pub trait PubTrait {
+    fn pub_trait_opt(&self, a: Option<&Vec<u8>>);
+    fn pub_trait_ret(&self) -> Option<&Vec<u8>>;
+}
+
+trait PrivateTrait {
+    fn trait_opt(&self, a: Option<&String>);
+    fn trait_ret(&self) -> Option<&String>;
+}
+
+pub struct PubStruct;
+
+impl PubStruct {
+    pub fn pub_opt_params(&self, a: Option<&()>) {}
+    pub fn pub_opt_ret(&self) -> Option<&String> {
+        panic!()
+    }
+
+    fn private_opt_params(&self, a: Option<&()>) {}
+    fn private_opt_ret(&self) -> Option<&String> {
+        panic!()
+    }
+}
+
+// valid, don't change
+fn mut_u8(a: &mut Option<u8>) {}
+pub fn pub_mut_u8(a: &mut Option<String>) {}
+
+// might be good to catch in the future
+fn mut_u8_ref(a: &mut &Option<u8>) {}
+pub fn pub_mut_u8_ref(a: &mut &Option<String>) {}
+fn lambdas() {
+    // Not handled for now, not sure if we should
+    let x = |a: &Option<String>| {};
+    let x = |a: &Option<String>| -> &Option<String> { panic!() };
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.all.stderr b/src/tools/clippy/tests/ui/ref_option/ref_option.all.stderr
new file mode 100644
index 00000000000..b4c69ac6296
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_option/ref_option.all.stderr
@@ -0,0 +1,162 @@
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:8:1
+   |
+LL | fn opt_u8(a: &Option<u8>) {}
+   | ^^^^^^^^^^^^^-----------^^^^
+   |              |
+   |              help: change this to: `Option<&u8>`
+   |
+   = note: `-D clippy::ref-option` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:9:1
+   |
+LL | fn opt_gen<T>(a: &Option<T>) {}
+   | ^^^^^^^^^^^^^^^^^----------^^^^
+   |                  |
+   |                  help: change this to: `Option<&T>`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:10:1
+   |
+LL | fn opt_string(a: &std::option::Option<String>) {}
+   | ^^^^^^^^^^^^^^^^^----------------------------^^^^
+   |                  |
+   |                  help: change this to: `std::option::Option<&String>`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:11:1
+   |
+LL |   fn ret_string<'a>(p: &'a str) -> &'a Option<u8> {
+   |   ^                                -------------- help: change this to: `Option<&'a u8>`
+   |  _|
+   | |
+LL | |     panic!()
+LL | | }
+   | |_^
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:14:1
+   |
+LL |   fn ret_string_static() -> &'static Option<u8> {
+   |   ^                         ------------------- help: change this to: `Option<&'static u8>`
+   |  _|
+   | |
+LL | |     panic!()
+LL | | }
+   | |_^
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:17:1
+   |
+LL | fn mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL | fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
+   |                   ~~~~~~~~~~~~~~~     ~~~~~~~~~~~~~~~~
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:18:1
+   |
+LL |   fn ret_box<'a>() -> &'a Option<Box<u8>> {
+   |   ^                   ------------------- help: change this to: `Option<&'a Box<u8>>`
+   |  _|
+   | |
+LL | |     panic!()
+LL | | }
+   | |_^
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:22:1
+   |
+LL | pub fn pub_opt_string(a: &Option<String>) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^
+   |                          |
+   |                          help: change this to: `Option<&String>`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:23:1
+   |
+LL | pub fn pub_mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL | pub fn pub_mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
+   |                           ~~~~~~~~~~~~~~~     ~~~~~~~~~~~~~~~~
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:26:5
+   |
+LL |     fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^^
+   |                                |
+   |                                help: change this to: `Option<&Vec<u8>>`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:27:5
+   |
+LL |     fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^
+   |                                |
+   |                                help: change this to: `Option<&Vec<u8>>`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:31:5
+   |
+LL |     fn trait_opt(&self, a: &Option<String>);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^^
+   |                            |
+   |                            help: change this to: `Option<&String>`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:32:5
+   |
+LL |     fn trait_ret(&self) -> &Option<String>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^
+   |                            |
+   |                            help: change this to: `Option<&String>`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:38:5
+   |
+LL |     pub fn pub_opt_params(&self, a: &Option<()>) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^
+   |                                     |
+   |                                     help: change this to: `Option<&()>`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:39:5
+   |
+LL |       pub fn pub_opt_ret(&self) -> &Option<String> {
+   |       ^                            --------------- help: change this to: `Option<&String>`
+   |  _____|
+   | |
+LL | |         panic!()
+LL | |     }
+   | |_____^
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:43:5
+   |
+LL |     fn private_opt_params(&self, a: &Option<()>) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^
+   |                                     |
+   |                                     help: change this to: `Option<&()>`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:44:5
+   |
+LL |       fn private_opt_ret(&self) -> &Option<String> {
+   |       ^                            --------------- help: change this to: `Option<&String>`
+   |  _____|
+   | |
+LL | |         panic!()
+LL | |     }
+   | |_____^
+
+error: aborting due to 17 previous errors
+
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.private.fixed b/src/tools/clippy/tests/ui/ref_option/ref_option.private.fixed
new file mode 100644
index 00000000000..8c42556e9b0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_option/ref_option.private.fixed
@@ -0,0 +1,62 @@
+//@revisions: private all
+//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private
+//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all
+
+#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)]
+#![warn(clippy::ref_option)]
+
+fn opt_u8(a: Option<&u8>) {}
+fn opt_gen<T>(a: Option<&T>) {}
+fn opt_string(a: std::option::Option<&String>) {}
+fn ret_string<'a>(p: &'a str) -> Option<&'a u8> {
+    panic!()
+}
+fn ret_string_static() -> Option<&'static u8> {
+    panic!()
+}
+fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
+fn ret_box<'a>() -> Option<&'a Box<u8>> {
+    panic!()
+}
+
+pub fn pub_opt_string(a: &Option<String>) {}
+pub fn pub_mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
+
+pub trait PubTrait {
+    fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
+    fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
+}
+
+trait PrivateTrait {
+    fn trait_opt(&self, a: Option<&String>);
+    fn trait_ret(&self) -> Option<&String>;
+}
+
+pub struct PubStruct;
+
+impl PubStruct {
+    pub fn pub_opt_params(&self, a: &Option<()>) {}
+    pub fn pub_opt_ret(&self) -> &Option<String> {
+        panic!()
+    }
+
+    fn private_opt_params(&self, a: Option<&()>) {}
+    fn private_opt_ret(&self) -> Option<&String> {
+        panic!()
+    }
+}
+
+// valid, don't change
+fn mut_u8(a: &mut Option<u8>) {}
+pub fn pub_mut_u8(a: &mut Option<String>) {}
+
+// might be good to catch in the future
+fn mut_u8_ref(a: &mut &Option<u8>) {}
+pub fn pub_mut_u8_ref(a: &mut &Option<String>) {}
+fn lambdas() {
+    // Not handled for now, not sure if we should
+    let x = |a: &Option<String>| {};
+    let x = |a: &Option<String>| -> &Option<String> { panic!() };
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.private.stderr b/src/tools/clippy/tests/ui/ref_option/ref_option.private.stderr
new file mode 100644
index 00000000000..17c90536da3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_option/ref_option.private.stderr
@@ -0,0 +1,108 @@
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:8:1
+   |
+LL | fn opt_u8(a: &Option<u8>) {}
+   | ^^^^^^^^^^^^^-----------^^^^
+   |              |
+   |              help: change this to: `Option<&u8>`
+   |
+   = note: `-D clippy::ref-option` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:9:1
+   |
+LL | fn opt_gen<T>(a: &Option<T>) {}
+   | ^^^^^^^^^^^^^^^^^----------^^^^
+   |                  |
+   |                  help: change this to: `Option<&T>`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:10:1
+   |
+LL | fn opt_string(a: &std::option::Option<String>) {}
+   | ^^^^^^^^^^^^^^^^^----------------------------^^^^
+   |                  |
+   |                  help: change this to: `std::option::Option<&String>`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:11:1
+   |
+LL |   fn ret_string<'a>(p: &'a str) -> &'a Option<u8> {
+   |   ^                                -------------- help: change this to: `Option<&'a u8>`
+   |  _|
+   | |
+LL | |     panic!()
+LL | | }
+   | |_^
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:14:1
+   |
+LL |   fn ret_string_static() -> &'static Option<u8> {
+   |   ^                         ------------------- help: change this to: `Option<&'static u8>`
+   |  _|
+   | |
+LL | |     panic!()
+LL | | }
+   | |_^
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:17:1
+   |
+LL | fn mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL | fn mult_string(a: Option<&String>, b: Option<&Vec<u8>>) {}
+   |                   ~~~~~~~~~~~~~~~     ~~~~~~~~~~~~~~~~
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:18:1
+   |
+LL |   fn ret_box<'a>() -> &'a Option<Box<u8>> {
+   |   ^                   ------------------- help: change this to: `Option<&'a Box<u8>>`
+   |  _|
+   | |
+LL | |     panic!()
+LL | | }
+   | |_^
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:31:5
+   |
+LL |     fn trait_opt(&self, a: &Option<String>);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^^
+   |                            |
+   |                            help: change this to: `Option<&String>`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:32:5
+   |
+LL |     fn trait_ret(&self) -> &Option<String>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^
+   |                            |
+   |                            help: change this to: `Option<&String>`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:43:5
+   |
+LL |     fn private_opt_params(&self, a: &Option<()>) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^
+   |                                     |
+   |                                     help: change this to: `Option<&()>`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option.rs:44:5
+   |
+LL |       fn private_opt_ret(&self) -> &Option<String> {
+   |       ^                            --------------- help: change this to: `Option<&String>`
+   |  _____|
+   | |
+LL | |         panic!()
+LL | |     }
+   | |_____^
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.rs b/src/tools/clippy/tests/ui/ref_option/ref_option.rs
new file mode 100644
index 00000000000..05251bcf12c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_option/ref_option.rs
@@ -0,0 +1,62 @@
+//@revisions: private all
+//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private
+//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all
+
+#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)]
+#![warn(clippy::ref_option)]
+
+fn opt_u8(a: &Option<u8>) {}
+fn opt_gen<T>(a: &Option<T>) {}
+fn opt_string(a: &std::option::Option<String>) {}
+fn ret_string<'a>(p: &'a str) -> &'a Option<u8> {
+    panic!()
+}
+fn ret_string_static() -> &'static Option<u8> {
+    panic!()
+}
+fn mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
+fn ret_box<'a>() -> &'a Option<Box<u8>> {
+    panic!()
+}
+
+pub fn pub_opt_string(a: &Option<String>) {}
+pub fn pub_mult_string(a: &Option<String>, b: &Option<Vec<u8>>) {}
+
+pub trait PubTrait {
+    fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
+    fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
+}
+
+trait PrivateTrait {
+    fn trait_opt(&self, a: &Option<String>);
+    fn trait_ret(&self) -> &Option<String>;
+}
+
+pub struct PubStruct;
+
+impl PubStruct {
+    pub fn pub_opt_params(&self, a: &Option<()>) {}
+    pub fn pub_opt_ret(&self) -> &Option<String> {
+        panic!()
+    }
+
+    fn private_opt_params(&self, a: &Option<()>) {}
+    fn private_opt_ret(&self) -> &Option<String> {
+        panic!()
+    }
+}
+
+// valid, don't change
+fn mut_u8(a: &mut Option<u8>) {}
+pub fn pub_mut_u8(a: &mut Option<String>) {}
+
+// might be good to catch in the future
+fn mut_u8_ref(a: &mut &Option<u8>) {}
+pub fn pub_mut_u8_ref(a: &mut &Option<String>) {}
+fn lambdas() {
+    // Not handled for now, not sure if we should
+    let x = |a: &Option<String>| {};
+    let x = |a: &Option<String>| -> &Option<String> { panic!() };
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr
new file mode 100644
index 00000000000..a9967168c12
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr
@@ -0,0 +1,37 @@
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option_traits.rs:10:5
+   |
+LL |     fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^^
+   |                                |
+   |                                help: change this to: `Option<&Vec<u8>>`
+   |
+   = note: `-D clippy::ref-option` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option_traits.rs:11:5
+   |
+LL |     fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^
+   |                                |
+   |                                help: change this to: `Option<&Vec<u8>>`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option_traits.rs:15:5
+   |
+LL |     fn trait_opt(&self, a: &Option<String>);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^^
+   |                            |
+   |                            help: change this to: `Option<&String>`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option_traits.rs:16:5
+   |
+LL |     fn trait_ret(&self) -> &Option<String>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^
+   |                            |
+   |                            help: change this to: `Option<&String>`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr
new file mode 100644
index 00000000000..36d0833af8a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr
@@ -0,0 +1,21 @@
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option_traits.rs:15:5
+   |
+LL |     fn trait_opt(&self, a: &Option<String>);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^^
+   |                            |
+   |                            help: change this to: `Option<&String>`
+   |
+   = note: `-D clippy::ref-option` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
+
+error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
+  --> tests/ui/ref_option/ref_option_traits.rs:16:5
+   |
+LL |     fn trait_ret(&self) -> &Option<String>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^---------------^
+   |                            |
+   |                            help: change this to: `Option<&String>`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs
new file mode 100644
index 00000000000..5d5f113c83d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs
@@ -0,0 +1,37 @@
+//@no-rustfix: fixes are only done to traits, not the impls
+//@revisions: private all
+//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private
+//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all
+
+#![allow(unused, clippy::all)]
+#![warn(clippy::ref_option)]
+
+pub trait PubTrait {
+    fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
+    fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
+}
+
+trait PrivateTrait {
+    fn trait_opt(&self, a: &Option<String>);
+    fn trait_ret(&self) -> &Option<String>;
+}
+
+pub struct PubStruct;
+
+impl PubTrait for PubStruct {
+    fn pub_trait_opt(&self, a: &Option<Vec<u8>>) {}
+    fn pub_trait_ret(&self) -> &Option<Vec<u8>> {
+        panic!()
+    }
+}
+
+struct PrivateStruct;
+
+impl PrivateTrait for PrivateStruct {
+    fn trait_opt(&self, a: &Option<String>) {}
+    fn trait_ret(&self) -> &Option<String> {
+        panic!()
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/serde.rs b/src/tools/clippy/tests/ui/serde.rs
index 610a50020ec..af8b10f3e6a 100644
--- a/src/tools/clippy/tests/ui/serde.rs
+++ b/src/tools/clippy/tests/ui/serde.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::serde_api_misuse)]
-#![allow(dead_code)]
+#![allow(dead_code, clippy::needless_lifetimes)]
 
 extern crate serde;
 
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
index 0db6fbfb7be..8468d1d7c7d 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
@@ -2,7 +2,12 @@
 //@no-rustfix
 #![warn(clippy::significant_drop_in_scrutinee)]
 #![allow(dead_code, unused_assignments)]
-#![allow(clippy::match_single_binding, clippy::single_match, clippy::uninlined_format_args)]
+#![allow(
+    clippy::match_single_binding,
+    clippy::single_match,
+    clippy::uninlined_format_args,
+    clippy::needless_lifetimes
+)]
 
 use std::num::ParseIntError;
 use std::ops::Deref;
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
index c0c93cd10c0..62030cbe70e 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
@@ -1,5 +1,5 @@
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:55:11
+  --> tests/ui/significant_drop_in_scrutinee.rs:60:11
    |
 LL |     match mutex.lock().unwrap().foo() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL ~     match value {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:143:11
+  --> tests/ui/significant_drop_in_scrutinee.rs:148:11
    |
 LL |     match s.lock_m().get_the_value() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -42,7 +42,7 @@ LL ~     match value {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:166:11
+  --> tests/ui/significant_drop_in_scrutinee.rs:171:11
    |
 LL |     match s.lock_m_m().get_the_value() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL ~     match value {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:216:11
+  --> tests/ui/significant_drop_in_scrutinee.rs:221:11
    |
 LL |     match counter.temp_increment().len() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -80,7 +80,7 @@ LL ~     match value {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:241:16
+  --> tests/ui/significant_drop_in_scrutinee.rs:246:16
    |
 LL |         match (mutex1.lock().unwrap().s.len(), true) {
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -99,7 +99,7 @@ LL ~         match (value, true) {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:252:22
+  --> tests/ui/significant_drop_in_scrutinee.rs:257:22
    |
 LL |         match (true, mutex1.lock().unwrap().s.len(), true) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -118,7 +118,7 @@ LL ~         match (true, value, true) {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:264:16
+  --> tests/ui/significant_drop_in_scrutinee.rs:269:16
    |
 LL |         match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) {
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -139,7 +139,7 @@ LL ~         match (value, true, mutex2.lock().unwrap().s.len()) {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:264:54
+  --> tests/ui/significant_drop_in_scrutinee.rs:269:54
    |
 LL |         match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) {
    |                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -160,7 +160,7 @@ LL ~         match (mutex1.lock().unwrap().s.len(), true, value) {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:319:11
+  --> tests/ui/significant_drop_in_scrutinee.rs:324:11
    |
 LL |     match mutex.lock().unwrap().s.len() > 1 {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -179,7 +179,7 @@ LL ~     match value > 1 {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:328:15
+  --> tests/ui/significant_drop_in_scrutinee.rs:333:15
    |
 LL |     match 1 < mutex.lock().unwrap().s.len() {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -198,7 +198,7 @@ LL ~     match 1 < value {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:348:11
+  --> tests/ui/significant_drop_in_scrutinee.rs:353:11
    |
 LL |     match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -219,7 +219,7 @@ LL ~     match value < mutex2.lock().unwrap().s.len() {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:348:44
+  --> tests/ui/significant_drop_in_scrutinee.rs:353:44
    |
 LL |     match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() {
    |                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -240,7 +240,7 @@ LL ~     match mutex1.lock().unwrap().s.len() < value {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:361:11
+  --> tests/ui/significant_drop_in_scrutinee.rs:366:11
    |
 LL |     match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -261,7 +261,7 @@ LL ~     match value >= mutex2.lock().unwrap().s.len() {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:361:45
+  --> tests/ui/significant_drop_in_scrutinee.rs:366:45
    |
 LL |     match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() {
    |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -282,7 +282,7 @@ LL ~     match mutex1.lock().unwrap().s.len() >= value {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:398:11
+  --> tests/ui/significant_drop_in_scrutinee.rs:403:11
    |
 LL |     match get_mutex_guard().s.len() > 1 {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -301,7 +301,7 @@ LL ~     match value > 1 {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:417:11
+  --> tests/ui/significant_drop_in_scrutinee.rs:422:11
    |
 LL |       match match i {
    |  ___________^
@@ -334,7 +334,7 @@ LL ~     match value
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:445:11
+  --> tests/ui/significant_drop_in_scrutinee.rs:450:11
    |
 LL |       match if i > 1 {
    |  ___________^
@@ -368,7 +368,7 @@ LL ~     match value
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:501:11
+  --> tests/ui/significant_drop_in_scrutinee.rs:506:11
    |
 LL |     match s.lock().deref().deref() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -386,7 +386,7 @@ LL ~     match (&value) {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:551:11
+  --> tests/ui/significant_drop_in_scrutinee.rs:556:11
    |
 LL |     match mutex.lock().unwrap().i = i {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -405,7 +405,7 @@ LL ~     match () {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:559:15
+  --> tests/ui/significant_drop_in_scrutinee.rs:564:15
    |
 LL |     match i = mutex.lock().unwrap().i {
    |               ^^^^^^^^^^^^^^^^^^^^^^^
@@ -424,7 +424,7 @@ LL ~     match i = value {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:567:11
+  --> tests/ui/significant_drop_in_scrutinee.rs:572:11
    |
 LL |     match mutex.lock().unwrap().i += 1 {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -443,7 +443,7 @@ LL ~     match () {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:575:16
+  --> tests/ui/significant_drop_in_scrutinee.rs:580:16
    |
 LL |     match i += mutex.lock().unwrap().i {
    |                ^^^^^^^^^^^^^^^^^^^^^^^
@@ -462,7 +462,7 @@ LL ~     match i += value {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:640:11
+  --> tests/ui/significant_drop_in_scrutinee.rs:645:11
    |
 LL |     match rwlock.read().unwrap().to_number() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -478,7 +478,7 @@ LL ~     match value {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:668:11
+  --> tests/ui/significant_drop_in_scrutinee.rs:673:11
    |
 LL |     match mutex.lock().unwrap().foo() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -494,7 +494,7 @@ LL ~     match value {
    |
 
 error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:731:11
+  --> tests/ui/significant_drop_in_scrutinee.rs:736:11
    |
 LL |     match guard.take().len() {
    |           ^^^^^^^^^^^^^^^^^^
@@ -510,7 +510,7 @@ LL ~     match value {
    |
 
 error: temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:757:16
+  --> tests/ui/significant_drop_in_scrutinee.rs:762:16
    |
 LL |     for val in mutex.lock().unwrap().copy_old_lifetime() {
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -526,7 +526,7 @@ LL ~     for val in value {
    |
 
 error: temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:797:17
+  --> tests/ui/significant_drop_in_scrutinee.rs:802:17
    |
 LL |     for val in [mutex.lock().unwrap()[0], 2] {
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -542,7 +542,7 @@ LL ~     for val in [value, 2] {
    |
 
 error: temporary with significant `Drop` in `if let` scrutinee will live until the end of the `if let` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:807:24
+  --> tests/ui/significant_drop_in_scrutinee.rs:812:24
    |
 LL |     if let Some(val) = mutex.lock().unwrap().first().copied() {
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -558,7 +558,7 @@ LL ~     if let Some(val) = value {
    |
 
 error: temporary with significant `Drop` in `while let` scrutinee will live until the end of the `while let` expression
-  --> tests/ui/significant_drop_in_scrutinee.rs:823:27
+  --> tests/ui/significant_drop_in_scrutinee.rs:828:27
    |
 LL |     while let Some(val) = mutex.lock().unwrap().pop() {
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/str_split.fixed b/src/tools/clippy/tests/ui/str_split.fixed
index 4f33241da7a..57a3c315a87 100644
--- a/src/tools/clippy/tests/ui/str_split.fixed
+++ b/src/tools/clippy/tests/ui/str_split.fixed
@@ -1,4 +1,5 @@
 #![warn(clippy::str_split_at_newline)]
+#![allow(clippy::needless_lifetimes)]
 
 use core::str::Split;
 use std::ops::Deref;
diff --git a/src/tools/clippy/tests/ui/str_split.rs b/src/tools/clippy/tests/ui/str_split.rs
index f24caa61c30..fcff036f264 100644
--- a/src/tools/clippy/tests/ui/str_split.rs
+++ b/src/tools/clippy/tests/ui/str_split.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::str_split_at_newline)]
+#![allow(clippy::needless_lifetimes)]
 
 use core::str::Split;
 use std::ops::Deref;
diff --git a/src/tools/clippy/tests/ui/str_split.stderr b/src/tools/clippy/tests/ui/str_split.stderr
index ebe0d4ef4d3..7b560468f12 100644
--- a/src/tools/clippy/tests/ui/str_split.stderr
+++ b/src/tools/clippy/tests/ui/str_split.stderr
@@ -1,5 +1,5 @@
 error: using `str.trim().split()` with hard-coded newlines
-  --> tests/ui/str_split.rs:59:13
+  --> tests/ui/str_split.rs:60:13
    |
 LL |     let _ = s1.trim().split('\n');
    |             ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()`
@@ -8,55 +8,55 @@ LL |     let _ = s1.trim().split('\n');
    = help: to override `-D warnings` add `#[allow(clippy::str_split_at_newline)]`
 
 error: using `str.trim().split()` with hard-coded newlines
-  --> tests/ui/str_split.rs:61:13
+  --> tests/ui/str_split.rs:62:13
    |
 LL |     let _ = s1.trim().split("\n");
    |             ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()`
 
 error: using `str.trim().split()` with hard-coded newlines
-  --> tests/ui/str_split.rs:62:13
+  --> tests/ui/str_split.rs:63:13
    |
 LL |     let _ = s1.trim().split("\r\n");
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()`
 
 error: using `str.trim().split()` with hard-coded newlines
-  --> tests/ui/str_split.rs:65:13
+  --> tests/ui/str_split.rs:66:13
    |
 LL |     let _ = s2.trim().split('\n');
    |             ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()`
 
 error: using `str.trim().split()` with hard-coded newlines
-  --> tests/ui/str_split.rs:67:13
+  --> tests/ui/str_split.rs:68:13
    |
 LL |     let _ = s2.trim().split("\n");
    |             ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()`
 
 error: using `str.trim().split()` with hard-coded newlines
-  --> tests/ui/str_split.rs:68:13
+  --> tests/ui/str_split.rs:69:13
    |
 LL |     let _ = s2.trim().split("\r\n");
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()`
 
 error: using `str.trim().split()` with hard-coded newlines
-  --> tests/ui/str_split.rs:72:13
+  --> tests/ui/str_split.rs:73:13
    |
 LL |     let _ = s3.trim().split('\n');
    |             ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()`
 
 error: using `str.trim().split()` with hard-coded newlines
-  --> tests/ui/str_split.rs:74:13
+  --> tests/ui/str_split.rs:75:13
    |
 LL |     let _ = s3.trim().split("\n");
    |             ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()`
 
 error: using `str.trim().split()` with hard-coded newlines
-  --> tests/ui/str_split.rs:75:13
+  --> tests/ui/str_split.rs:76:13
    |
 LL |     let _ = s3.trim().split("\r\n");
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()`
 
 error: using `str.trim().split()` with hard-coded newlines
-  --> tests/ui/str_split.rs:78:13
+  --> tests/ui/str_split.rs:79:13
    |
 LL |     let _ = make_str!(s1).trim().split('\n');
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `make_str!(s1).lines()`
diff --git a/src/tools/clippy/tests/ui/temporary_assignment.rs b/src/tools/clippy/tests/ui/temporary_assignment.rs
index 383e70be925..d269f91b9fa 100644
--- a/src/tools/clippy/tests/ui/temporary_assignment.rs
+++ b/src/tools/clippy/tests/ui/temporary_assignment.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::temporary_assignment)]
-#![allow(const_item_mutation)]
+#![allow(clippy::needless_lifetimes)]
 
 use std::ops::{Deref, DerefMut};
 
diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed
index 83814ca43b9..075a198918a 100644
--- a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed
+++ b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed
@@ -1,7 +1,7 @@
 #![warn(clippy::transmute_float_to_int)]
 #![allow(clippy::missing_transmute_annotations)]
-#![feature(f128, f128_const)]
-#![feature(f16, f16_const)]
+#![feature(f128)]
+#![feature(f16)]
 
 fn float_to_int() {
     let _: u32 = unsafe { 1f32.to_bits() };
diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.rs b/src/tools/clippy/tests/ui/transmute_float_to_int.rs
index 64d6e917203..12541b2f7cf 100644
--- a/src/tools/clippy/tests/ui/transmute_float_to_int.rs
+++ b/src/tools/clippy/tests/ui/transmute_float_to_int.rs
@@ -1,7 +1,7 @@
 #![warn(clippy::transmute_float_to_int)]
 #![allow(clippy::missing_transmute_annotations)]
-#![feature(f128, f128_const)]
-#![feature(f16, f16_const)]
+#![feature(f128)]
+#![feature(f16)]
 
 fn float_to_int() {
     let _: u32 = unsafe { std::mem::transmute(1f32) };
diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
index e95054a7ccb..617d32d1fa7 100644
--- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
+++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
@@ -84,8 +84,11 @@ fn issue_10449() {
 }
 
 // Pointers cannot be cast to integers in const contexts
+#[allow(ptr_to_integer_transmute_in_consts, reason = "This is tested in the compiler test suite")]
 const fn issue_12402<P>(ptr: *const P) {
-    unsafe { transmute::<*const i32, usize>(&42i32) };
-    unsafe { transmute::<fn(*const P), usize>(issue_12402) };
-    let _ = unsafe { transmute::<_, usize>(ptr) };
+    // This test exists even though the compiler lints against it
+    // to test that clippy's transmute lints do not trigger on this.
+    unsafe { std::mem::transmute::<*const i32, usize>(&42i32) };
+    unsafe { std::mem::transmute::<fn(*const P), usize>(issue_12402) };
+    let _ = unsafe { std::mem::transmute::<_, usize>(ptr) };
 }
diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
index e5fcdef7a1c..d68db3c2deb 100644
--- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
+++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
@@ -84,8 +84,11 @@ fn issue_10449() {
 }
 
 // Pointers cannot be cast to integers in const contexts
+#[allow(ptr_to_integer_transmute_in_consts, reason = "This is tested in the compiler test suite")]
 const fn issue_12402<P>(ptr: *const P) {
-    unsafe { transmute::<*const i32, usize>(&42i32) };
-    unsafe { transmute::<fn(*const P), usize>(issue_12402) };
-    let _ = unsafe { transmute::<_, usize>(ptr) };
+    // This test exists even though the compiler lints against it
+    // to test that clippy's transmute lints do not trigger on this.
+    unsafe { std::mem::transmute::<*const i32, usize>(&42i32) };
+    unsafe { std::mem::transmute::<fn(*const P), usize>(issue_12402) };
+    let _ = unsafe { std::mem::transmute::<_, usize>(ptr) };
 }
diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.rs b/src/tools/clippy/tests/ui/unconditional_recursion.rs
index a51fc567f50..b8476a7088a 100644
--- a/src/tools/clippy/tests/ui/unconditional_recursion.rs
+++ b/src/tools/clippy/tests/ui/unconditional_recursion.rs
@@ -4,7 +4,8 @@
 #![allow(
     clippy::partialeq_ne_impl,
     clippy::default_constructed_unit_structs,
-    clippy::only_used_in_recursion
+    clippy::only_used_in_recursion,
+    clippy::needless_lifetimes
 )]
 
 enum Foo {
diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.stderr b/src/tools/clippy/tests/ui/unconditional_recursion.stderr
index 03c27bd8ed8..6a0078ee090 100644
--- a/src/tools/clippy/tests/ui/unconditional_recursion.stderr
+++ b/src/tools/clippy/tests/ui/unconditional_recursion.stderr
@@ -1,5 +1,5 @@
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:46:5
+  --> tests/ui/unconditional_recursion.rs:47:5
    |
 LL |     fn ne(&self, other: &Self) -> bool {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -12,7 +12,7 @@ LL |         self.ne(other)
    = help: to override `-D warnings` add `#[allow(unconditional_recursion)]`
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:50:5
+  --> tests/ui/unconditional_recursion.rs:51:5
    |
 LL |     fn eq(&self, other: &Self) -> bool {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -23,7 +23,7 @@ LL |         self.eq(other)
    = help: a `loop` may express intention better if this is on purpose
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:215:5
+  --> tests/ui/unconditional_recursion.rs:216:5
    |
 LL |     fn to_string(&self) -> String {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -34,7 +34,7 @@ LL |         self.to_string()
    = help: a `loop` may express intention better if this is on purpose
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:225:5
+  --> tests/ui/unconditional_recursion.rs:226:5
    |
 LL |     fn to_string(&self) -> String {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -45,7 +45,7 @@ LL |         x.to_string()
    = help: a `loop` may express intention better if this is on purpose
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:236:5
+  --> tests/ui/unconditional_recursion.rs:237:5
    |
 LL |     fn to_string(&self) -> String {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -56,7 +56,7 @@ LL |         (self as &Self).to_string()
    = help: a `loop` may express intention better if this is on purpose
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:16:5
+  --> tests/ui/unconditional_recursion.rs:17:5
    |
 LL | /     fn ne(&self, other: &Self) -> bool {
 LL | |
@@ -65,7 +65,7 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:18:9
+  --> tests/ui/unconditional_recursion.rs:19:9
    |
 LL |         self != other
    |         ^^^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL |         self != other
    = help: to override `-D warnings` add `#[allow(clippy::unconditional_recursion)]`
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:20:5
+  --> tests/ui/unconditional_recursion.rs:21:5
    |
 LL | /     fn eq(&self, other: &Self) -> bool {
 LL | |
@@ -82,13 +82,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:22:9
+  --> tests/ui/unconditional_recursion.rs:23:9
    |
 LL |         self == other
    |         ^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:32:5
+  --> tests/ui/unconditional_recursion.rs:33:5
    |
 LL | /     fn ne(&self, other: &Self) -> bool {
 LL | |         self != &Foo2::B // no error here
@@ -96,13 +96,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:33:9
+  --> tests/ui/unconditional_recursion.rs:34:9
    |
 LL |         self != &Foo2::B // no error here
    |         ^^^^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:35:5
+  --> tests/ui/unconditional_recursion.rs:36:5
    |
 LL | /     fn eq(&self, other: &Self) -> bool {
 LL | |         self == &Foo2::B // no error here
@@ -110,13 +110,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:36:9
+  --> tests/ui/unconditional_recursion.rs:37:9
    |
 LL |         self == &Foo2::B // no error here
    |         ^^^^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:46:5
+  --> tests/ui/unconditional_recursion.rs:47:5
    |
 LL | /     fn ne(&self, other: &Self) -> bool {
 LL | |
@@ -125,13 +125,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:48:9
+  --> tests/ui/unconditional_recursion.rs:49:9
    |
 LL |         self.ne(other)
    |         ^^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:50:5
+  --> tests/ui/unconditional_recursion.rs:51:5
    |
 LL | /     fn eq(&self, other: &Self) -> bool {
 LL | |
@@ -140,13 +140,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:52:9
+  --> tests/ui/unconditional_recursion.rs:53:9
    |
 LL |         self.eq(other)
    |         ^^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:94:5
+  --> tests/ui/unconditional_recursion.rs:95:5
    |
 LL | /     fn ne(&self, other: &Self) -> bool {
 LL | |
@@ -155,13 +155,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:96:9
+  --> tests/ui/unconditional_recursion.rs:97:9
    |
 LL |         other != self
    |         ^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:98:5
+  --> tests/ui/unconditional_recursion.rs:99:5
    |
 LL | /     fn eq(&self, other: &Self) -> bool {
 LL | |
@@ -170,13 +170,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:100:9
+  --> tests/ui/unconditional_recursion.rs:101:9
    |
 LL |         other == self
    |         ^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:108:5
+  --> tests/ui/unconditional_recursion.rs:109:5
    |
 LL | /     fn ne(&self, other: &Self) -> bool {
 LL | |
@@ -185,13 +185,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:110:9
+  --> tests/ui/unconditional_recursion.rs:111:9
    |
 LL |         other != other
    |         ^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `!=`
-  --> tests/ui/unconditional_recursion.rs:110:9
+  --> tests/ui/unconditional_recursion.rs:111:9
    |
 LL |         other != other
    |         ^^^^^^^^^^^^^^
@@ -199,7 +199,7 @@ LL |         other != other
    = note: `#[deny(clippy::eq_op)]` on by default
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:112:5
+  --> tests/ui/unconditional_recursion.rs:113:5
    |
 LL | /     fn eq(&self, other: &Self) -> bool {
 LL | |
@@ -208,19 +208,19 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:114:9
+  --> tests/ui/unconditional_recursion.rs:115:9
    |
 LL |         other == other
    |         ^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `==`
-  --> tests/ui/unconditional_recursion.rs:114:9
+  --> tests/ui/unconditional_recursion.rs:115:9
    |
 LL |         other == other
    |         ^^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:121:5
+  --> tests/ui/unconditional_recursion.rs:122:5
    |
 LL | /     fn ne(&self, _other: &Self) -> bool {
 LL | |
@@ -229,19 +229,19 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:123:9
+  --> tests/ui/unconditional_recursion.rs:124:9
    |
 LL |         self != self
    |         ^^^^^^^^^^^^
 
 error: equal expressions as operands to `!=`
-  --> tests/ui/unconditional_recursion.rs:123:9
+  --> tests/ui/unconditional_recursion.rs:124:9
    |
 LL |         self != self
    |         ^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:125:5
+  --> tests/ui/unconditional_recursion.rs:126:5
    |
 LL | /     fn eq(&self, _other: &Self) -> bool {
 LL | |
@@ -250,19 +250,19 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:127:9
+  --> tests/ui/unconditional_recursion.rs:128:9
    |
 LL |         self == self
    |         ^^^^^^^^^^^^
 
 error: equal expressions as operands to `==`
-  --> tests/ui/unconditional_recursion.rs:127:9
+  --> tests/ui/unconditional_recursion.rs:128:9
    |
 LL |         self == self
    |         ^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:153:13
+  --> tests/ui/unconditional_recursion.rs:154:13
    |
 LL | /             fn eq(&self, other: &Self) -> bool {
 LL | |
@@ -274,7 +274,7 @@ LL |   impl_partial_eq!(S5);
    |   -------------------- in this macro invocation
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:155:17
+  --> tests/ui/unconditional_recursion.rs:156:17
    |
 LL |                 self == other
    |                 ^^^^^^^^^^^^^
@@ -284,7 +284,7 @@ LL | impl_partial_eq!(S5);
    = note: this error originates in the macro `impl_partial_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:182:5
+  --> tests/ui/unconditional_recursion.rs:183:5
    |
 LL | /     fn eq(&self, other: &Self) -> bool {
 LL | |
@@ -295,13 +295,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:186:9
+  --> tests/ui/unconditional_recursion.rs:187:9
    |
 LL |         mine == theirs
    |         ^^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:251:5
+  --> tests/ui/unconditional_recursion.rs:252:5
    |
 LL | /     fn new() -> Self {
 LL | |
@@ -310,13 +310,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:253:9
+  --> tests/ui/unconditional_recursion.rs:254:9
    |
 LL |         Self::default()
    |         ^^^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:290:5
+  --> tests/ui/unconditional_recursion.rs:291:5
    |
 LL | /     fn eq(&self, other: &Self) -> bool {
 LL | |
@@ -327,13 +327,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:294:9
+  --> tests/ui/unconditional_recursion.rs:295:9
    |
 LL |         mine.eq(theirs)
    |         ^^^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:361:5
+  --> tests/ui/unconditional_recursion.rs:362:5
    |
 LL | /     fn from(f: BadFromTy1<'a>) -> Self {
 LL | |         f.into()
@@ -341,13 +341,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:362:9
+  --> tests/ui/unconditional_recursion.rs:363:9
    |
 LL |         f.into()
    |         ^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:370:5
+  --> tests/ui/unconditional_recursion.rs:371:5
    |
 LL | /     fn from(f: BadFromTy2<'a>) -> Self {
 LL | |         Into::into(f)
@@ -355,7 +355,7 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:371:9
+  --> tests/ui/unconditional_recursion.rs:372:9
    |
 LL |         Into::into(f)
    |         ^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs
index 7ec8a3adb4c..838d6f0aa97 100644
--- a/src/tools/clippy/tests/ui/unused_async.rs
+++ b/src/tools/clippy/tests/ui/unused_async.rs
@@ -55,6 +55,22 @@ mod issue9695 {
     }
 }
 
+mod issue13466 {
+    use std::future::Future;
+
+    struct Wrap<F>(F);
+    impl<F> From<F> for Wrap<F> {
+        fn from(f: F) -> Self {
+            Self(f)
+        }
+    }
+    fn takes_fut<F: Fn() -> Fut, Fut: Future>(_: Wrap<F>) {}
+    async fn unused_async() {}
+    fn fp() {
+        takes_fut(unused_async.into());
+    }
+}
+
 async fn foo() -> i32 {
     //~^ ERROR: unused `async` for function with no await statements
     4
diff --git a/src/tools/clippy/tests/ui/unused_async.stderr b/src/tools/clippy/tests/ui/unused_async.stderr
index 337c650e029..4811df63658 100644
--- a/src/tools/clippy/tests/ui/unused_async.stderr
+++ b/src/tools/clippy/tests/ui/unused_async.stderr
@@ -27,7 +27,7 @@ LL |     async fn f3() {}
    = help: consider removing the `async` from this function
 
 error: unused `async` for function with no await statements
-  --> tests/ui/unused_async.rs:58:1
+  --> tests/ui/unused_async.rs:74:1
    |
 LL | / async fn foo() -> i32 {
 LL | |
@@ -38,7 +38,7 @@ LL | | }
    = help: consider removing the `async` from this function
 
 error: unused `async` for function with no await statements
-  --> tests/ui/unused_async.rs:70:5
+  --> tests/ui/unused_async.rs:86:5
    |
 LL | /     async fn unused(&self) -> i32 {
 LL | |
diff --git a/src/tools/clippy/tests/ui/unused_format_specs.1.fixed b/src/tools/clippy/tests/ui/unused_format_specs.1.fixed
new file mode 100644
index 00000000000..b7d1cce2870
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_format_specs.1.fixed
@@ -0,0 +1,35 @@
+#![warn(clippy::unused_format_specs)]
+#![allow(unused)]
+
+macro_rules! format_args_from_macro {
+    () => {
+        format_args!("from macro")
+    };
+}
+
+fn main() {
+    // prints `.`, not `     .`
+    println!("{:5}.", format!(""));
+    //~^ ERROR: format specifiers have no effect on `format_args!()`
+    //~| NOTE: `-D clippy::unused-format-specs` implied by `-D warnings`
+    //prints `abcde`, not `abc`
+    println!("{:.3}", format!("abcde"));
+    //~^ ERROR: format specifiers have no effect on `format_args!()`
+
+    println!("{}.", format_args_from_macro!());
+    //~^ ERROR: format specifiers have no effect on `format_args!()`
+
+    let args = format_args!("");
+    println!("{args}");
+    //~^ ERROR: format specifiers have no effect on `format_args!()`
+}
+
+fn should_not_lint() {
+    println!("{}", format_args!(""));
+    // Technically the same as `{}`, but the `format_args` docs specifically mention that you can use
+    // debug formatting so allow it
+    println!("{:?}", format_args!(""));
+
+    let args = format_args!("");
+    println!("{args}");
+}
diff --git a/src/tools/clippy/tests/ui/unused_format_specs.2.fixed b/src/tools/clippy/tests/ui/unused_format_specs.2.fixed
new file mode 100644
index 00000000000..94bb6b7036b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_format_specs.2.fixed
@@ -0,0 +1,35 @@
+#![warn(clippy::unused_format_specs)]
+#![allow(unused)]
+
+macro_rules! format_args_from_macro {
+    () => {
+        format_args!("from macro")
+    };
+}
+
+fn main() {
+    // prints `.`, not `     .`
+    println!("{}.", format_args!(""));
+    //~^ ERROR: format specifiers have no effect on `format_args!()`
+    //~| NOTE: `-D clippy::unused-format-specs` implied by `-D warnings`
+    //prints `abcde`, not `abc`
+    println!("{}", format_args!("abcde"));
+    //~^ ERROR: format specifiers have no effect on `format_args!()`
+
+    println!("{}.", format_args_from_macro!());
+    //~^ ERROR: format specifiers have no effect on `format_args!()`
+
+    let args = format_args!("");
+    println!("{args}");
+    //~^ ERROR: format specifiers have no effect on `format_args!()`
+}
+
+fn should_not_lint() {
+    println!("{}", format_args!(""));
+    // Technically the same as `{}`, but the `format_args` docs specifically mention that you can use
+    // debug formatting so allow it
+    println!("{:?}", format_args!(""));
+
+    let args = format_args!("");
+    println!("{args}");
+}
diff --git a/src/tools/clippy/tests/ui/unused_format_specs_unfixable.rs b/src/tools/clippy/tests/ui/unused_format_specs.rs
index be991935366..2c85e371149 100644
--- a/src/tools/clippy/tests/ui/unused_format_specs_unfixable.rs
+++ b/src/tools/clippy/tests/ui/unused_format_specs.rs
@@ -1,6 +1,6 @@
 #![warn(clippy::unused_format_specs)]
 #![allow(unused)]
-//@no-rustfix
+
 macro_rules! format_args_from_macro {
     () => {
         format_args!("from macro")
diff --git a/src/tools/clippy/tests/ui/unused_format_specs_unfixable.stderr b/src/tools/clippy/tests/ui/unused_format_specs.stderr
index d3b334c6092..2b5c81c63d6 100644
--- a/src/tools/clippy/tests/ui/unused_format_specs_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/unused_format_specs.stderr
@@ -1,5 +1,5 @@
 error: format specifiers have no effect on `format_args!()`
-  --> tests/ui/unused_format_specs_unfixable.rs:12:15
+  --> tests/ui/unused_format_specs.rs:12:15
    |
 LL |     println!("{:5}.", format_args!(""));
    |               ^^^^
@@ -17,7 +17,7 @@ LL +     println!("{}.", format_args!(""));
    |
 
 error: format specifiers have no effect on `format_args!()`
-  --> tests/ui/unused_format_specs_unfixable.rs:16:15
+  --> tests/ui/unused_format_specs.rs:16:15
    |
 LL |     println!("{:.3}", format_args!("abcde"));
    |               ^^^^^
@@ -33,7 +33,7 @@ LL +     println!("{}", format_args!("abcde"));
    |
 
 error: format specifiers have no effect on `format_args!()`
-  --> tests/ui/unused_format_specs_unfixable.rs:19:15
+  --> tests/ui/unused_format_specs.rs:19:15
    |
 LL |     println!("{:5}.", format_args_from_macro!());
    |               ^^^^
@@ -46,7 +46,7 @@ LL +     println!("{}.", format_args_from_macro!());
    |
 
 error: format specifiers have no effect on `format_args!()`
-  --> tests/ui/unused_format_specs_unfixable.rs:23:15
+  --> tests/ui/unused_format_specs.rs:23:15
    |
 LL |     println!("{args:5}");
    |               ^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/useful_asref.rs b/src/tools/clippy/tests/ui/useful_asref.rs
index a9f0170a79c..d17db9371ee 100644
--- a/src/tools/clippy/tests/ui/useful_asref.rs
+++ b/src/tools/clippy/tests/ui/useful_asref.rs
@@ -1,4 +1,5 @@
 #![deny(clippy::useless_asref)]
+#![allow(clippy::needless_lifetimes)]
 
 trait Trait {
     fn as_ptr(&self);
diff --git a/src/tools/clippy/tests/ui/wild_in_or_pats.rs b/src/tools/clippy/tests/ui/wild_in_or_pats.rs
index f8bb31b83c4..bc8a1dbee71 100644
--- a/src/tools/clippy/tests/ui/wild_in_or_pats.rs
+++ b/src/tools/clippy/tests/ui/wild_in_or_pats.rs
@@ -37,4 +37,72 @@ fn main() {
             dbg!("matched (bar or) wild");
         },
     };
+
+    // shouldn't lint
+    #[non_exhaustive]
+    pub enum NonExhaustiveEnum<'a> {
+        Message(&'a str),
+        Quit(&'a str),
+        Other,
+    }
+
+    match NonExhaustiveEnum::Message("Pass") {
+        NonExhaustiveEnum::Message(_) => dbg!("message"),
+        NonExhaustiveEnum::Quit(_) => dbg!("quit"),
+        NonExhaustiveEnum::Other | _ => dbg!("wildcard"),
+    };
+
+    // should lint
+    enum ExhaustiveEnum {
+        Quit,
+        Write(String),
+        ChangeColor(i32, i32, i32),
+    }
+
+    match ExhaustiveEnum::ChangeColor(0, 160, 255) {
+        ExhaustiveEnum::Write(text) => {
+            dbg!("Write");
+        },
+        ExhaustiveEnum::ChangeColor(r, g, b) => {
+            dbg!("Change the color");
+        },
+        ExhaustiveEnum::Quit | _ => {
+            dbg!("Quit or other");
+        },
+    };
+
+    // shouldn't lint
+    #[non_exhaustive]
+    struct NonExhaustiveStruct {
+        a: u32,
+        b: u32,
+        c: u64,
+    }
+
+    let b = NonExhaustiveStruct { a: 5, b: 42, c: 342 };
+
+    match b {
+        NonExhaustiveStruct { a: 5, b: 42, .. } => {},
+        NonExhaustiveStruct { a: 0, b: 0, c: 128 } => {},
+        NonExhaustiveStruct { a: 0, b: 0, c: 128, .. } | _ => {},
+    }
+
+    // should lint
+    struct ExhaustiveStruct {
+        x: i32,
+        y: i32,
+    }
+
+    let p = ExhaustiveStruct { x: 0, y: 7 };
+    match p {
+        ExhaustiveStruct { x: 0, y: 0 } => {
+            dbg!("On the x axis at {x}");
+        },
+        ExhaustiveStruct { x: 0, y: 1 } => {
+            dbg!("On the y axis at {y}");
+        },
+        ExhaustiveStruct { x: 1, y: 1 } | _ => {
+            dbg!("On neither axis: ({x}, {y})");
+        },
+    }
 }
diff --git a/src/tools/clippy/tests/ui/wild_in_or_pats.stderr b/src/tools/clippy/tests/ui/wild_in_or_pats.stderr
index 06b2415d221..5e409d6dfa6 100644
--- a/src/tools/clippy/tests/ui/wild_in_or_pats.stderr
+++ b/src/tools/clippy/tests/ui/wild_in_or_pats.stderr
@@ -32,5 +32,21 @@ LL |         _ | "bar" => {
    |
    = help: consider handling `_` separately
 
-error: aborting due to 4 previous errors
+error: wildcard pattern covers any other pattern as it will match anyway
+  --> tests/ui/wild_in_or_pats.rs:69:9
+   |
+LL |         ExhaustiveEnum::Quit | _ => {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider handling `_` separately
+
+error: wildcard pattern covers any other pattern as it will match anyway
+  --> tests/ui/wild_in_or_pats.rs:104:9
+   |
+LL |         ExhaustiveStruct { x: 1, y: 1 } | _ => {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider handling `_` separately
+
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/zombie_processes.rs b/src/tools/clippy/tests/ui/zombie_processes.rs
index a2abc7fc3a1..b41bcce3f7f 100644
--- a/src/tools/clippy/tests/ui/zombie_processes.rs
+++ b/src/tools/clippy/tests/ui/zombie_processes.rs
@@ -131,6 +131,13 @@ fn main() {
         }
         x.wait().unwrap();
     }
+
+    {
+        let mut x = Command::new("").spawn().unwrap();
+        std::thread::spawn(move || {
+            x.wait().unwrap();
+        });
+    }
 }
 
 fn process_child(c: Child) {
diff --git a/src/tools/compiletest/src/command-list.rs b/src/tools/compiletest/src/command-list.rs
index 865aa76ddb0..bcdd4a69b66 100644
--- a/src/tools/compiletest/src/command-list.rs
+++ b/src/tools/compiletest/src/command-list.rs
@@ -64,23 +64,8 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "ignore-loongarch64",
     "ignore-macabi",
     "ignore-macos",
-    "ignore-mode-assembly",
-    "ignore-mode-codegen",
-    "ignore-mode-codegen-units",
     "ignore-mode-coverage-map",
     "ignore-mode-coverage-run",
-    "ignore-mode-crashes",
-    "ignore-mode-debuginfo",
-    "ignore-mode-incremental",
-    "ignore-mode-js-doc-test",
-    "ignore-mode-mir-opt",
-    "ignore-mode-pretty",
-    "ignore-mode-run-make",
-    "ignore-mode-run-pass-valgrind",
-    "ignore-mode-rustdoc",
-    "ignore-mode-rustdoc-json",
-    "ignore-mode-ui",
-    "ignore-mode-ui-fulldeps",
     "ignore-msp430",
     "ignore-msvc",
     "ignore-musl",
@@ -139,6 +124,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "needs-deterministic-layouts",
     "needs-dlltool",
     "needs-dynamic-linking",
+    "needs-enzyme",
     "needs-force-clang-based-tests",
     "needs-git-hash",
     "needs-llvm-components",
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 2d8c0c3fa5e..adc89cad72f 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -349,6 +349,9 @@ pub struct Config {
     /// whether to run `tidy` when a rustdoc test fails
     pub has_tidy: bool,
 
+    /// whether to run `enzyme` autodiff tests
+    pub has_enzyme: bool,
+
     /// The current Rust channel
     pub channel: String,
 
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index a291ff37112..83a10c56208 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -218,6 +218,8 @@ pub struct TestProps {
     pub filecheck_flags: Vec<String>,
     /// Don't automatically insert any `--check-cfg` args
     pub no_auto_check_cfg: bool,
+    /// Run tests which require enzyme being build
+    pub has_enzyme: bool,
 }
 
 mod directives {
@@ -322,6 +324,7 @@ impl TestProps {
             llvm_cov_flags: vec![],
             filecheck_flags: vec![],
             no_auto_check_cfg: false,
+            has_enzyme: false,
         }
     }
 
@@ -1115,6 +1118,7 @@ fn expand_variables(mut value: String, config: &Config) -> String {
     const CWD: &str = "{{cwd}}";
     const SRC_BASE: &str = "{{src-base}}";
     const BUILD_BASE: &str = "{{build-base}}";
+    const RUST_SRC_BASE: &str = "{{rust-src-base}}";
     const SYSROOT_BASE: &str = "{{sysroot-base}}";
     const TARGET_LINKER: &str = "{{target-linker}}";
     const TARGET: &str = "{{target}}";
@@ -1144,6 +1148,13 @@ fn expand_variables(mut value: String, config: &Config) -> String {
         value = value.replace(TARGET, &config.target);
     }
 
+    if value.contains(RUST_SRC_BASE) {
+        let src_base = config.sysroot_base.join("lib/rustlib/src/rust");
+        src_base.try_exists().expect(&*format!("{} should exists", src_base.display()));
+        let src_base = src_base.read_link().unwrap_or(src_base);
+        value = value.replace(RUST_SRC_BASE, &src_base.to_string_lossy());
+    }
+
     value
 }
 
diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs
index 948568e63c2..f3835637a1e 100644
--- a/src/tools/compiletest/src/header/cfg.rs
+++ b/src/tools/compiletest/src/header/cfg.rs
@@ -1,6 +1,6 @@
 use std::collections::HashSet;
 
-use crate::common::{CompareMode, Config, Debugger, Mode};
+use crate::common::{CompareMode, Config, Debugger};
 use crate::header::IgnoreDecision;
 
 const EXTRA_ARCHS: &[&str] = &["spirv"];
@@ -222,7 +222,7 @@ pub(super) fn parse_cfg_name_directive<'a>(
         name: format!("mode-{}", config.mode.to_str()),
         allowed_names: ContainsPrefixed {
             prefix: "mode-",
-            inner: Mode::STR_VARIANTS,
+            inner: ["coverage-run", "coverage-map"],
         },
         message: "when the test mode is {name}",
     }
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index 99c0e850f1a..f5dd722ed37 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -80,6 +80,11 @@ pub(super) fn handle_needs(
             ignore_reason: "ignored on targets without SafeStack support",
         },
         Need {
+            name: "needs-enzyme",
+            condition: config.has_enzyme,
+            ignore_reason: "ignored when LLVM Enzyme is disabled",
+        },
+        Need {
             name: "needs-run-enabled",
             condition: config.run_enabled(),
             ignore_reason: "ignored when running the resulting test binaries is disabled",
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index ae661200c6c..76a8b129198 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -1,6 +1,5 @@
 use std::io::Read;
 use std::path::Path;
-use std::str::FromStr;
 
 use super::iter_header;
 use crate::common::{Config, Debugger, Mode};
@@ -574,14 +573,12 @@ fn families() {
 
 #[test]
 fn ignore_mode() {
-    for &mode in Mode::STR_VARIANTS {
+    for mode in ["coverage-map", "coverage-run"] {
         // Indicate profiler support so that "coverage-run" tests aren't skipped.
         let config: Config = cfg().mode(mode).profiler_support(true).build();
         let other = if mode == "coverage-run" { "coverage-map" } else { "coverage-run" };
 
         assert_ne!(mode, other);
-        assert_eq!(config.mode, Mode::from_str(mode).unwrap());
-        assert_ne!(config.mode, Mode::from_str(other).unwrap());
 
         assert!(check_ignore(&config, &format!("//@ ignore-mode-{mode}")));
         assert!(!check_ignore(&config, &format!("//@ ignore-mode-{other}")));
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index cfc619f9342..a8355ee9590 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -83,6 +83,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         )
         .optopt("", "run", "whether to execute run-* tests", "auto | always | never")
         .optflag("", "ignored", "run tests marked as ignored")
+        .optflag("", "has-enzyme", "run tests that require enzyme")
         .optflag("", "with-debug-assertions", "whether to run tests with `ignore-debug` header")
         .optmulti(
             "",
@@ -233,6 +234,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         // Avoid spawning an external command when we know tidy won't be used.
         false
     };
+    let has_enzyme = matches.opt_present("has-enzyme");
     let filters = if mode == Mode::RunMake {
         matches
             .free
@@ -331,6 +333,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
             .map(|s| s.parse().expect("invalid --compare-mode provided")),
         rustfix_coverage: matches.opt_present("rustfix-coverage"),
         has_tidy,
+        has_enzyme,
         channel: matches.opt_str("channel").unwrap(),
         git_hash: matches.opt_present("git-hash"),
         edition: matches.opt_str("edition"),
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 0674debd6a2..e26c178ccb0 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -39,7 +39,7 @@ mod assembly;
 mod codegen;
 mod codegen_units;
 mod coverage;
-mod crash;
+mod crashes;
 mod debuginfo;
 mod incremental;
 mod js_doc;
@@ -2298,13 +2298,19 @@ impl<'test> TestCx<'test> {
         }
 
         let base_dir = Path::new("/rustc/FAKE_PREFIX");
-        // Paths into the libstd/libcore
+        // Fake paths into the libstd/libcore
         normalize_path(&base_dir.join("library"), "$SRC_DIR");
         // `ui-fulldeps` tests can show paths to the compiler source when testing macros from
         // `rustc_macros`
         // eg. /home/user/rust/compiler
         normalize_path(&base_dir.join("compiler"), "$COMPILER_DIR");
 
+        // Real paths into the libstd/libcore
+        let rust_src_dir = &self.config.sysroot_base.join("lib/rustlib/src/rust");
+        rust_src_dir.try_exists().expect(&*format!("{} should exists", rust_src_dir.display()));
+        let rust_src_dir = rust_src_dir.read_link().unwrap_or(rust_src_dir.to_path_buf());
+        normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL");
+
         // Paths into the build directory
         let test_build_dir = &self.config.build_base;
         let parent_build_dir = test_build_dir.parent().unwrap().parent().unwrap().parent().unwrap();
@@ -2314,9 +2320,6 @@ impl<'test> TestCx<'test> {
         // eg. /home/user/rust/build
         normalize_path(parent_build_dir, "$BUILD_DIR");
 
-        // Paths into lib directory.
-        normalize_path(&parent_build_dir.parent().unwrap().join("lib"), "$LIB_DIR");
-
         if json {
             // escaped newlines in json strings should be readable
             // in the stderr files. There's no point int being correct,
diff --git a/src/tools/compiletest/src/runtest/crash.rs b/src/tools/compiletest/src/runtest/crashes.rs
index 885ed3b08fa..885ed3b08fa 100644
--- a/src/tools/compiletest/src/runtest/crash.rs
+++ b/src/tools/compiletest/src/runtest/crashes.rs
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index b9441236bcd..8b0916f5111 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -12,9 +12,6 @@ on:
   schedule:
     - cron: '44 4 * * *' # At 4:44 UTC every day.
 
-permissions:
-  contents: write
-
 defaults:
   run:
     shell: bash
@@ -90,6 +87,11 @@ jobs:
   cron-fail-notify:
     name: cronjob failure notification
     runs-on: ubuntu-latest
+    permissions:
+        # The cronjob needs to be able to push to the repo...
+        contents: write
+        # ... and create a PR.
+        pull-requests: write
     needs: [build, style]
     if: github.event_name == 'schedule' && failure()
     steps:
diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock
index 002c44b0cc5..05d1c2d1eb3 100644
--- a/src/tools/miri/Cargo.lock
+++ b/src/tools/miri/Cargo.lock
@@ -137,9 +137,12 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.1.7"
+version = "1.1.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc"
+checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
+dependencies = [
+ "shlex",
+]
 
 [[package]]
 name = "cfg-if"
@@ -164,9 +167,9 @@ dependencies = [
 
 [[package]]
 name = "chrono-tz"
-version = "0.9.0"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb"
+checksum = "cd6dd8046d00723a59a2f8c5f295c515b9bb9a331ee4f8f3d4dd49e428acd3b6"
 dependencies = [
  "chrono",
  "chrono-tz-build",
@@ -175,12 +178,11 @@ dependencies = [
 
 [[package]]
 name = "chrono-tz-build"
-version = "0.3.0"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1"
+checksum = "e94fea34d77a245229e7746bd2beb786cd2a896f306ff491fb8cecb3074b10a7"
 dependencies = [
  "parse-zoneinfo",
- "phf",
  "phf_codegen",
 ]
 
@@ -948,6 +950,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
 name = "siphasher"
 version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index 30cea9da373..cb02914fd93 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -25,7 +25,7 @@ aes = { version = "0.8.3", features = ["hazmat"] }
 measureme = "11"
 ctrlc = "3.2.5"
 chrono = { version = "0.4.38", default-features = false }
-chrono-tz = "0.9"
+chrono-tz = "0.10"
 directories = "5"
 
 # Copied from `compiler/rustc/Cargo.toml`.
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index d8636915ea8..f6349f45f43 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -219,7 +219,7 @@ degree documented below):
   - `solaris` / `illumos`: maintained by @devnexen. Supports `std::{env, thread, sync}`, but not `std::fs`.
   - `freebsd`: **maintainer wanted**. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`.
   - `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works.
-  - `wasm`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works.
+  - `wasi`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works.
 - For targets on other operating systems, Miri might fail before even reaching the `main` function.
 
 However, even for targets that we do support, the degree of support for accessing platform APIs
diff --git a/src/tools/miri/bench-cargo-miri/backtraces/Cargo.lock b/src/tools/miri/bench-cargo-miri/backtraces/Cargo.lock
index 375b129a7e5..848864ea1f3 100644
--- a/src/tools/miri/bench-cargo-miri/backtraces/Cargo.lock
+++ b/src/tools/miri/bench-cargo-miri/backtraces/Cargo.lock
@@ -41,9 +41,12 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.73"
+version = "1.1.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
+checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
+dependencies = [
+ "shlex",
+]
 
 [[package]]
 name = "cfg-if"
@@ -92,3 +95,9 @@ name = "rustc-demangle"
 version = "0.1.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
diff --git a/src/tools/miri/bench-cargo-miri/backtraces/src/main.rs b/src/tools/miri/bench-cargo-miri/backtraces/src/main.rs
index eba51c60dbc..b1a58712bec 100644
--- a/src/tools/miri/bench-cargo-miri/backtraces/src/main.rs
+++ b/src/tools/miri/bench-cargo-miri/backtraces/src/main.rs
@@ -1,8 +1,9 @@
 //! Extracted from the backtrace crate's test test_frame_conversion
 
-use backtrace::{Backtrace, BacktraceFrame};
 use std::fmt::Write;
 
+use backtrace::{Backtrace, BacktraceFrame};
+
 fn main() {
     let mut frames = vec![];
     backtrace::trace(|frame| {
diff --git a/src/tools/miri/bench-cargo-miri/serde2/src/main.rs b/src/tools/miri/bench-cargo-miri/serde2/src/main.rs
index 83c04b9dd5f..8842d4ce310 100644
--- a/src/tools/miri/bench-cargo-miri/serde2/src/main.rs
+++ b/src/tools/miri/bench-cargo-miri/serde2/src/main.rs
@@ -1,9 +1,10 @@
 // Like serde1, but in two threads concurrently. And we don't print.
 static JSON: &str = r#"{"buffer":[-29,-42,-40,-37,-28,-5,-21,1,-24,-8,-20,4,-18,26,-24,44,-26,66,-30,86,-37,88,-41,72,-46,50,-31,28,23,14,64,16,51,26,32,34,39,42,48,35,58,0,72,-36,69,-59,58,-98,54,-124,36,-103,12,-110,5,-173,-19,-146,-59,-4,-42,51,1,-23,-6,-30,-6,45,46,47,70,6,55,19,60,38,62,42,47,61,46,40,42,-19,22,-34,6,-35,-50,-61,-141,-37,-171,17,-163,26,-180,46,-154,80,-63,48,-4,18,20,50,47,58,53,44,61,57,85,37,80,0,86,-8,106,-95,49,-213,-8,-131,47,49,63,40,-39,-69,-74,-37,-20,63,-12,58,-14,-12,25,-31,41,11,45,76,47,167,5,261,-37,277,-83,183,-172,35,-122,-79,138,-70,266,69,124,228,0,391,-29,594,-84,702,-78,627,-8,551,-13,509,13,372,120,352,125,622,127,691,223,362,126,386,-33,915,198,958,457,456,298,500,233,1027,469,1096,426,918,160,1067,141,1220,189,1245,164,1375,297,1378,503,1299,702,1550,929,1799,855,1752,547,1830,602,1928,832,1736,796,1735,933,1961,1385,1935,1562,2105,1485,2716,1449,2948,1305,2768,1205,2716,1346,2531,1450,2470,1653,3117,2111,3370,2176,2696,1947,2925,2305,3846,2658,2425,2184,-877,1981,-2261,2623,-1645,2908,-1876,2732,-2704,2953,-2484,3116,-2120,2954,-2442,3216,-2466,3499,-2192,3234,-2392,3361,-2497,3869,-2078,3772,-1858,3915,-2066,4438,-2285,2934,-2294,-280,-2066,-1762,-1992,-1412,-2298,-1535,-2399,-1789,-2223,-1419,-2244,-1334,-2092,-1476,-1777,-1396,-2014,-1571,-2199,-1574,-1843,-1167,-1910,-1446,-2007,-1818,-1506,-1331,-2526,-2048,-5535,-4573,-7148,-5828,-6422,-5327,-5840,-5488,-5992,-6144,-6014,-6164,-6109,-6234,-6271,-6388,-6288,-6156,-6517,-6249,-6794,-6602,-6822,-6418,-6788,-6245,-6490,-6560,-6394,-6794,-7920,-6937,-10397,-7140,-11428,-6972,-11019,-6610,-11141,-6665,-11913,-7046,-11979,-7235,-11599,-7015,-11854,-6912,-12161,-7441,-12136,-7761,-12861,-7292,-13390,-7254,-12345,-7809,-12490,-7463,-13983,-6969,-10489,-8465,-2382,-11054,1272,-12247,-270,-12060,-323,-12113,502,-12486,-697,-12251,-1086,-12141,-181,-13116,-670,-13509,-1173,-12592,-443,-12811,-449,-13698,-934,-12850,-747,-13083,-873,-15036,-1161,-11478,-1047,-2669,-1407,1006,-1658,-1146,-1195,-1297,-1421,-73,-1946,-977,-1590,-1499,-1577,-1010,-1862,-1256,-1389,-962,-1692,-509,-2613,-1317,-2087,-1359,-1997,-1034,-2891,-2024,-119,-84,5651,5723,8074,8306,7156,6870,6985,7106,7312,8403,7114,8096,7173,7848,7082,7827,6761,7189,6985,7368,7076,7835,6992,7297,7453,7260,7016,7755,6025,7429,8533,7352,14150,7628,17142,7077,16399,6947,15939,7475,16564,7069,16463,6882,16400,7602,17031,7233,16543,6517,15395,7018,15985,7104,16689,6869,15655,7622,16155,7198,17884,6022,14056,8856,5665,14484,1815,16782,3034,15786,3107,15664,2312,16517,2965,16443,3036,16120,2287,16584,2479,16720,2693,16073,2535,16159,2958,16609,3067,16086,2716,16579,3035,17752,3092,13704,2499,5265,2620,1452,2808,3024,2444,3275,2839,2267,3340,2857,2968,3232,3066,2867,3152,3072,2248,2961,2413,2807,3238,3237,2368,2699,2262,2392,3537,3339,827,823,-5020,-5359,-7095,-7857,-5973,-6274,-6208,-6279,-6934,-7181,-6893,-6647,-7146,-6687,-7026,-7328,-6451,-6924,-6763,-6535,-7109,-6639,-6926,-6559,-7188,-6799,-6727,-6955,-5786,-6554,-8543,-6796,-14465,-7190,-17356,-6641,-16372,-6529,-15941,-6898,-16526,-6434,-16219,-6520,-16222,-7449,-17077,-7097,-16665,-6476,-15675,-7026,-16498,-6848,-17147,-6271,-15894,-7069,-16266,-7032,-17817,-5991,-13796,-8594,-5421,-14349,-1649,-17288,-2847,-16525,-2974,-15945,-2324,-16482,-3022,-16593,-3097,-16451,-2420,-16780,-2649,-16641,-2836,-15900,-2660,-16214,-3050,-16827,-3111,-15993,-2741,-16151,-2994,-17537,-2933,-13812,-2314,-5216,-2475,-1125,-2648,-2801,-2290,-3285,-2796,-2243,-3415,-2642,-3109,-3000,-3271,-2839,-3408,-3161,-2497,-2876,-2603,-2570,-3351,-3173,-2416,-2832,-2235,-2408,-3405,-3186,-613,-768,5271,5201,7376,7644,6241,6176,6366,6275,6964,7124,6831,6508,6998,6566,6836,7230,6277,6777,6589,6376,6934,6536,6819,6494,7160,6749,6736,6900,5822,6476,8593,6747,14520,7204,17448,6637,16490,6483,16033,6906,16600,6511,16304,6568,16279,7438,17079,7072,16624,6463,15577,7028,16343,6877,16990,6331,15760,7121,16140,7023,17719,5944,13748,8575,5401,14336,1645,17210,2880,16419,3036,15896,2382,16483,3074,16584,3143,16425,2443,16782,2650,16695,2825,15978,2632,16272,3015,16880,3084,16096,2709,16289,2965,17641,2932,13887,2323,5330,2474,1286,2656,2954,2309,3410,2803,2373,3414,2795,3106,3151,3263,2952,3403,3241,2483,2969,2568,2681,3316,3245,2383,2837,2199,2390,3396,3165,641,706,-5230,-5323,-7307,-7790,-6136,-6317,-6268,-6419,-6884,-7278,-6766,-6666,-6976,-6731,-6853,-7406,-6308,-6958,-6636,-6553,-6978,-6703,-6829,-6647,-7156,-6883,-6737,-7017,-5814,-6581,-8575,-6833,-14490,-7270,-17411,-6699,-16466,-6539,-16016,-6931,-16571,-6504,-16257,-6551,-16202,-7408,-16983,-7021,-16545,-6410,-15512,-6976,-16305,-6803,-17017,-6243,-15820,-7037,-16197,-6923,-17802,-5820,-13840,-8455,-5475,-14227,-1724,-17099,-2923,-16314,-3008,-15801,-2362,-16392,-3088,-16506,-3163,-16356,-2503,-16700,-2717,-16605,-2855,-15904,-2710,-16226,-3108,-16870,-3089,-16101,-2747,-16257,-3087,-17584,-2975,-13868,-2324,-5343,-2548,-1275,-2673,-2917,-2213,-3363,-2694,-2311,-3251,-2744,-2867,-3129,-3034,-2939,-3190,-3234,-2346,-2964,-2639,-2658,-3558,-3241,-2670,-2892,-2453,-2437,-3564,-3175,-771,-779,5105,5171,7308,7655,6265,6204,6397,6288,7024,7172,6903,6586,7002,6627,6777,7308,6190,6889,6537,6465,7011,6613,6985,6631,7393,6934,7073,7072,6112,6615,8751,6859,14672,7282,17448,6652,16146,6448,15565,6899,16151,6547,15860,6591,16048,7446,17065,7064,16661,6368,15774,6857,16524,6677,16825,6071,15577,6900,16119,7040,17490,6118,13495,8696,5432,14446,1678,17366,3036,16488,3624,15834,3012,16382,3575,16465,3685,16301,2815,16708,2982,16679,3356,15952,2934,16049,3290,16352,3964,15605,3612,16222,3647,17764,4272,13865,3977,5384,3592,1580,3794,3243,3627,3670,3622,2758,4007,3130,3835,3294,3964,3065,4468,3408,3933,3234,3789,3118,4634,3643,4211,3174,4155,3176,5512,4400,2792,1730,-3702,-4499,-5940,-6691,-4265,-5094,-4381,-5215,-4918,-5746,-4217,-4871,-4402,-4981,-4479,-5525,-3732,-4968,-4118,-4924,-4300,-5349,-3422,-5021,-3876,-4886,-4087,-4860,-2790,-4254,-5025,-4196,-10898,-4415,-13419,-4007,-12198,-4121,-11995,-4413,-12471,-3808,-11937,-3920,-11792,-4583,-12284,-3776,-12085,-3107,-11421,-3583,-11226,-3081,-11157,-2768,-10580,-3914,-10424,-3197,-11040,-1715,-9822,-5144,-6189,-11154,-4236,-13029,-5134,-11598,-5507,-10949,-4921,-11142,-4999,-11180,-4883,-11184,-4366,-11090,-4548,-10887,-4818,-10708,-4866,-10534,-5253,-10272,-5179,-9894,-4633,-10029,-4773,-10382,-4977,-8674,-4668,-5292,-4651,-3928,-4629,-4465,-4312,-3994,-4459,-3528,-4570,-4400,-4272,-4601,-4482,-4035,-4627,-4334,-4080,-4498,-4045,-3835,-4204,-3526,-3695,-3646,-4045,-4101,-4856,-4628,-3338,-3235,-673,-508,28,147,-453,-639,11,0,8,-2,7,0,7,-3,11,-8,15,-9,17,-6,17,-5,13,-3,7,0,3,0,-2,0,-4,0,-4,-2,-6,0,-14,-2,-17,-4,-8,0,-7,5,-17,7,-18,10,-7,18,-2,25,-3,27,0,31,4,34,4,34,8,36,8,37,2,36,4,34,8,28,3,15,0,11,0,12,-5,8,-4,10,0,23,-4,31,-8,30,-2,30,0,26,-6,22,-6,20,-12,15,-19,10,-10,13,-14,6,-43,-13,-43,-16,-9,-12,-10,-29,-42,-40,-37,-28,-5,-21,1,-24,-8,-20,4,-18,26,-24,44,-26,66,-30,86,-37,88,-41,72,-46,50,-31,28,23,14,64,16,51,26,32,34,39,42,48,35,58,0,72,-36,69,-59,58,-98,54,-124,36,-103,12,-110,5,-173,-19,-146,-59,-4,-42,51,1,-23,-6,-30,-6,45,46,47,70,6,55,19,60,38,62,42,47,61,46,40,42,-19,22,-34,6,-35,-50,-61,-141,-37,-171,17,-163,26,-180,46,-154,80,-63,48,-4,18,20,50,47,58,53,44,61,57,85,37,80,0,86,-8,106,-95,49,-213,-8,-131,47,49,63,40,-39,-69,-74,-37,-20,63,-12,58,-14,-12,25,-31,41,11,45,76,47,167,5,261,-37,277,-83,183,-172,35,-122,-79,138,-70,266,69,124,228,0,391,-29,594,-84,702,-78,627,-8,551,-13,509,13,372,120,352,125,622,127,691,223,362,126,386,-33,915,198,958,457,456,298,500,233,1027,469,1096,426,918,160,1067,141,1220,189,1245,164,1375,297,1378,503,1299,702,1550,929,1799,855,1752,547,1830,602,1928,832,1736,796,1735,933,1961,1385,1935,1562,2105,1485,2716,1449,2948,1305,2768,1205,2716,1346,2531,1450,2470,1653,3117,2111,3370,2176,2696,1947,2925,2305,3846,2658,2425,2184,-877,1981,-2261,2623,-1645,2908,-1876,2732,-2704,2953,-2484,3116,-2120,2954,-2442,3216,-2466,3499,-2192,3234,-2392,3361,-2497,3869,-2078,3772,-1858,3915,-2066,4438,-2285,2934,-2294,-280,-2066,-1762,-1992,-1412,-2298,-1535,-2399,-1789,-2223,-1419,-2244,-1334,-2092,-1476,-1777,-1396,-2014,-1571,-2199,-1574,-1843,-1167,-1910,-1446,-2007,-1818,-1506,-1331,-2526,-2048,-5535,-4573,-7148,-5828,-6422,-5327,-5840,-5488,-5992,-6144,-6014,-6164,-6109,-6234,-6271,-6388,-6288,-6156,-6517,-6249,-6794,-6602,-6822,-6418,-6788,-6245,-6490,-6560,-6394,-6794,-7920,-6937,-10397,-7140,-11428,-6972,-11019,-6610,-11141,-6665,-11913,-7046,-11979,-7235,-11599,-7015,-11854,-6912,-12161,-7441,-12136,-7761,-12861,-7292,-13390,-7254,-12345,-7809,-12490,-7463,-13983,-6969,-10489,-8465,-2382,-11054,1272,-12247,-270,-12060,-323,-12113,502,-12486,-697,-12251,-1086,-12141,-181,-13116,-670,-13509,-1173,-12592,-443,-12811,-449,-13698,-934,-12850,-747,-13083,-873,-15036,-1161,-11478,-1047,-2669,-1407,1006,-1658,-1146,-1195,-1297,-1421,-73,-1946,-977,-1590,-1499,-1577,-1010,-1862,-1256,-1389,-962,-1692,-509,-2613,-1317,-2087,-1359,-1997,-1034,-2891,-2024,-119,-84,5651,5723,8074,8306,7156,6870,6985,7106,7312,8403,7114,8096,7173,7848,7082,7827,6761,7189,6985,7368]}"#;
 
-use serde::Deserialize;
 use std::thread;
 
+use serde::Deserialize;
+
 #[derive(Deserialize)]
 #[allow(unused)]
 struct DeriveStruct {
diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock
index 7369a3fbf09..a873472fd5d 100644
--- a/src/tools/miri/cargo-miri/Cargo.lock
+++ b/src/tools/miri/cargo-miri/Cargo.lock
@@ -190,9 +190,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.5.3"
+version = "0.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2471f8f296262437d7e848e527b4210b44a96e53a3b4435b890227ce3e6da106"
+checksum = "d6d984a9db43148467059309bd1e5ad577085162f695d9fe2cf3543aeb25cd38"
 dependencies = [
  "anyhow",
  "rustc_version",
diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml
index 477c60db162..ee2004278b4 100644
--- a/src/tools/miri/cargo-miri/Cargo.toml
+++ b/src/tools/miri/cargo-miri/Cargo.toml
@@ -18,7 +18,7 @@ directories = "5"
 rustc_version = "0.4"
 serde_json = "1.0.40"
 cargo_metadata = "0.18.0"
-rustc-build-sysroot = "0.5.3"
+rustc-build-sysroot = "0.5.4"
 
 # Enable some feature flags that dev-dependencies need but dependencies
 # do not.  This makes `./miri install` after `./miri build` faster.
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index 3743446e276..f1f76fd338c 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -8,7 +8,8 @@ use std::{env, thread};
 
 use rustc_version::VersionMeta;
 
-use crate::{setup::*, util::*};
+use crate::setup::*;
+use crate::util::*;
 
 const CARGO_MIRI_HELP: &str = r"Runs binary crates and tests in Miri
 
@@ -666,6 +667,7 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner
         match phase {
             RunnerPhase::Rustdoc => {
                 cmd.stdin(std::process::Stdio::piped());
+                // the warning is wrong, we have a `wait` inside the `scope` closure.
                 let mut child = cmd.spawn().expect("failed to spawn process");
                 let child_stdin = child.stdin.take().unwrap();
                 // Write stdin in a background thread, as it may block.
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index c7be71662bd..689bc6d46fc 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -148,18 +148,18 @@ case $HOST_TARGET in
     TEST_TARGET=arm-unknown-linux-gnueabi run_tests
     TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice
     # Partially supported targets (tier 2)
-    BASIC="empty_main integer vec string btreemap hello hashmap heap_alloc align" # ensures we have the basics: stdout/stderr, system allocator, randomness (for HashMap initialization)
-    UNIX="panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
-    TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname pthread time fs
-    TEST_TARGET=i686-unknown-freebsd   run_tests_minimal $BASIC $UNIX threadname pthread time fs
-    TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX thread sync available-parallelism time tls
-    TEST_TARGET=x86_64-pc-solaris      run_tests_minimal $BASIC $UNIX thread sync available-parallelism time tls
-    TEST_TARGET=aarch64-linux-android  run_tests_minimal $BASIC $UNIX pthread --skip threadname --skip pthread_cond_timedwait
-    TEST_TARGET=wasm32-wasip2          run_tests_minimal empty_main wasm heap_alloc libc-mem
-    TEST_TARGET=wasm32-unknown-unknown run_tests_minimal empty_main wasm
+    BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator
+    UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
+    TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs
+    TEST_TARGET=i686-unknown-freebsd   run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs
+    TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls
+    TEST_TARGET=x86_64-pc-solaris      run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls
+    TEST_TARGET=aarch64-linux-android  run_tests_minimal $BASIC $UNIX time hashmap pthread --skip threadname
+    TEST_TARGET=wasm32-wasip2          run_tests_minimal $BASIC wasm
+    TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std
     TEST_TARGET=thumbv7em-none-eabihf  run_tests_minimal no_std
     # Custom target JSON file
-    TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std
+    TEST_TARGET=tests/x86_64-unknown-kernel.json MIRI_NO_STD=1 run_tests_minimal no_std
     ;;
   i686-pc-windows-msvc)
     # Host
diff --git a/src/tools/miri/miri-script/Cargo.lock b/src/tools/miri/miri-script/Cargo.lock
index 8f19576c51d..146e613c24b 100644
--- a/src/tools/miri/miri-script/Cargo.lock
+++ b/src/tools/miri/miri-script/Cargo.lock
@@ -10,12 +10,6 @@ checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
 
 [[package]]
 name = "bitflags"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-
-[[package]]
-name = "bitflags"
 version = "2.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
@@ -112,13 +106,12 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
 
 [[package]]
 name = "libredox"
-version = "0.0.1"
+version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
+checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
 dependencies = [
- "bitflags 2.4.2",
+ "bitflags",
  "libc",
- "redox_syscall",
 ]
 
 [[package]]
@@ -151,12 +144,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "once_cell"
-version = "1.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
-
-[[package]]
 name = "option-ext"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -187,19 +174,10 @@ dependencies = [
 ]
 
 [[package]]
-name = "redox_syscall"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
-dependencies = [
- "bitflags 1.3.2",
-]
-
-[[package]]
 name = "redox_users"
-version = "0.4.4"
+version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4"
+checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
 dependencies = [
  "getrandom",
  "libredox",
@@ -221,7 +199,7 @@ version = "0.38.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
 dependencies = [
- "bitflags 2.4.2",
+ "bitflags",
  "errno",
  "libc",
  "linux-raw-sys",
@@ -342,48 +320,26 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "which"
-version = "4.4.2"
+version = "6.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
+checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f"
 dependencies = [
  "either",
  "home",
- "once_cell",
  "rustix",
+ "winsafe",
 ]
 
 [[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
 name = "winapi-util"
-version = "0.1.6"
+version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
 dependencies = [
- "winapi",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
 name = "windows-sys"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -523,6 +479,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
+name = "winsafe"
+version = "0.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
+
+[[package]]
 name = "xshell"
 version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/miri/miri-script/Cargo.toml b/src/tools/miri/miri-script/Cargo.toml
index 2922c24d6c0..23b9a625159 100644
--- a/src/tools/miri/miri-script/Cargo.toml
+++ b/src/tools/miri/miri-script/Cargo.toml
@@ -13,7 +13,7 @@ edition = "2021"
 # This is needed to make this package build on stable when the parent package uses unstable cargo features.
 
 [dependencies]
-which = "4.4"
+which = "6.0"
 walkdir = "2.3"
 itertools = "0.11"
 path_macro = "1.0"
diff --git a/src/tools/miri/miri-script/src/args.rs b/src/tools/miri/miri-script/src/args.rs
index c1688ca0fb6..55d9de4233d 100644
--- a/src/tools/miri/miri-script/src/args.rs
+++ b/src/tools/miri/miri-script/src/args.rs
@@ -1,5 +1,4 @@
-use std::env;
-use std::iter;
+use std::{env, iter};
 
 use anyhow::{Result, bail};
 
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index b0e62d5cda6..36175c8dd2b 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -1,12 +1,9 @@
-use std::env;
 use std::ffi::{OsStr, OsString};
 use std::io::Write;
-use std::net;
-use std::ops::Not;
-use std::ops::Range;
+use std::ops::{Not, Range};
 use std::path::PathBuf;
-use std::process;
 use std::time::Duration;
+use std::{env, net, process};
 
 use anyhow::{Context, Result, anyhow, bail};
 use path_macro::path;
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 76fe17316ac..eb4dfcf57cf 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-6ce376774c0bc46ac8be247bca93ff5a1287a8fc
+7067e4aee45c18cfa1c6af3bf79bd097684fb294
diff --git a/src/tools/miri/rustfmt.toml b/src/tools/miri/rustfmt.toml
index 3f9311d9d1a..49650d8486c 100644
--- a/src/tools/miri/rustfmt.toml
+++ b/src/tools/miri/rustfmt.toml
@@ -1,5 +1,10 @@
+# This matches rustc
 style_edition = "2024"
 use_small_heuristics = "Max"
+group_imports = "StdExternalCrate"
+imports_granularity = "Module"
+
+# Miri-specific settings
+force_multiline_blocks = true
 match_arm_blocks = false
 match_arm_leading_pipes = "Preserve"
-force_multiline_blocks = true
diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs
index c19a962e652..a13b14ca90a 100644
--- a/src/tools/miri/src/alloc_addresses/mod.rs
+++ b/src/tools/miri/src/alloc_addresses/mod.rs
@@ -7,14 +7,13 @@ use std::cell::RefCell;
 use std::cmp::max;
 
 use rand::Rng;
-
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_span::Span;
 use rustc_target::abi::{Align, Size};
 
-use crate::{concurrency::VClock, *};
-
 use self::reuse_pool::ReusePool;
+use crate::concurrency::VClock;
+use crate::*;
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum ProvenanceMode {
@@ -201,7 +200,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 AllocKind::Dead => unreachable!(),
             };
             // Ensure this pointer's provenance is exposed, so that it can be used by FFI code.
-            return Ok(base_ptr.expose_provenance().try_into().unwrap());
+            return interp_ok(base_ptr.expose_provenance().try_into().unwrap());
         }
         // We are not in native lib mode, so we control the addresses ourselves.
         if let Some((reuse_addr, clock)) =
@@ -210,7 +209,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             if let Some(clock) = clock {
                 ecx.acquire_clock(&clock);
             }
-            Ok(reuse_addr)
+            interp_ok(reuse_addr)
         } else {
             // We have to pick a fresh address.
             // Leave some space to the previous allocation, to give it some chance to be less aligned.
@@ -235,7 +234,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 throw_exhaust!(AddressSpaceFull);
             }
 
-            Ok(base_addr)
+            interp_ok(base_addr)
         }
     }
 
@@ -249,7 +248,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let global_state = &mut *global_state;
 
         match global_state.base_addr.get(&alloc_id) {
-            Some(&addr) => Ok(addr),
+            Some(&addr) => interp_ok(addr),
             None => {
                 // First time we're looking for the absolute address of this allocation.
                 let base_addr =
@@ -275,7 +274,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 };
                 global_state.int_to_ptr_map.insert(pos, (base_addr, alloc_id));
 
-                Ok(base_addr)
+                interp_ok(base_addr)
             }
         }
     }
@@ -288,12 +287,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let global_state = ecx.machine.alloc_addresses.get_mut();
         // In strict mode, we don't need this, so we can save some cycles by not tracking it.
         if global_state.provenance_mode == ProvenanceMode::Strict {
-            return Ok(());
+            return interp_ok(());
         }
         // Exposing a dead alloc is a no-op, because it's not possible to get a dead allocation
         // via int2ptr.
         if !ecx.is_alloc_live(alloc_id) {
-            return Ok(());
+            return interp_ok(());
         }
         trace!("Exposing allocation id {alloc_id:?}");
         let global_state = ecx.machine.alloc_addresses.get_mut();
@@ -301,7 +300,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if ecx.machine.borrow_tracker.is_some() {
             ecx.expose_tag(alloc_id, tag)?;
         }
-        Ok(())
+        interp_ok(())
     }
 
     fn ptr_from_addr_cast(&self, addr: u64) -> InterpResult<'tcx, Pointer> {
@@ -338,7 +337,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // cast is fairly irrelevant. Instead we generate this as a "wildcard" pointer, such that
         // *every time the pointer is used*, we do an `AllocId` lookup to find the (exposed)
         // allocation it might be referencing.
-        Ok(Pointer::new(Some(Provenance::Wildcard), Size::from_bytes(addr)))
+        interp_ok(Pointer::new(Some(Provenance::Wildcard), Size::from_bytes(addr)))
     }
 
     /// Convert a relative (tcx) pointer to a Miri pointer.
@@ -360,7 +359,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Size::from_bytes(base_addr),
         );
         // Add offset with the right kind of pointer-overflowing arithmetic.
-        Ok(base_ptr.wrapping_offset(offset, ecx))
+        interp_ok(base_ptr.wrapping_offset(offset, ecx))
     }
 
     // This returns some prepared `MiriAllocBytes`, either because `addr_from_alloc_id` reserved
@@ -391,9 +390,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             assert_eq!(prepared_alloc_bytes.len(), bytes.len());
             // Copy allocation contents into prepared memory.
             prepared_alloc_bytes.copy_from_slice(bytes);
-            Ok(prepared_alloc_bytes)
+            interp_ok(prepared_alloc_bytes)
         } else {
-            Ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align))
+            interp_ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align))
         }
     }
 
diff --git a/src/tools/miri/src/alloc_addresses/reuse_pool.rs b/src/tools/miri/src/alloc_addresses/reuse_pool.rs
index f6c16756344..b5366d5ce92 100644
--- a/src/tools/miri/src/alloc_addresses/reuse_pool.rs
+++ b/src/tools/miri/src/alloc_addresses/reuse_pool.rs
@@ -1,10 +1,10 @@
 //! Manages a pool of addresses that can be reused.
 
 use rand::Rng;
-
 use rustc_target::abi::{Align, Size};
 
-use crate::{MemoryKind, MiriConfig, ThreadId, concurrency::VClock};
+use crate::concurrency::VClock;
+use crate::{MemoryKind, MiriConfig, ThreadId};
 
 const MAX_POOL_SIZE: usize = 64;
 
diff --git a/src/tools/miri/src/alloc_bytes.rs b/src/tools/miri/src/alloc_bytes.rs
index 84225d83b6a..6ada8c66fde 100644
--- a/src/tools/miri/src/alloc_bytes.rs
+++ b/src/tools/miri/src/alloc_bytes.rs
@@ -1,7 +1,6 @@
-use std::alloc;
 use std::alloc::Layout;
 use std::borrow::Cow;
-use std::slice;
+use std::{alloc, slice};
 
 use rustc_middle::mir::interpret::AllocBytes;
 use rustc_target::abi::{Align, Size};
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 14f43f576d3..8d3ae97e0e9 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -28,31 +28,27 @@ use std::num::NonZero;
 use std::path::PathBuf;
 use std::str::FromStr;
 
-use tracing::debug;
-
+use miri::{BacktraceStyle, BorrowTrackerMethod, ProvenanceMode, RetagFields, ValidationMode};
 use rustc_data_structures::sync::Lrc;
 use rustc_driver::Compilation;
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_hir::{self as hir, Node};
 use rustc_hir_analysis::check::check_function_signature;
 use rustc_interface::interface::Config;
-use rustc_middle::{
-    middle::{
-        codegen_fn_attrs::CodegenFnAttrFlags,
-        exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel},
-    },
-    query::LocalCrate,
-    traits::{ObligationCause, ObligationCauseCode},
-    ty::{self, Ty, TyCtxt},
-    util::Providers,
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::middle::exported_symbols::{
+    ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel,
 };
+use rustc_middle::query::LocalCrate;
+use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::util::Providers;
 use rustc_session::config::{CrateType, EntryFnType, ErrorOutputType, OptLevel};
 use rustc_session::search_paths::PathKind;
 use rustc_session::{CtfeBacktrace, EarlyDiagCtxt};
 use rustc_span::def_id::DefId;
 use rustc_target::spec::abi::Abi;
-
-use miri::{BacktraceStyle, BorrowTrackerMethod, ProvenanceMode, RetagFields, ValidationMode};
+use tracing::debug;
 
 struct MiriCompilerCalls {
     miri_config: miri::MiriConfig,
diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs
index 9e205cd0064..5204558f98c 100644
--- a/src/tools/miri/src/borrow_tracker/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/mod.rs
@@ -2,11 +2,10 @@ use std::cell::RefCell;
 use std::fmt;
 use std::num::NonZero;
 
-use smallvec::SmallVec;
-
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_middle::mir::RetagKind;
 use rustc_target::abi::Size;
+use smallvec::SmallVec;
 
 use crate::*;
 pub mod stacked_borrows;
@@ -323,7 +322,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match method {
             BorrowTrackerMethod::StackedBorrows => {
                 this.tcx.tcx.dcx().warn("Stacked Borrows does not support named pointers; `miri_pointer_name` is a no-op");
-                Ok(())
+                interp_ok(())
             }
             BorrowTrackerMethod::TreeBorrows =>
                 this.tb_give_pointer_debug_name(ptr, nth_parent, name),
@@ -334,7 +333,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         let Some(borrow_tracker) = &this.machine.borrow_tracker else {
             eprintln!("attempted to print borrow state, but no borrow state is being tracked");
-            return Ok(());
+            return interp_ok(());
         };
         let method = borrow_tracker.borrow().borrow_tracker_method;
         match method {
@@ -377,7 +376,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
         }
         borrow_tracker.borrow_mut().end_call(&frame.extra);
-        Ok(())
+        interp_ok(())
     }
 }
 
@@ -490,7 +489,7 @@ impl AllocState {
         alloc_id: AllocId, // diagnostics
     ) -> InterpResult<'tcx> {
         match self {
-            AllocState::StackedBorrows(_sb) => Ok(()),
+            AllocState::StackedBorrows(_sb) => interp_ok(()),
             AllocState::TreeBorrows(tb) =>
                 tb.borrow_mut().release_protector(machine, global, tag, alloc_id),
         }
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
index 12eeaae0eff..146f9902f6f 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
@@ -1,9 +1,9 @@
-use smallvec::SmallVec;
 use std::fmt;
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_span::{Span, SpanData};
 use rustc_target::abi::Size;
+use smallvec::SmallVec;
 
 use crate::borrow_tracker::{GlobalStateInner, ProtectorKind};
 use crate::*;
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index f792e75ad08..fdc7a675fb7 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -6,25 +6,24 @@ mod item;
 mod stack;
 
 use std::cell::RefCell;
-use std::cmp;
 use std::fmt::Write;
-use std::mem;
+use std::{cmp, mem};
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::mir::{Mutability, RetagKind};
-use rustc_middle::ty::{self, Ty, layout::HasParamEnv};
+use rustc_middle::ty::layout::HasParamEnv;
+use rustc_middle::ty::{self, Ty};
 use rustc_target::abi::{Abi, Size};
 
-use crate::borrow_tracker::{
-    GlobalStateInner, ProtectorKind,
-    stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder},
-};
-use crate::concurrency::data_race::{NaReadType, NaWriteType};
-use crate::*;
-
 use self::diagnostics::{RetagCause, RetagInfo};
 pub use self::item::{Item, Permission};
 pub use self::stack::Stack;
+use crate::borrow_tracker::stacked_borrows::diagnostics::{
+    AllocHistory, DiagnosticCx, DiagnosticCxBuilder,
+};
+use crate::borrow_tracker::{GlobalStateInner, ProtectorKind};
+use crate::concurrency::data_race::{NaReadType, NaWriteType};
+use crate::*;
 
 pub type AllocState = Stacks;
 
@@ -171,7 +170,7 @@ impl NewPermission {
 ///     F2b: No `SharedReadWrite` or `Unique` will ever be added on top of our `SharedReadOnly`.
 /// F3: If an access happens with an `&` outside `UnsafeCell`,
 ///     it requires the `SharedReadOnly` to still be in the stack.
-
+///
 /// Core relation on `Permission` to define which accesses are allowed
 impl Permission {
     /// This defines for a given permission, whether it permits the given kind of access.
@@ -231,7 +230,7 @@ impl<'tcx> Stack {
         }
 
         if !item.protected() {
-            return Ok(());
+            return interp_ok(());
         }
 
         // We store tags twice, once in global.protected_tags and once in each call frame.
@@ -253,10 +252,10 @@ impl<'tcx> Stack {
             let allowed = matches!(cause, ItemInvalidationCause::Dealloc)
                 && matches!(protector_kind, ProtectorKind::WeakProtector);
             if !allowed {
-                return Err(dcx.protector_error(item, protector_kind).into());
+                return Err(dcx.protector_error(item, protector_kind)).into();
             }
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Test if a memory `access` using pointer tagged `tag` is granted.
@@ -296,7 +295,7 @@ impl<'tcx> Stack {
             self.pop_items_after(first_incompatible_idx, |item| {
                 Stack::item_invalidated(&item, global, dcx, ItemInvalidationCause::Conflict)?;
                 dcx.log_invalidation(item.tag());
-                Ok(())
+                interp_ok(())
             })?;
         } else {
             // On a read, *disable* all `Unique` above the granting item.  This ensures U2 for read accesses.
@@ -317,7 +316,7 @@ impl<'tcx> Stack {
             self.disable_uniques_starting_at(first_incompatible_idx, |item| {
                 Stack::item_invalidated(&item, global, dcx, ItemInvalidationCause::Conflict)?;
                 dcx.log_invalidation(item.tag());
-                Ok(())
+                interp_ok(())
             })?;
         }
 
@@ -346,7 +345,7 @@ impl<'tcx> Stack {
         }
 
         // Done.
-        Ok(())
+        interp_ok(())
     }
 
     /// Deallocate a location: Like a write access, but also there must be no
@@ -368,7 +367,7 @@ impl<'tcx> Stack {
             Stack::item_invalidated(&item, global, dcx, ItemInvalidationCause::Dealloc)?;
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     /// Derive a new pointer from one with the given tag.
@@ -419,7 +418,7 @@ impl<'tcx> Stack {
                     "reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown"
                 );
                 self.set_unknown_bottom(global.next_ptr_tag);
-                return Ok(());
+                return interp_ok(());
             };
 
             // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write
@@ -432,7 +431,7 @@ impl<'tcx> Stack {
         // Put the new item there.
         trace!("reborrow: adding item {:?}", new);
         self.insert(new_idx, new);
-        Ok(())
+        interp_ok(())
     }
 }
 // # Stacked Borrows Core End
@@ -492,7 +491,7 @@ impl<'tcx> Stacks {
             f(stack, &mut dcx, &mut self.exposed_tags)?;
             dcx_builder = dcx.unbuild();
         }
-        Ok(())
+        interp_ok(())
     }
 }
 
@@ -577,7 +576,7 @@ impl Stacks {
         self.for_each(alloc_range(Size::ZERO, size), dcx, |stack, dcx, exposed_tags| {
             stack.dealloc(tag, &state, dcx, exposed_tags)
         })?;
-        Ok(())
+        interp_ok(())
     }
 }
 
@@ -624,7 +623,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
             drop(global); // don't hold that reference any longer than we have to
 
             let Some((alloc_id, base_offset, orig_tag)) = loc else {
-                return Ok(())
+                return interp_ok(())
             };
 
             let (_size, _align, alloc_kind) = this.get_alloc_info(alloc_id);
@@ -656,7 +655,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
                     // No stacked borrows on these allocations.
                 }
             }
-            Ok(())
+            interp_ok(())
         };
 
         if size == Size::ZERO {
@@ -677,12 +676,12 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
             {
                 log_creation(this, Some((alloc_id, base_offset, orig_tag)))?;
                 // Still give it the new provenance, it got retagged after all.
-                return Ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }));
+                return interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }));
             } else {
                 // This pointer doesn't come with an AllocId. :shrug:
                 log_creation(this, None)?;
                 // Provenance unchanged.
-                return Ok(place.ptr().provenance);
+                return interp_ok(place.ptr().provenance);
             }
         }
 
@@ -801,12 +800,12 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
                             )?;
                         }
                     }
-                    Ok(())
+                    interp_ok(())
                 })?;
             }
         }
 
-        Ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }))
+        interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }))
     }
 
     fn sb_retag_place(
@@ -833,7 +832,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
                     *shown = true;
                     this.emit_diagnostic(NonHaltingDiagnostic::ExternTypeReborrow);
                 });
-                return Ok(place.clone());
+                return interp_ok(place.clone());
             }
         };
 
@@ -846,7 +845,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
         // Adjust place.
         // (If the closure gets called, that means the old provenance was `Some`, and hence the new
         // one must also be `Some`.)
-        Ok(place.clone().map_provenance(|_| new_prov.unwrap()))
+        interp_ok(place.clone().map_provenance(|_| new_prov.unwrap()))
     }
 
     /// Retags an individual pointer, returning the retagged version.
@@ -860,7 +859,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         let place = this.ref_to_mplace(val)?;
         let new_place = this.sb_retag_place(&place, new_perm, info)?;
-        Ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout))
+        interp_ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout))
     }
 }
 
@@ -918,7 +917,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     in_field: self.in_field,
                 })?;
                 self.ecx.write_immediate(*val, place)?;
-                Ok(())
+                interp_ok(())
             }
         }
         impl<'ecx, 'tcx> ValueVisitor<'tcx, MiriMachine<'tcx>> for RetagVisitor<'ecx, 'tcx> {
@@ -936,7 +935,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx);
                     self.retag_ptr_inplace(place, new_perm)?;
                 }
-                Ok(())
+                interp_ok(())
             }
 
             fn visit_value(&mut self, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> {
@@ -945,7 +944,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // This optimization is crucial for ZSTs, because they can contain way more fields
                 // than we can ever visit.
                 if place.layout.is_sized() && place.layout.size < self.ecx.pointer_size() {
-                    return Ok(());
+                    return interp_ok(());
                 }
 
                 // Check the type of this value to see what to do with it (retag, or recurse).
@@ -984,7 +983,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     }
                 }
 
-                Ok(())
+                interp_ok(())
             }
         }
     }
@@ -1029,7 +1028,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // No stacked borrows on these allocations.
             }
         }
-        Ok(())
+        interp_ok(())
     }
 
     fn print_stacks(&mut self, alloc_id: AllocId) -> InterpResult<'tcx> {
@@ -1047,6 +1046,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             println!(" ]");
         }
-        Ok(())
+        interp_ok(())
     }
 }
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
index 5c040983142..f024796c0a7 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
@@ -4,11 +4,9 @@ use std::ops::Range;
 use rustc_data_structures::fx::FxHashSet;
 use tracing::trace;
 
-use crate::ProvenanceExtra;
-use crate::borrow_tracker::{
-    AccessKind, BorTag,
-    stacked_borrows::{Item, Permission},
-};
+use crate::borrow_tracker::stacked_borrows::{Item, Permission};
+use crate::borrow_tracker::{AccessKind, BorTag};
+use crate::{InterpResult, ProvenanceExtra, interp_ok};
 
 /// Exactly what cache size we should use is a difficult trade-off. There will always be some
 /// workload which has a `BorTag` working set which exceeds the size of the cache, and ends up
@@ -382,8 +380,8 @@ impl<'tcx> Stack {
     pub fn disable_uniques_starting_at(
         &mut self,
         disable_start: usize,
-        mut visitor: impl FnMut(Item) -> crate::InterpResult<'tcx>,
-    ) -> crate::InterpResult<'tcx> {
+        mut visitor: impl FnMut(Item) -> InterpResult<'tcx>,
+    ) -> InterpResult<'tcx> {
         #[cfg(feature = "stack-cache")]
         let unique_range = self.unique_range.clone();
         #[cfg(not(feature = "stack-cache"))]
@@ -422,16 +420,16 @@ impl<'tcx> Stack {
         #[cfg(feature = "stack-cache-consistency-check")]
         self.verify_cache_consistency();
 
-        Ok(())
+        interp_ok(())
     }
 
     /// Produces an iterator which iterates over `range` in reverse, and when dropped removes that
     /// range of `Item`s from this `Stack`.
-    pub fn pop_items_after<V: FnMut(Item) -> crate::InterpResult<'tcx>>(
+    pub fn pop_items_after<V: FnMut(Item) -> InterpResult<'tcx>>(
         &mut self,
         start: usize,
         mut visitor: V,
-    ) -> crate::InterpResult<'tcx> {
+    ) -> InterpResult<'tcx> {
         while self.borrows.len() > start {
             let item = self.borrows.pop().unwrap();
             visitor(item)?;
@@ -476,6 +474,6 @@ impl<'tcx> Stack {
 
         #[cfg(feature = "stack-cache-consistency-check")]
         self.verify_cache_consistency();
-        Ok(())
+        interp_ok(())
     }
 }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
index 44ea7533b00..cb840f19e3b 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
@@ -5,11 +5,9 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_span::{Span, SpanData};
 
 use crate::borrow_tracker::ProtectorKind;
-use crate::borrow_tracker::tree_borrows::{
-    perms::{PermTransition, Permission},
-    tree::LocationState,
-    unimap::UniIndex,
-};
+use crate::borrow_tracker::tree_borrows::perms::{PermTransition, Permission};
+use crate::borrow_tracker::tree_borrows::tree::LocationState;
+use crate::borrow_tracker::tree_borrows::unimap::UniIndex;
 use crate::*;
 
 /// Cause of an access: either a real access or one
@@ -228,7 +226,7 @@ impl<'tcx> Tree {
         } else {
             eprintln!("Tag {tag:?} (to be named '{name}') not found!");
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Debug helper: determines if the tree contains a tag.
@@ -800,6 +798,6 @@ impl<'tcx> Tree {
                 /* print warning message about tags not shown */ !show_unnamed,
             );
         }
-        Ok(())
+        interp_ok(())
     }
 }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index 2afe02dc2c7..acfb76030f5 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -1,15 +1,12 @@
-use rustc_middle::{
-    mir::{Mutability, RetagKind},
-    ty::{self, Ty, layout::HasParamEnv},
-};
+use rustc_middle::mir::{Mutability, RetagKind};
+use rustc_middle::ty::layout::HasParamEnv;
+use rustc_middle::ty::{self, Ty};
 use rustc_span::def_id::DefId;
 use rustc_target::abi::{Abi, Size};
 
+use crate::borrow_tracker::{GlobalState, GlobalStateInner, ProtectorKind};
+use crate::concurrency::data_race::NaReadType;
 use crate::*;
-use crate::{
-    borrow_tracker::{GlobalState, GlobalStateInner, ProtectorKind},
-    concurrency::data_race::NaReadType,
-};
 
 pub mod diagnostics;
 mod perms;
@@ -59,7 +56,7 @@ impl<'tcx> Tree {
         // handle them as much as we can.
         let tag = match prov {
             ProvenanceExtra::Concrete(tag) => tag,
-            ProvenanceExtra::Wildcard => return Ok(()),
+            ProvenanceExtra::Wildcard => return interp_ok(()),
         };
         let global = machine.borrow_tracker.as_ref().unwrap();
         let span = machine.current_span();
@@ -84,7 +81,7 @@ impl<'tcx> Tree {
         // handle them as much as we can.
         let tag = match prov {
             ProvenanceExtra::Concrete(tag) => tag,
-            ProvenanceExtra::Wildcard => return Ok(()),
+            ProvenanceExtra::Wildcard => return interp_ok(()),
         };
         let global = machine.borrow_tracker.as_ref().unwrap();
         let span = machine.current_span();
@@ -216,7 +213,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 ));
             }
             drop(global); // don't hold that reference any longer than we have to
-            Ok(())
+            interp_ok(())
         };
 
         trace!("Reborrow of size {:?}", ptr_size);
@@ -238,13 +235,13 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 );
                 log_creation(this, None)?;
                 // Keep original provenance.
-                return Ok(place.ptr().provenance);
+                return interp_ok(place.ptr().provenance);
             }
         };
         log_creation(this, Some((alloc_id, base_offset, parent_prov)))?;
 
         let orig_tag = match parent_prov {
-            ProvenanceExtra::Wildcard => return Ok(place.ptr().provenance), // TODO: handle wildcard pointers
+            ProvenanceExtra::Wildcard => return interp_ok(place.ptr().provenance), // TODO: handle wildcard pointers
             ProvenanceExtra::Concrete(tag) => tag,
         };
 
@@ -282,7 +279,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             assert_eq!(ptr_size, Size::ZERO); // we did the deref check above, size has to be 0 here
             // There's not actually any bytes here where accesses could even be tracked.
             // Just produce the new provenance, nothing else to do.
-            return Ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }));
+            return interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }));
         }
 
         let span = this.machine.current_span();
@@ -315,7 +312,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
         }
 
-        Ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }))
+        interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }))
     }
 
     fn tb_retag_place(
@@ -353,7 +350,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Adjust place.
         // (If the closure gets called, that means the old provenance was `Some`, and hence the new
         // one must also be `Some`.)
-        Ok(place.clone().map_provenance(|_| new_prov.unwrap()))
+        interp_ok(place.clone().map_provenance(|_| new_prov.unwrap()))
     }
 
     /// Retags an individual pointer, returning the retagged version.
@@ -365,7 +362,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         let place = this.ref_to_mplace(val)?;
         let new_place = this.tb_retag_place(&place, new_perm)?;
-        Ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout))
+        interp_ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout))
     }
 }
 
@@ -387,7 +384,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let Some(new_perm) = new_perm {
             this.tb_retag_reference(val, new_perm)
         } else {
-            Ok(val.clone())
+            interp_ok(val.clone())
         }
     }
 
@@ -424,7 +421,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     let val = self.ecx.tb_retag_reference(&val, new_perm)?;
                     self.ecx.write_immediate(*val, place)?;
                 }
-                Ok(())
+                interp_ok(())
             }
         }
         impl<'ecx, 'tcx> ValueVisitor<'tcx, MiriMachine<'tcx>> for RetagVisitor<'ecx, 'tcx> {
@@ -449,7 +446,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     );
                     self.retag_ptr_inplace(place, new_perm)?;
                 }
-                Ok(())
+                interp_ok(())
             }
 
             fn visit_value(&mut self, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> {
@@ -458,7 +455,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // This optimization is crucial for ZSTs, because they can contain way more fields
                 // than we can ever visit.
                 if place.layout.is_sized() && place.layout.size < self.ecx.pointer_size() {
-                    return Ok(());
+                    return interp_ok(());
                 }
 
                 // Check the type of this value to see what to do with it (retag, or recurse).
@@ -506,7 +503,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         }
                     }
                 }
-                Ok(())
+                interp_ok(())
             }
         }
     }
@@ -552,7 +549,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // No tree borrows on these allocations.
             }
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Display the tree.
@@ -578,7 +575,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Some(Provenance::Concrete { tag, alloc_id }) => (tag, alloc_id),
             _ => {
                 eprintln!("Can't give the name {name} to Wildcard pointer");
-                return Ok(());
+                return interp_ok(());
             }
         };
         let alloc_extra = this.get_alloc_extra(alloc_id)?;
@@ -608,5 +605,5 @@ fn inner_ptr_of_unique<'tcx>(
     assert_eq!(nonnull.layout.fields.count(), 1, "NonNull must have exactly 1 field");
     let ptr = ecx.project_field(&nonnull, 0)?;
     // Finally a plain `*mut`
-    Ok(ptr)
+    interp_ok(ptr)
 }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
index a99c71d96b4..15cefab1a68 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
@@ -12,18 +12,17 @@
 
 use std::{fmt, mem};
 
-use smallvec::SmallVec;
-
 use rustc_data_structures::fx::FxHashSet;
 use rustc_span::Span;
 use rustc_target::abi::Size;
+use smallvec::SmallVec;
 
-use crate::borrow_tracker::tree_borrows::{
-    Permission,
-    diagnostics::{self, NodeDebugInfo, TbError, TransitionError},
-    perms::PermTransition,
-    unimap::{UniEntry, UniIndex, UniKeyMap, UniValMap},
+use crate::borrow_tracker::tree_borrows::Permission;
+use crate::borrow_tracker::tree_borrows::diagnostics::{
+    self, NodeDebugInfo, TbError, TransitionError,
 };
+use crate::borrow_tracker::tree_borrows::perms::PermTransition;
+use crate::borrow_tracker::tree_borrows::unimap::{UniEntry, UniIndex, UniKeyMap, UniValMap};
 use crate::borrow_tracker::{GlobalState, ProtectorKind};
 use crate::*;
 
@@ -638,7 +637,7 @@ impl<'tcx> Tree {
         {
             perms.insert(idx, perm);
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Deallocation requires
@@ -689,7 +688,7 @@ impl<'tcx> Tree {
                     },
                 )?;
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Map the per-node and per-location `LocationState::perform_access`
@@ -828,7 +827,7 @@ impl<'tcx> Tree {
                 }
             }
         }
-        Ok(())
+        interp_ok(())
     }
 }
 
@@ -860,14 +859,15 @@ impl Tree {
     ) -> Option<UniIndex> {
         let node = self.nodes.get(idx).unwrap();
 
+        let [child_idx] = node.children[..] else { return None };
+
         // We never want to replace the root node, as it is also kept in `root_ptr_tags`.
-        if node.children.len() != 1 || live.contains(&node.tag) || node.parent.is_none() {
+        if live.contains(&node.tag) || node.parent.is_none() {
             return None;
         }
         // Since protected nodes are never GC'd (see `borrow_tracker::FrameExtra::visit_provenance`),
         // we know that `node` is not protected because otherwise `live` would
         // have contained `node.tag`.
-        let child_idx = node.children[0];
         let child = self.nodes.get(child_idx).unwrap();
         // Check that for that one child, `can_be_replaced_by_child` holds for the permission
         // on all locations.
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
index 5cd5040f807..5d51a72852c 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
@@ -1,9 +1,10 @@
 //! Tests for the tree
 #![cfg(test)]
 
+use std::fmt;
+
 use super::*;
 use crate::borrow_tracker::tree_borrows::exhaustive::{Exhaustive, precondition};
-use std::fmt;
 
 impl Exhaustive for LocationState {
     fn exhaustive() -> Box<dyn Iterator<Item = Self>> {
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
index cbc25724cb6..7874721c0ac 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
@@ -12,7 +12,8 @@
 
 #![allow(dead_code)]
 
-use std::{hash::Hash, mem};
+use std::hash::Hash;
+use std::mem;
 
 use rustc_data_structures::fx::FxHashMap;
 
diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs
index b5b43f589f6..82c4f6d3007 100644
--- a/src/tools/miri/src/concurrency/data_race.rs
+++ b/src/tools/miri/src/concurrency/data_race.rs
@@ -40,28 +40,23 @@
 //! code some atomic operations may increment the timestamp when not necessary but this has no effect
 //! on the data-race detection code.
 
-use std::{
-    cell::{Cell, Ref, RefCell, RefMut},
-    fmt::Debug,
-    mem,
-};
+use std::cell::{Cell, Ref, RefCell, RefMut};
+use std::fmt::Debug;
+use std::mem;
 
 use rustc_ast::Mutability;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_index::{Idx, IndexVec};
-use rustc_middle::{mir, ty::Ty};
+use rustc_middle::mir;
+use rustc_middle::ty::Ty;
 use rustc_span::Span;
 use rustc_target::abi::{Align, HasDataLayout, Size};
 
+use super::vector_clock::{VClock, VTimestamp, VectorIdx};
+use super::weak_memory::EvalContextExt as _;
 use crate::diagnostics::RacingOp;
 use crate::*;
 
-use super::{
-    vector_clock::{VClock, VTimestamp, VectorIdx},
-    weak_memory::EvalContextExt as _,
-};
-
 pub type AllocState = VClockAlloc;
 
 /// Valid atomic read-write orderings, alias of atomic::Ordering (not non-exhaustive).
@@ -191,7 +186,8 @@ struct AtomicMemoryCellClocks {
     /// The size of accesses to this atomic location.
     /// We use this to detect non-synchronized mixed-size accesses. Since all accesses must be
     /// aligned to their size, this is sufficient to detect imperfectly overlapping accesses.
-    size: Size,
+    /// `None` indicates that we saw multiple different sizes, which is okay as long as all accesses are reads.
+    size: Option<Size>,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -265,6 +261,14 @@ impl AccessType {
         let mut msg = String::new();
 
         if let Some(size) = size {
+            if size == Size::ZERO {
+                // In this case there were multiple read accesss with different sizes and then a write.
+                // We will be reporting *one* of the other reads, but we don't have enough information
+                // to determine which one had which size.
+                assert!(self == AccessType::AtomicLoad);
+                assert!(ty.is_none());
+                return format!("multiple differently-sized atomic loads, including one load");
+            }
             msg.push_str(&format!("{}-byte {}", size.bytes(), msg))
         }
 
@@ -305,8 +309,7 @@ impl AccessType {
     }
 }
 
-/// Memory Cell vector clock metadata
-/// for data-race detection.
+/// Per-byte vector clock metadata for data-race detection.
 #[derive(Clone, PartialEq, Eq, Debug)]
 struct MemoryCellClocks {
     /// The vector-clock timestamp and the thread that did the last non-atomic write. We don't need
@@ -325,8 +328,8 @@ struct MemoryCellClocks {
     read: VClock,
 
     /// Atomic access, acquire, release sequence tracking clocks.
-    /// For non-atomic memory in the common case this
-    /// value is set to None.
+    /// For non-atomic memory this value is set to None.
+    /// For atomic memory, each byte carries this information.
     atomic_ops: Option<Box<AtomicMemoryCellClocks>>,
 }
 
@@ -336,7 +339,7 @@ impl AtomicMemoryCellClocks {
             read_vector: Default::default(),
             write_vector: Default::default(),
             sync_vector: Default::default(),
-            size,
+            size: Some(size),
         }
     }
 }
@@ -383,17 +386,23 @@ impl MemoryCellClocks {
         &mut self,
         thread_clocks: &ThreadClockSet,
         size: Size,
+        write: bool,
     ) -> Result<&mut AtomicMemoryCellClocks, DataRace> {
         match self.atomic_ops {
             Some(ref mut atomic) => {
                 // We are good if the size is the same or all atomic accesses are before our current time.
-                if atomic.size == size {
+                if atomic.size == Some(size) {
                     Ok(atomic)
                 } else if atomic.read_vector <= thread_clocks.clock
                     && atomic.write_vector <= thread_clocks.clock
                 {
-                    // This is now the new size that must be used for accesses here.
-                    atomic.size = size;
+                    // We are fully ordered after all previous accesses, so we can change the size.
+                    atomic.size = Some(size);
+                    Ok(atomic)
+                } else if !write && atomic.write_vector <= thread_clocks.clock {
+                    // This is a read, and it is ordered after the last write. It's okay for the
+                    // sizes to mismatch, as long as no writes with a different size occur later.
+                    atomic.size = None;
                     Ok(atomic)
                 } else {
                     Err(DataRace)
@@ -499,7 +508,7 @@ impl MemoryCellClocks {
         Ok(())
     }
 
-    /// Detect data-races with an atomic read, caused by a non-atomic access that does
+    /// Detect data-races with an atomic read, caused by a non-atomic write that does
     /// not happen-before the atomic-read.
     fn atomic_read_detect(
         &mut self,
@@ -508,14 +517,10 @@ impl MemoryCellClocks {
         access_size: Size,
     ) -> Result<(), DataRace> {
         trace!("Atomic read with vectors: {:#?} :: {:#?}", self, thread_clocks);
-        let atomic = self.atomic_access(thread_clocks, access_size)?;
+        let atomic = self.atomic_access(thread_clocks, access_size, /*write*/ false)?;
         atomic.read_vector.set_at_index(&thread_clocks.clock, index);
-        // Make sure the last non-atomic write and all non-atomic reads were before this access.
-        if self.write_was_before(&thread_clocks.clock) && self.read <= thread_clocks.clock {
-            Ok(())
-        } else {
-            Err(DataRace)
-        }
+        // Make sure the last non-atomic write was before this access.
+        if self.write_was_before(&thread_clocks.clock) { Ok(()) } else { Err(DataRace) }
     }
 
     /// Detect data-races with an atomic write, either with a non-atomic read or with
@@ -527,7 +532,7 @@ impl MemoryCellClocks {
         access_size: Size,
     ) -> Result<(), DataRace> {
         trace!("Atomic write with vectors: {:#?} :: {:#?}", self, thread_clocks);
-        let atomic = self.atomic_access(thread_clocks, access_size)?;
+        let atomic = self.atomic_access(thread_clocks, access_size, /*write*/ true)?;
         atomic.write_vector.set_at_index(&thread_clocks.clock, index);
         // Make sure the last non-atomic write and all non-atomic reads were before this access.
         if self.write_was_before(&thread_clocks.clock) && self.read <= thread_clocks.clock {
@@ -552,11 +557,9 @@ impl MemoryCellClocks {
         }
         thread_clocks.clock.index_mut(index).set_read_type(read_type);
         if self.write_was_before(&thread_clocks.clock) {
+            // We must be ordered-after all atomic writes.
             let race_free = if let Some(atomic) = self.atomic() {
-                // We must be ordered-after all atomic accesses, reads and writes.
-                // This ensures we don't mix atomic and non-atomic accesses.
                 atomic.write_vector <= thread_clocks.clock
-                    && atomic.read_vector <= thread_clocks.clock
             } else {
                 true
             };
@@ -621,7 +624,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
         let buffered_scalar = this.buffered_atomic_read(place, atomic, scalar, || {
             this.validate_atomic_load(place, atomic)
         })?;
-        Ok(buffered_scalar.ok_or_else(|| err_ub!(InvalidUninitBytes(None)))?)
+        interp_ok(buffered_scalar.ok_or_else(|| err_ub!(InvalidUninitBytes(None)))?)
     }
 
     /// Perform an atomic write operation at the memory location.
@@ -638,7 +641,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
         // The program didn't actually do a read, so suppress the memory access hooks.
         // This is also a very special exception where we just ignore an error -- if this read
         // was UB e.g. because the memory is uninitialized, we don't want to know!
-        let old_val = this.run_for_validation(|this| this.read_scalar(dest)).ok();
+        let old_val = this.run_for_validation(|this| this.read_scalar(dest)).discard_err();
         this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?;
         this.validate_atomic_store(dest, atomic)?;
         this.buffered_atomic_write(val, dest, atomic, old_val)
@@ -665,7 +668,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
         this.validate_atomic_rmw(place, atomic)?;
 
         this.buffered_atomic_rmw(val.to_scalar(), place, atomic, old.to_scalar())?;
-        Ok(old)
+        interp_ok(old)
     }
 
     /// Perform an atomic exchange with a memory place and a new
@@ -685,7 +688,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
         this.validate_atomic_rmw(place, atomic)?;
 
         this.buffered_atomic_rmw(new, place, atomic, old)?;
-        Ok(old)
+        interp_ok(old)
     }
 
     /// Perform an conditional atomic exchange with a memory place and a new
@@ -717,7 +720,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
         this.buffered_atomic_rmw(new_val.to_scalar(), place, atomic, old.to_scalar())?;
 
         // Return the old value.
-        Ok(old)
+        interp_ok(old)
     }
 
     /// Perform an atomic compare and exchange at a given memory location.
@@ -774,7 +777,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
         }
 
         // Return the old value.
-        Ok(res)
+        interp_ok(res)
     }
 
     /// Update the data-race detector for an atomic fence on the current thread.
@@ -806,11 +809,11 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
                     }
 
                     // Increment timestamp in case of release semantics.
-                    Ok(atomic != AtomicFenceOrd::Acquire)
+                    interp_ok(atomic != AtomicFenceOrd::Acquire)
                 },
             )
         } else {
-            Ok(())
+            interp_ok(())
         }
     }
 
@@ -957,9 +960,7 @@ impl VClockAlloc {
         let mut other_size = None; // if `Some`, this was a size-mismatch race
         let write_clock;
         let (other_access, other_thread, other_clock) =
-            // First check the atomic-nonatomic cases. If it looks like multiple
-            // cases apply, this one should take precedence, else it might look like
-            // we are reporting races between two non-atomic reads.
+            // First check the atomic-nonatomic cases.
             if !access.is_atomic() &&
                 let Some(atomic) = mem_clocks.atomic() &&
                 let Some(idx) = Self::find_gt_index(&atomic.write_vector, &active_clocks.clock)
@@ -977,10 +978,10 @@ impl VClockAlloc {
             } else if let Some(idx) = Self::find_gt_index(&mem_clocks.read, &active_clocks.clock) {
                 (AccessType::NaRead(mem_clocks.read[idx].read_type()), idx, &mem_clocks.read)
             // Finally, mixed-size races.
-            } else if access.is_atomic() && let Some(atomic) = mem_clocks.atomic() && atomic.size != access_size {
+            } else if access.is_atomic() && let Some(atomic) = mem_clocks.atomic() && atomic.size != Some(access_size) {
                 // This is only a race if we are not synchronized with all atomic accesses, so find
                 // the one we are not synchronized with.
-                other_size = Some(atomic.size);
+                other_size = Some(atomic.size.unwrap_or(Size::ZERO));
                 if let Some(idx) = Self::find_gt_index(&atomic.write_vector, &active_clocks.clock)
                     {
                         (AccessType::AtomicStore, idx, &atomic.write_vector)
@@ -1007,10 +1008,7 @@ impl VClockAlloc {
             assert!(!involves_non_atomic);
             Some("overlapping unsynchronized atomic accesses must use the same access size")
         } else if access.is_read() && other_access.is_read() {
-            assert!(involves_non_atomic);
-            Some(
-                "overlapping atomic and non-atomic accesses must be synchronized, even if both are read-only",
-            )
+            panic!("there should be no same-size read-read races")
         } else {
             None
         };
@@ -1049,7 +1047,7 @@ impl VClockAlloc {
         let current_span = machine.current_span();
         let global = machine.data_race.as_ref().unwrap();
         if !global.race_detecting() {
-            return Ok(());
+            return interp_ok(());
         }
         let (index, mut thread_clocks) = global.active_thread_state_mut(&machine.threads);
         let mut alloc_ranges = self.alloc_ranges.borrow_mut();
@@ -1072,7 +1070,7 @@ impl VClockAlloc {
                 );
             }
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Detect data-races for an unsynchronized write operation. It will not perform
@@ -1091,7 +1089,7 @@ impl VClockAlloc {
         let current_span = machine.current_span();
         let global = machine.data_race.as_mut().unwrap();
         if !global.race_detecting() {
-            return Ok(());
+            return interp_ok(());
         }
         let (index, mut thread_clocks) = global.active_thread_state_mut(&machine.threads);
         for (mem_clocks_range, mem_clocks) in
@@ -1113,7 +1111,7 @@ impl VClockAlloc {
                 );
             }
         }
-        Ok(())
+        interp_ok(())
     }
 }
 
@@ -1309,7 +1307,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
                 }
             }
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Update the data-race detector for an atomic read occurring at the
@@ -1401,9 +1399,9 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_ref();
         assert!(access.is_atomic());
-        let Some(data_race) = &this.machine.data_race else { return Ok(()) };
+        let Some(data_race) = &this.machine.data_race else { return interp_ok(()) };
         if !data_race.race_detecting() {
-            return Ok(());
+            return interp_ok(());
         }
         let size = place.layout.size;
         let (alloc_id, base_offset, _prov) = this.ptr_get_alloc_id(place.ptr(), 0)?;
@@ -1446,7 +1444,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
                 }
 
                 // This conservatively assumes all operations have release semantics
-                Ok(true)
+                interp_ok(true)
             },
         )?;
 
@@ -1462,7 +1460,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
             }
         }
 
-        Ok(())
+        interp_ok(())
     }
 }
 
@@ -1759,7 +1757,7 @@ impl GlobalState {
                 clocks.increment_clock(index, current_span);
             }
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Internal utility to identify a thread stored internally
diff --git a/src/tools/miri/src/concurrency/init_once.rs b/src/tools/miri/src/concurrency/init_once.rs
index 9c2c6ae1330..7a9b12bbe82 100644
--- a/src/tools/miri/src/concurrency/init_once.rs
+++ b/src/tools/miri/src/concurrency/init_once.rs
@@ -37,9 +37,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             lock,
             offset,
             |ecx| &mut ecx.machine.sync.init_onces,
-            |_| Ok(Default::default()),
+            |_| interp_ok(Default::default()),
         )?
-        .ok_or_else(|| err_ub_format!("init_once has invalid ID").into())
+        .ok_or_else(|| err_ub_format!("init_once has invalid ID"))
+        .into()
     }
 
     #[inline]
@@ -101,7 +102,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.unblock_thread(waiter, BlockReason::InitOnce(id))?;
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     #[inline]
@@ -126,7 +127,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.unblock_thread(waiter, BlockReason::InitOnce(id))?;
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     /// Synchronize with the previous completion of an InitOnce.
diff --git a/src/tools/miri/src/concurrency/range_object_map.rs b/src/tools/miri/src/concurrency/range_object_map.rs
index 859eb4bbb60..d36ed36ac1a 100644
--- a/src/tools/miri/src/concurrency/range_object_map.rs
+++ b/src/tools/miri/src/concurrency/range_object_map.rs
@@ -2,10 +2,10 @@
 //! ranges and data are discrete and non-splittable -- they represent distinct "objects". An
 //! allocation in the map will always have the same range until explicitly removed
 
-use rustc_target::abi::Size;
 use std::ops::{Index, IndexMut, Range};
 
 use rustc_const_eval::interpret::AllocRange;
+use rustc_target::abi::Size;
 
 #[derive(Clone, Debug)]
 struct Elem<T> {
diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs
index bc4d8056872..5627ccdbbea 100644
--- a/src/tools/miri/src/concurrency/sync.rs
+++ b/src/tools/miri/src/concurrency/sync.rs
@@ -1,5 +1,6 @@
 use std::any::Any;
-use std::collections::{VecDeque, hash_map::Entry};
+use std::collections::VecDeque;
+use std::collections::hash_map::Entry;
 use std::ops::Not;
 use std::time::Duration;
 
@@ -205,7 +206,7 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             )?
             .to_scalar_pair();
 
-        Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") {
+        interp_ok(if success.to_bool().expect("compare_exchange's second return value is a bool") {
             // We set the in-memory ID to `next_index`, now also create this object in the machine
             // state.
             let obj = create_obj(this)?;
@@ -246,7 +247,7 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let new_index = get_objs(this).push(obj);
         this.write_scalar(Scalar::from_u32(new_index.to_u32()), &id_place)?;
-        Ok(new_index)
+        interp_ok(new_index)
     }
 
     fn condvar_reacquire_mutex(
@@ -265,7 +266,7 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Don't forget to write the return value.
             this.write_scalar(retval, &dest)?;
         }
-        Ok(())
+        interp_ok(())
     }
 }
 
@@ -306,7 +307,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             |ecx| &mut ecx.machine.sync.mutexes,
             |ecx| initialize_data(ecx).map(|data| Mutex { data, ..Default::default() }),
         )?
-        .ok_or_else(|| err_ub_format!("mutex has invalid ID").into())
+        .ok_or_else(|| err_ub_format!("mutex has invalid ID"))
+        .into()
     }
 
     /// Retrieve the additional data stored for a mutex.
@@ -333,7 +335,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             |ecx| &mut ecx.machine.sync.rwlocks,
             |ecx| initialize_data(ecx).map(|data| RwLock { data, ..Default::default() }),
         )?
-        .ok_or_else(|| err_ub_format!("rwlock has invalid ID").into())
+        .ok_or_else(|| err_ub_format!("rwlock has invalid ID"))
+        .into()
     }
 
     /// Retrieve the additional data stored for a rwlock.
@@ -374,7 +377,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             |ecx| &mut ecx.machine.sync.condvars,
             |ecx| initialize_data(ecx).map(|data| Condvar { data, ..Default::default() }),
         )?
-        .ok_or_else(|| err_ub_format!("condvar has invalid ID").into())
+        .ok_or_else(|| err_ub_format!("condvar has invalid ID"))
+        .into()
     }
 
     /// Retrieve the additional data stored for a condvar.
@@ -427,11 +431,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn mutex_unlock(&mut self, id: MutexId) -> InterpResult<'tcx, Option<usize>> {
         let this = self.eval_context_mut();
         let mutex = &mut this.machine.sync.mutexes[id];
-        Ok(if let Some(current_owner) = mutex.owner {
+        interp_ok(if let Some(current_owner) = mutex.owner {
             // Mutex is locked.
             if current_owner != this.machine.threads.active_thread() {
                 // Only the owner can unlock the mutex.
-                return Ok(None);
+                return interp_ok(None);
             }
             let old_lock_count = mutex.lock_count;
             mutex.lock_count = old_lock_count.strict_sub(1);
@@ -483,7 +487,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         this.write_scalar(retval, &dest)?;
                     }
 
-                    Ok(())
+                    interp_ok(())
                 }
             ),
         );
@@ -545,7 +549,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     trace!("rwlock_reader_unlock: {:?} held one less time by {:?}", id, thread);
                 }
             }
-            Entry::Vacant(_) => return Ok(false), // we did not even own this lock
+            Entry::Vacant(_) => return interp_ok(false), // we did not even own this lock
         }
         if let Some(data_race) = &this.machine.data_race {
             // Add this to the shared-release clock of all concurrent readers.
@@ -564,7 +568,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.unblock_thread(writer, BlockReason::RwLock(id))?;
             }
         }
-        Ok(true)
+        interp_ok(true)
     }
 
     /// Put the reader in the queue waiting for the lock and block it.
@@ -592,7 +596,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 @unblock = |this| {
                     this.rwlock_reader_lock(id);
                     this.write_scalar(retval, &dest)?;
-                    Ok(())
+                    interp_ok(())
                 }
             ),
         );
@@ -619,10 +623,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         let thread = this.active_thread();
         let rwlock = &mut this.machine.sync.rwlocks[id];
-        Ok(if let Some(current_writer) = rwlock.writer {
+        interp_ok(if let Some(current_writer) = rwlock.writer {
             if current_writer != thread {
                 // Only the owner can unlock the rwlock.
-                return Ok(false);
+                return interp_ok(false);
             }
             rwlock.writer = None;
             trace!("rwlock_writer_unlock: {:?} unlocked by {:?}", id, thread);
@@ -675,7 +679,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 @unblock = |this| {
                     this.rwlock_writer_lock(id);
                     this.write_scalar(retval, &dest)?;
-                    Ok(())
+                    interp_ok(())
                 }
             ),
         );
@@ -748,7 +752,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
             ),
         );
-        return Ok(());
+        interp_ok(())
     }
 
     /// Wake up some thread (if there is any) sleeping on the conditional
@@ -763,10 +767,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             condvar.clock.clone_from(&*data_race.release_clock(&this.machine.threads));
         }
         let Some(waiter) = condvar.waiters.pop_front() else {
-            return Ok(false);
+            return interp_ok(false);
         };
         this.unblock_thread(waiter, BlockReason::Condvar(id))?;
-        Ok(true)
+        interp_ok(true)
     }
 
     /// Wait for the futex to be signaled, or a timeout.
@@ -807,7 +811,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     }
                     // Write the return value.
                     this.write_scalar(retval_succ, &dest)?;
-                    Ok(())
+                    interp_ok(())
                 }
                 @timeout = |this| {
                     // Remove the waiter from the futex.
@@ -817,7 +821,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     // Set errno and write return value.
                     this.set_last_error(errno_timeout)?;
                     this.write_scalar(retval_timeout, &dest)?;
-                    Ok(())
+                    interp_ok(())
                 }
             ),
         );
@@ -827,7 +831,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn futex_wake(&mut self, addr: u64, bitset: u32) -> InterpResult<'tcx, bool> {
         let this = self.eval_context_mut();
         let Some(futex) = this.machine.sync.futexes.get_mut(&addr) else {
-            return Ok(false);
+            return interp_ok(false);
         };
         let data_race = &this.machine.data_race;
 
@@ -838,10 +842,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // Wake up the first thread in the queue that matches any of the bits in the bitset.
         let Some(i) = futex.waiters.iter().position(|w| w.bitset & bitset != 0) else {
-            return Ok(false);
+            return interp_ok(false);
         };
         let waiter = futex.waiters.remove(i).unwrap();
         this.unblock_thread(waiter.thread, BlockReason::Futex { addr })?;
-        Ok(true)
+        interp_ok(true)
     }
 }
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 4efe2beb155..dcae85109a5 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -7,7 +7,6 @@ use std::task::Poll;
 use std::time::{Duration, SystemTime};
 
 use either::Either;
-
 use rustc_const_eval::CTRL_C_RECEIVED;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
@@ -623,7 +622,7 @@ impl<'tcx> ThreadManager<'tcx> {
         }
 
         self.threads[id].join_status = ThreadJoinStatus::Detached;
-        Ok(())
+        interp_ok(())
     }
 
     /// Mark that the active thread tries to join the thread with `joined_thread_id`.
@@ -658,7 +657,7 @@ impl<'tcx> ThreadManager<'tcx> {
                         if let Some(data_race) = &mut this.machine.data_race {
                             data_race.thread_joined(&this.machine.threads, joined_thread_id);
                         }
-                        Ok(())
+                        interp_ok(())
                     }
                 ),
             );
@@ -668,7 +667,7 @@ impl<'tcx> ThreadManager<'tcx> {
                 data_race.thread_joined(self, joined_thread_id);
             }
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Mark that the active thread tries to exclusively join the thread with `joined_thread_id`.
@@ -755,7 +754,7 @@ impl<'tcx> ThreadManager<'tcx> {
         // This thread and the program can keep going.
         if self.threads[self.active_thread].state.is_enabled() && !self.yield_active_thread {
             // The currently active thread is still enabled, just continue with it.
-            return Ok(SchedulingAction::ExecuteStep);
+            return interp_ok(SchedulingAction::ExecuteStep);
         }
         // The active thread yielded or got terminated. Let's see if there are any timeouts to take
         // care of. We do this *before* running any other thread, to ensure that timeouts "in the
@@ -765,7 +764,7 @@ impl<'tcx> ThreadManager<'tcx> {
         // <https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html>
         let potential_sleep_time = self.next_callback_wait_time(clock);
         if potential_sleep_time == Some(Duration::ZERO) {
-            return Ok(SchedulingAction::ExecuteTimeoutCallback);
+            return interp_ok(SchedulingAction::ExecuteTimeoutCallback);
         }
         // No callbacks immediately scheduled, pick a regular thread to execute.
         // The active thread blocked or yielded. So we go search for another enabled thread.
@@ -794,7 +793,7 @@ impl<'tcx> ThreadManager<'tcx> {
         }
         self.yield_active_thread = false;
         if self.threads[self.active_thread].state.is_enabled() {
-            return Ok(SchedulingAction::ExecuteStep);
+            return interp_ok(SchedulingAction::ExecuteStep);
         }
         // We have not found a thread to execute.
         if self.threads.iter().all(|thread| thread.state.is_terminated()) {
@@ -803,7 +802,7 @@ impl<'tcx> ThreadManager<'tcx> {
             // All threads are currently blocked, but we have unexecuted
             // timeout_callbacks, which may unblock some of the threads. Hence,
             // sleep until the first callback.
-            Ok(SchedulingAction::Sleep(sleep_time))
+            interp_ok(SchedulingAction::Sleep(sleep_time))
         } else {
             throw_machine_stop!(TerminationInfo::Deadlock);
         }
@@ -849,7 +848,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
         // https://github.com/rust-lang/miri/issues/1763). In this case,
         // just do nothing, which effectively just returns to the
         // scheduler.
-        return Ok(());
+        interp_ok(())
     }
 
     #[inline]
@@ -862,7 +861,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
             .expect("`on_stack_empty` not set up, or already running");
         let res = callback(this)?;
         this.active_thread_mut().on_stack_empty = Some(callback);
-        Ok(res)
+        interp_ok(res)
     }
 }
 
@@ -880,7 +879,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let Some(old_alloc) = this.machine.threads.get_thread_local_alloc_id(def_id) {
             // We already have a thread-specific allocation id for this
             // thread-local static.
-            Ok(old_alloc)
+            interp_ok(old_alloc)
         } else {
             // We need to allocate a thread-specific allocation id for this
             // thread-local static.
@@ -893,7 +892,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             let mut alloc = alloc.inner().adjust_from_tcx(
                 &this.tcx,
                 |bytes, align| {
-                    Ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align))
+                    interp_ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align))
                 },
                 |ptr| this.global_root_pointer(ptr),
             )?;
@@ -902,7 +901,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Create a fresh allocation with this content.
             let ptr = this.insert_allocation(alloc, MiriMemoryKind::Tls.into())?;
             this.machine.threads.set_thread_local_alloc(def_id, ptr);
-            Ok(ptr)
+            interp_ok(ptr)
         }
     }
 
@@ -965,7 +964,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Restore the old active thread frame.
         this.machine.threads.set_active_thread_id(old_thread_id);
 
-        Ok(new_thread_id)
+        interp_ok(new_thread_id)
     }
 
     /// Handles thread termination of the active thread: wakes up threads joining on this one,
@@ -1023,7 +1022,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.unblock_thread(thread, unblock_reason)?;
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     /// Block the current thread, with an optional timeout.
@@ -1079,7 +1078,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let old_thread = this.machine.threads.set_active_thread_id(thread);
         callback.unblock(this)?;
         this.machine.threads.set_active_thread_id(old_thread);
-        Ok(())
+        interp_ok(())
     }
 
     #[inline]
@@ -1096,7 +1095,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
         this.machine.threads.join_thread(joined_thread_id, this.machine.data_race.as_mut())?;
-        Ok(())
+        interp_ok(())
     }
 
     #[inline]
@@ -1105,7 +1104,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.machine
             .threads
             .join_thread_exclusive(joined_thread_id, this.machine.data_race.as_mut())?;
-        Ok(())
+        interp_ok(())
     }
 
     #[inline]
diff --git a/src/tools/miri/src/concurrency/vector_clock.rs b/src/tools/miri/src/concurrency/vector_clock.rs
index 901b097c1bd..34572663429 100644
--- a/src/tools/miri/src/concurrency/vector_clock.rs
+++ b/src/tools/miri/src/concurrency/vector_clock.rs
@@ -1,11 +1,10 @@
+use std::cmp::Ordering;
+use std::fmt::Debug;
+use std::ops::{Index, Shr};
+
 use rustc_index::Idx;
 use rustc_span::{DUMMY_SP, Span, SpanData};
 use smallvec::SmallVec;
-use std::{
-    cmp::Ordering,
-    fmt::Debug,
-    ops::{Index, Shr},
-};
 
 use super::data_race::NaReadType;
 
@@ -152,7 +151,7 @@ impl VClock {
     /// Load the internal timestamp slice in the vector clock
     #[inline]
     pub(super) fn as_slice(&self) -> &[VTimestamp] {
-        debug_assert!(!self.0.last().is_some_and(|t| t.time() == 0));
+        debug_assert!(self.0.last().is_none_or(|t| t.time() != 0));
         self.0.as_slice()
     }
 
@@ -430,10 +429,12 @@ impl Index<VectorIdx> for VClock {
 ///  test suite
 #[cfg(test)]
 mod tests {
+    use std::cmp::Ordering;
+
+    use rustc_span::DUMMY_SP;
+
     use super::{VClock, VTimestamp, VectorIdx};
     use crate::concurrency::data_race::NaReadType;
-    use rustc_span::DUMMY_SP;
-    use std::cmp::Ordering;
 
     #[test]
     fn test_equal() {
diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs
index 0605b744e6a..800c301a821 100644
--- a/src/tools/miri/src/concurrency/weak_memory.rs
+++ b/src/tools/miri/src/concurrency/weak_memory.rs
@@ -76,21 +76,16 @@
 // (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.cc#L295)
 // and here.
 
-use std::{
-    cell::{Ref, RefCell},
-    collections::VecDeque,
-};
+use std::cell::{Ref, RefCell};
+use std::collections::VecDeque;
 
 use rustc_data_structures::fx::FxHashMap;
 
+use super::data_race::{GlobalState as DataRaceState, ThreadClockSet};
+use super::range_object_map::{AccessType, RangeObjectMap};
+use super::vector_clock::{VClock, VTimestamp, VectorIdx};
 use crate::*;
 
-use super::{
-    data_race::{GlobalState as DataRaceState, ThreadClockSet},
-    range_object_map::{AccessType, RangeObjectMap},
-    vector_clock::{VClock, VTimestamp, VectorIdx},
-};
-
 pub type AllocState = StoreBufferAlloc;
 
 // Each store buffer must be bounded otherwise it will grow indefinitely.
@@ -200,10 +195,10 @@ impl StoreBufferAlloc {
             AccessType::PerfectlyOverlapping(pos) => pos,
             // If there is nothing here yet, that means there wasn't an atomic write yet so
             // we can't return anything outdated.
-            _ => return Ok(None),
+            _ => return interp_ok(None),
         };
         let store_buffer = Ref::map(self.store_buffers.borrow(), |buffer| &buffer[pos]);
-        Ok(Some(store_buffer))
+        interp_ok(Some(store_buffer))
     }
 
     /// Gets a mutable store buffer associated with an atomic object in this allocation,
@@ -228,7 +223,7 @@ impl StoreBufferAlloc {
                 pos_range.start
             }
         };
-        Ok(&mut buffers[pos])
+        interp_ok(&mut buffers[pos])
     }
 }
 
@@ -289,7 +284,7 @@ impl<'tcx> StoreBuffer {
 
         let (index, clocks) = global.active_thread_state(thread_mgr);
         let loaded = store_elem.load_impl(index, &clocks, is_seqcst);
-        Ok((loaded, recency))
+        interp_ok((loaded, recency))
     }
 
     fn buffered_write(
@@ -302,7 +297,7 @@ impl<'tcx> StoreBuffer {
         let (index, clocks) = global.active_thread_state(thread_mgr);
 
         self.store_impl(val, index, &clocks.clock, is_seqcst);
-        Ok(())
+        interp_ok(())
     }
 
     #[allow(clippy::if_same_then_else, clippy::needless_bool)]
@@ -475,7 +470,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             buffer.read_from_last_store(global, threads, atomic == AtomicRwOrd::SeqCst);
             buffer.buffered_write(new_val, global, threads, atomic == AtomicRwOrd::SeqCst)?;
         }
-        Ok(())
+        interp_ok(())
     }
 
     fn buffered_atomic_read(
@@ -513,14 +508,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         });
                     }
 
-                    return Ok(loaded);
+                    return interp_ok(loaded);
                 }
             }
         }
 
         // Race detector or weak memory disabled, simply read the latest value
         validate()?;
-        Ok(Some(latest_in_mo))
+        interp_ok(Some(latest_in_mo))
     }
 
     /// Add the given write to the store buffer. (Does not change machine memory.)
@@ -551,7 +546,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         }
 
         // Caller should've written to dest with the vanilla scalar write, we do nothing here
-        Ok(())
+        interp_ok(())
     }
 
     /// Caller should never need to consult the store buffer for the latest value.
@@ -575,7 +570,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     alloc_buffers.get_store_buffer(alloc_range(base_offset, size))?
                 else {
                     // No store buffer, nothing to do.
-                    return Ok(());
+                    return interp_ok(());
                 };
                 buffer.read_from_last_store(
                     global,
@@ -584,6 +579,6 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 );
             }
         }
-        Ok(())
+        interp_ok(())
     }
 }
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 4445550512b..5b1bad28c07 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -223,7 +223,7 @@ pub fn report_error<'tcx>(
         let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
         use TerminationInfo::*;
         let title = match info {
-            Exit { code, leak_check } => return Some((*code, *leak_check)),
+            &Exit { code, leak_check } => return Some((code, leak_check)),
             Abort(_) => Some("abnormal termination"),
             UnsupportedInIsolation(_) | Int2PtrWithStrictProvenance | UnsupportedForeignItem(_) =>
                 Some("unsupported operation"),
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 8c8ed9c4ddc..ece76e581f2 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -1,25 +1,21 @@
 //! Main evaluator loop and setting up the initial stack frame.
 
 use std::ffi::{OsStr, OsString};
-use std::iter;
 use std::panic::{self, AssertUnwindSafe};
 use std::path::PathBuf;
 use std::task::Poll;
-use std::thread;
+use std::{iter, thread};
 
-use crate::concurrency::thread::TlsAllocAction;
-use crate::diagnostics::report_leaks;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{
-    self, Ty, TyCtxt,
-    layout::{LayoutCx, LayoutOf},
-};
-use rustc_target::spec::abi::Abi;
-
+use rustc_middle::ty::layout::{LayoutCx, LayoutOf};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::config::EntryFnType;
+use rustc_target::spec::abi::Abi;
 
+use crate::concurrency::thread::TlsAllocAction;
+use crate::diagnostics::report_leaks;
 use crate::shims::tls;
 use crate::*;
 
@@ -263,7 +259,7 @@ impl<'tcx> MainThreadState<'tcx> {
                 throw_machine_stop!(TerminationInfo::Exit { code: exit_code, leak_check: true });
             }
         }
-        Ok(Poll::Pending)
+        interp_ok(Poll::Pending)
     }
 }
 
@@ -424,7 +420,7 @@ pub fn create_ecx<'tcx>(
         }
     }
 
-    Ok(ecx)
+    interp_ok(ecx)
 }
 
 /// Evaluates the entry function specified by `entry_id`.
@@ -440,7 +436,7 @@ pub fn eval_entry<'tcx>(
     // Copy setting before we move `config`.
     let ignore_leaks = config.ignore_leaks;
 
-    let mut ecx = match create_ecx(tcx, entry_id, entry_type, &config) {
+    let mut ecx = match create_ecx(tcx, entry_id, entry_type, &config).report_err() {
         Ok(v) => v,
         Err(err) => {
             let (kind, backtrace) = err.into_parts();
@@ -457,7 +453,7 @@ pub fn eval_entry<'tcx>(
         panic::resume_unwind(panic_payload)
     });
     // `Ok` can never happen.
-    let Err(res) = res;
+    let Err(err) = res.report_err();
 
     // Machine cleanup. Only do this if all threads have terminated; threads that are still running
     // might cause Stacked Borrows errors (https://github.com/rust-lang/miri/issues/2396).
@@ -470,7 +466,7 @@ pub fn eval_entry<'tcx>(
     }
 
     // Process the result.
-    let (return_code, leak_check) = report_error(&ecx, res)?;
+    let (return_code, leak_check) = report_error(&ecx, err)?;
     if leak_check && !ignore_leaks {
         // Check for thread leaks.
         if !ecx.have_all_terminated() {
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 10e5882b5ba..013bfe03aaf 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -1,29 +1,22 @@
-use std::cmp;
 use std::collections::BTreeSet;
-use std::iter;
 use std::num::NonZero;
 use std::sync::Mutex;
 use std::time::Duration;
+use std::{cmp, iter};
 
 use rand::RngCore;
-
 use rustc_apfloat::Float;
 use rustc_apfloat::ieee::{Double, Half, Quad, Single};
-use rustc_hir::{
-    Safety,
-    def::{DefKind, Namespace},
-    def_id::{CRATE_DEF_INDEX, CrateNum, DefId, LOCAL_CRATE},
-};
+use rustc_hir::Safety;
+use rustc_hir::def::{DefKind, Namespace};
+use rustc_hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefId, LOCAL_CRATE};
 use rustc_index::IndexVec;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::ExportedSymbol;
 use rustc_middle::mir;
-use rustc_middle::ty::layout::{FnAbiOf, MaybeResult};
-use rustc_middle::ty::{
-    self, FloatTy, IntTy, Ty, TyCtxt, UintTy,
-    layout::{LayoutOf, TyAndLayout},
-};
+use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, MaybeResult, TyAndLayout};
+use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, UintTy};
 use rustc_session::config::CrateType;
 use rustc_span::{Span, Symbol};
 use rustc_target::abi::{Align, FieldIdx, FieldsShape, Size, Variants};
@@ -38,65 +31,6 @@ pub enum AccessKind {
     Write,
 }
 
-// This mapping should match `decode_error_kind` in
-// <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/pal/unix/mod.rs>.
-const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = {
-    use std::io::ErrorKind::*;
-    &[
-        ("E2BIG", ArgumentListTooLong),
-        ("EADDRINUSE", AddrInUse),
-        ("EADDRNOTAVAIL", AddrNotAvailable),
-        ("EBUSY", ResourceBusy),
-        ("ECONNABORTED", ConnectionAborted),
-        ("ECONNREFUSED", ConnectionRefused),
-        ("ECONNRESET", ConnectionReset),
-        ("EDEADLK", Deadlock),
-        ("EDQUOT", FilesystemQuotaExceeded),
-        ("EEXIST", AlreadyExists),
-        ("EFBIG", FileTooLarge),
-        ("EHOSTUNREACH", HostUnreachable),
-        ("EINTR", Interrupted),
-        ("EINVAL", InvalidInput),
-        ("EISDIR", IsADirectory),
-        ("ELOOP", FilesystemLoop),
-        ("ENOENT", NotFound),
-        ("ENOMEM", OutOfMemory),
-        ("ENOSPC", StorageFull),
-        ("ENOSYS", Unsupported),
-        ("EMLINK", TooManyLinks),
-        ("ENAMETOOLONG", InvalidFilename),
-        ("ENETDOWN", NetworkDown),
-        ("ENETUNREACH", NetworkUnreachable),
-        ("ENOTCONN", NotConnected),
-        ("ENOTDIR", NotADirectory),
-        ("ENOTEMPTY", DirectoryNotEmpty),
-        ("EPIPE", BrokenPipe),
-        ("EROFS", ReadOnlyFilesystem),
-        ("ESPIPE", NotSeekable),
-        ("ESTALE", StaleNetworkFileHandle),
-        ("ETIMEDOUT", TimedOut),
-        ("ETXTBSY", ExecutableFileBusy),
-        ("EXDEV", CrossesDevices),
-        // The following have two valid options. We have both for the forwards mapping; only the
-        // first one will be used for the backwards mapping.
-        ("EPERM", PermissionDenied),
-        ("EACCES", PermissionDenied),
-        ("EWOULDBLOCK", WouldBlock),
-        ("EAGAIN", WouldBlock),
-    ]
-};
-// This mapping should match `decode_error_kind` in
-// <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/pal/windows/mod.rs>.
-const WINDOWS_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = {
-    use std::io::ErrorKind::*;
-    // FIXME: this is still incomplete.
-    &[
-        ("ERROR_ACCESS_DENIED", PermissionDenied),
-        ("ERROR_FILE_NOT_FOUND", NotFound),
-        ("ERROR_INVALID_PARAMETER", InvalidInput),
-    ]
-};
-
 /// Gets an instance for a path.
 ///
 /// A `None` namespace indicates we are looking for a module.
@@ -235,7 +169,7 @@ pub fn iter_exported_symbols<'tcx>(
             }
         }
     }
-    Ok(())
+    interp_ok(())
 }
 
 /// Convert a softfloat type to its corresponding hostfloat type.
@@ -438,7 +372,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             let field = this.project_field(dest, idx)?;
             this.write_int(val, &field)?;
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Write the given fields of the given place.
@@ -452,7 +386,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             let field = this.project_field_named(dest, name)?;
             this.write_int(val, &field)?;
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Write a 0 of the appropriate size to `dest`.
@@ -462,7 +396,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
     /// Test if this pointer equals 0.
     fn ptr_is_null(&self, ptr: Pointer) -> InterpResult<'tcx, bool> {
-        Ok(ptr.addr().bytes() == 0)
+        interp_ok(ptr.addr().bytes() == 0)
     }
 
     /// Generate some random bytes, and write them to `dest`.
@@ -473,7 +407,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // any additional checks - it's okay if the pointer is invalid,
         // since we wouldn't actually be writing to it.
         if len == 0 {
-            return Ok(());
+            return interp_ok(());
         }
         let this = self.eval_context_mut();
 
@@ -578,7 +512,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             cur_addr += unsafe_cell_size;
             // Done
-            Ok(())
+            interp_ok(())
         };
         // Run a visitor
         {
@@ -596,7 +530,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     if unsafe_cell_size != Size::ZERO {
                         unsafe_cell_action(&place.ptr(), unsafe_cell_size)
                     } else {
-                        Ok(())
+                        interp_ok(())
                     }
                 },
             };
@@ -606,7 +540,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // So pretend there is a 0-sized `UnsafeCell` at the end.
         unsafe_cell_action(&place.ptr().wrapping_offset(size, this), Size::ZERO)?;
         // Done!
-        return Ok(());
+        return interp_ok(());
 
         /// Visiting the memory covered by a `MemPlace`, being aware of
         /// whether we are inside an `UnsafeCell` or not.
@@ -649,7 +583,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     (self.unsafe_cell_action)(v)
                 } else if self.ecx.type_is_freeze(v.layout.ty) {
                     // This is `Freeze`, there cannot be an `UnsafeCell`
-                    Ok(())
+                    interp_ok(())
                 } else if matches!(v.layout.fields, FieldsShape::Union(..)) {
                     // A (non-frozen) union. We fall back to whatever the type says.
                     (self.unsafe_cell_action)(v)
@@ -698,7 +632,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if !self.eval_context_ref().machine.communicate() {
             self.reject_in_isolation(name, RejectOpWith::Abort)?;
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Helper function used inside the shims of foreign functions which reject the op
@@ -720,13 +654,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         .dcx()
                         .warn(format!("{op_name} was made to return an error due to isolation"));
                 }
-                Ok(())
+                interp_ok(())
             }
             RejectOpWith::Warning => {
                 this.emit_diagnostic(NonHaltingDiagnostic::RejectedIsolatedOp(op_name.to_string()));
-                Ok(())
+                interp_ok(())
             }
-            RejectOpWith::NoWarning => Ok(()), // no warning
+            RejectOpWith::NoWarning => interp_ok(()), // no warning
         }
     }
 
@@ -752,119 +686,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         self.eval_context_ref().tcx.sess.target.families.iter().any(|f| f == "unix")
     }
 
-    /// Get last error variable as a place, lazily allocating thread-local storage for it if
-    /// necessary.
-    fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
-        let this = self.eval_context_mut();
-        if let Some(errno_place) = this.active_thread_ref().last_error.as_ref() {
-            Ok(errno_place.clone())
-        } else {
-            // Allocate new place, set initial value to 0.
-            let errno_layout = this.machine.layouts.u32;
-            let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into())?;
-            this.write_scalar(Scalar::from_u32(0), &errno_place)?;
-            this.active_thread_mut().last_error = Some(errno_place.clone());
-            Ok(errno_place)
-        }
-    }
-
-    /// Sets the last error variable.
-    fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-        let errno_place = this.last_error_place()?;
-        this.write_scalar(scalar, &errno_place)
-    }
-
-    /// Gets the last error variable.
-    fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> {
-        let this = self.eval_context_mut();
-        let errno_place = this.last_error_place()?;
-        this.read_scalar(&errno_place)
-    }
-
-    /// This function tries to produce the most similar OS error from the `std::io::ErrorKind`
-    /// as a platform-specific errnum.
-    fn io_error_to_errnum(&self, err: std::io::Error) -> InterpResult<'tcx, Scalar> {
-        let this = self.eval_context_ref();
-        let target = &this.tcx.sess.target;
-        if target.families.iter().any(|f| f == "unix") {
-            for &(name, kind) in UNIX_IO_ERROR_TABLE {
-                if err.kind() == kind {
-                    return Ok(this.eval_libc(name));
-                }
-            }
-            throw_unsup_format!("unsupported io error: {err}")
-        } else if target.families.iter().any(|f| f == "windows") {
-            for &(name, kind) in WINDOWS_IO_ERROR_TABLE {
-                if err.kind() == kind {
-                    return Ok(this.eval_windows("c", name));
-                }
-            }
-            throw_unsup_format!("unsupported io error: {err}");
-        } else {
-            throw_unsup_format!(
-                "converting io::Error into errnum is unsupported for OS {}",
-                target.os
-            )
-        }
-    }
-
-    /// The inverse of `io_error_to_errnum`.
-    #[allow(clippy::needless_return)]
-    fn try_errnum_to_io_error(
-        &self,
-        errnum: Scalar,
-    ) -> InterpResult<'tcx, Option<std::io::ErrorKind>> {
-        let this = self.eval_context_ref();
-        let target = &this.tcx.sess.target;
-        if target.families.iter().any(|f| f == "unix") {
-            let errnum = errnum.to_i32()?;
-            for &(name, kind) in UNIX_IO_ERROR_TABLE {
-                if errnum == this.eval_libc_i32(name) {
-                    return Ok(Some(kind));
-                }
-            }
-            return Ok(None);
-        } else if target.families.iter().any(|f| f == "windows") {
-            let errnum = errnum.to_u32()?;
-            for &(name, kind) in WINDOWS_IO_ERROR_TABLE {
-                if errnum == this.eval_windows("c", name).to_u32()? {
-                    return Ok(Some(kind));
-                }
-            }
-            return Ok(None);
-        } else {
-            throw_unsup_format!(
-                "converting errnum into io::Error is unsupported for OS {}",
-                target.os
-            )
-        }
-    }
-
-    /// Sets the last OS error using a `std::io::ErrorKind`.
-    fn set_last_error_from_io_error(&mut self, err: std::io::Error) -> InterpResult<'tcx> {
-        self.set_last_error(self.io_error_to_errnum(err)?)
-    }
-
-    /// Helper function that consumes an `std::io::Result<T>` and returns an
-    /// `InterpResult<'tcx,T>::Ok` instead. In case the result is an error, this function returns
-    /// `Ok(-1)` and sets the last OS error accordingly.
-    ///
-    /// This function uses `T: From<i32>` instead of `i32` directly because some IO related
-    /// functions return different integer types (like `read`, that returns an `i64`).
-    fn try_unwrap_io_result<T: From<i32>>(
-        &mut self,
-        result: std::io::Result<T>,
-    ) -> InterpResult<'tcx, T> {
-        match result {
-            Ok(ok) => Ok(ok),
-            Err(e) => {
-                self.eval_context_mut().set_last_error_from_io_error(e)?;
-                Ok((-1).into())
-            }
-        }
-    }
-
     /// Dereference a pointer operand to a place using `layout` instead of the pointer's declared type
     fn deref_pointer_as(
         &self,
@@ -873,7 +694,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
         let this = self.eval_context_ref();
         let ptr = this.read_pointer(op)?;
-        Ok(this.ptr_to_mplace(ptr, layout))
+        interp_ok(this.ptr_to_mplace(ptr, layout))
     }
 
     /// Calculates the MPlaceTy given the offset and layout of an access on an operand
@@ -891,7 +712,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Ensure that the access is within bounds.
         assert!(base_layout.size >= offset + value_layout.size);
         let value_place = op_place.offset(offset, value_layout, this)?;
-        Ok(value_place)
+        interp_ok(value_place)
     }
 
     fn deref_pointer_and_read(
@@ -931,17 +752,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let nanoseconds_scalar = this.read_scalar(&nanoseconds_place)?;
         let nanoseconds = nanoseconds_scalar.to_target_isize(this)?;
 
-        Ok(try {
-            // tv_sec must be non-negative.
-            let seconds: u64 = seconds.try_into().ok()?;
-            // tv_nsec must be non-negative.
-            let nanoseconds: u32 = nanoseconds.try_into().ok()?;
-            if nanoseconds >= 1_000_000_000 {
-                // tv_nsec must not be greater than 999,999,999.
-                None?
-            }
-            Duration::new(seconds, nanoseconds)
-        })
+        interp_ok(
+            try {
+                // tv_sec must be non-negative.
+                let seconds: u64 = seconds.try_into().ok()?;
+                // tv_nsec must be non-negative.
+                let nanoseconds: u32 = nanoseconds.try_into().ok()?;
+                if nanoseconds >= 1_000_000_000 {
+                    // tv_nsec must not be greater than 999,999,999.
+                    None?
+                }
+                Duration::new(seconds, nanoseconds)
+            },
+        )
     }
 
     /// Read bytes from a byte slice.
@@ -954,7 +777,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let ptr = ptr.to_pointer(this)?;
         let len = len.to_target_usize(this)?;
         let bytes = this.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?;
-        Ok(bytes)
+        interp_ok(bytes)
     }
 
     /// Read a sequence of bytes until the first null terminator.
@@ -999,11 +822,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let string_length = u64::try_from(c_str.len()).unwrap();
         let string_length = string_length.strict_add(1);
         if size < string_length {
-            return Ok((false, string_length));
+            return interp_ok((false, string_length));
         }
         self.eval_context_mut()
             .write_bytes_ptr(ptr, c_str.iter().copied().chain(iter::once(0u8)))?;
-        Ok((true, string_length))
+        interp_ok((true, string_length))
     }
 
     /// Helper function to read a sequence of unsigned integers of the given size and alignment
@@ -1038,7 +861,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
         }
 
-        Ok(wchars)
+        interp_ok(wchars)
     }
 
     /// Read a sequence of u16 until the first null terminator.
@@ -1063,7 +886,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let string_length = u64::try_from(wide_str.len()).unwrap();
         let string_length = string_length.strict_add(1);
         if size < string_length {
-            return Ok((false, string_length));
+            return interp_ok((false, string_length));
         }
 
         // Store the UTF-16 string.
@@ -1075,7 +898,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             let offset = u64::try_from(offset).unwrap();
             alloc.write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar))?;
         }
-        Ok((true, string_length))
+        interp_ok((true, string_length))
     }
 
     /// Read a sequence of wchar_t until the first null terminator.
@@ -1100,7 +923,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 abi.name()
             )
         }
-        Ok(())
+        interp_ok(())
     }
 
     fn frame_in_std(&self) -> bool {
@@ -1135,7 +958,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // message is slightly different here to make automated analysis easier
             let error_msg = format!("unsupported Miri functionality: {error_msg}");
             this.start_panic(error_msg.as_ref(), mir::UnwindAction::Continue)?;
-            Ok(())
+            interp_ok(())
         } else {
             throw_machine_stop!(TerminationInfo::UnsupportedForeignItem(error_msg));
         }
@@ -1155,7 +978,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // compiler-builtins when running other crates, but Miri can still be run on
             // compiler-builtins itself (or any crate that uses it as a normal dependency)
             if self.eval_context_ref().tcx.is_compiler_builtins(instance.def_id().krate) {
-                return Ok(());
+                return interp_ok(());
             }
 
             throw_machine_stop!(TerminationInfo::SymbolShimClashing {
@@ -1163,7 +986,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 span: body.span.data(),
             })
         }
-        Ok(())
+        interp_ok(())
     }
 
     fn check_shim<'a, const N: usize>(
@@ -1249,11 +1072,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         ) {
             // Floating point value is NaN (flagged with INVALID_OP) or outside the range
             // of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
-            Ok(None)
+            interp_ok(None)
         } else {
             // Floating point value can be represented by the integer type after rounding.
             // The INEXACT flag is ignored on purpose to allow rounding.
-            Ok(Some(ImmTy::from_scalar(val, cast_to)))
+            interp_ok(Some(ImmTy::from_scalar(val, cast_to)))
         }
     }
 
@@ -1290,7 +1113,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 "attempted to call intrinsic `{intrinsic}` that requires missing target feature {target_feature}"
             );
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Lookup an array of immediates stored as a linker section of name `name`.
@@ -1303,7 +1126,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         iter_exported_symbols(tcx, |_cnum, def_id| {
             let attrs = tcx.codegen_fn_attrs(def_id);
             let Some(link_section) = attrs.link_section else {
-                return Ok(());
+                return interp_ok(());
             };
             if link_section.as_str() == name {
                 let instance = ty::Instance::mono(tcx, def_id);
@@ -1315,10 +1138,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let val = this.read_immediate(&const_val)?;
                 array.push(val);
             }
-            Ok(())
+            interp_ok(())
         })?;
 
-        Ok(array)
+        interp_ok(array)
     }
 }
 
@@ -1368,7 +1191,7 @@ where
     &'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>,
 {
     if let Ok(ops) = args.try_into() {
-        return Ok(ops);
+        return interp_ok(ops);
     }
     throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N)
 }
@@ -1408,7 +1231,7 @@ pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar {
 
 pub(crate) fn simd_element_to_bool(elem: ImmTy<'_>) -> InterpResult<'_, bool> {
     let val = elem.to_scalar().to_int(elem.layout.size)?;
-    Ok(match val {
+    interp_ok(match val {
         0 => false,
         -1 => true,
         _ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"),
diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs
index 6365e0efd51..8507b0f49de 100644
--- a/src/tools/miri/src/intrinsics/atomic.rs
+++ b/src/tools/miri/src/intrinsics/atomic.rs
@@ -1,7 +1,8 @@
-use rustc_middle::{mir, mir::BinOp, ty};
+use rustc_middle::mir::BinOp;
+use rustc_middle::{mir, ty};
 
-use crate::*;
 use self::helpers::check_arg_count;
+use crate::*;
 
 pub enum AtomicOp {
     /// The `bool` indicates whether the result of the operation should be negated (`UnOp::Not`,
@@ -114,9 +115,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.atomic_rmw_op(args, dest, AtomicOp::Max, rw_ord(ord))?;
             }
 
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
 
@@ -137,7 +138,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
         let val = this.read_scalar_atomic(&place, atomic)?;
         // Perform regular store.
         this.write_scalar(val, dest)?;
-        Ok(())
+        interp_ok(())
     }
 
     fn atomic_store(&mut self, args: &[OpTy<'tcx>], atomic: AtomicWriteOrd) -> InterpResult<'tcx> {
@@ -150,7 +151,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
         let val = this.read_scalar(val)?;
         // Perform atomic store
         this.write_scalar_atomic(val, &place, atomic)?;
-        Ok(())
+        interp_ok(())
     }
 
     fn compiler_fence_intrinsic(
@@ -161,7 +162,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
         let [] = check_arg_count(args)?;
         let _ = atomic;
         //FIXME: compiler fences are currently ignored
-        Ok(())
+        interp_ok(())
     }
 
     fn atomic_fence_intrinsic(
@@ -172,7 +173,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         let [] = check_arg_count(args)?;
         this.atomic_fence(atomic)?;
-        Ok(())
+        interp_ok(())
     }
 
     fn atomic_rmw_op(
@@ -202,17 +203,17 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
             AtomicOp::Min => {
                 let old = this.atomic_min_max_scalar(&place, rhs, true, atomic)?;
                 this.write_immediate(*old, dest)?; // old value is returned
-                Ok(())
+                interp_ok(())
             }
             AtomicOp::Max => {
                 let old = this.atomic_min_max_scalar(&place, rhs, false, atomic)?;
                 this.write_immediate(*old, dest)?; // old value is returned
-                Ok(())
+                interp_ok(())
             }
             AtomicOp::MirOp(op, not) => {
                 let old = this.atomic_rmw_op_immediate(&place, &rhs, op, not, atomic)?;
                 this.write_immediate(*old, dest)?; // old value is returned
-                Ok(())
+                interp_ok(())
             }
         }
     }
@@ -231,7 +232,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
 
         let old = this.atomic_exchange_scalar(&place, new, atomic)?;
         this.write_scalar(old, dest)?; // old value is returned
-        Ok(())
+        interp_ok(())
     }
 
     fn atomic_compare_exchange_impl(
@@ -260,7 +261,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
 
         // Return old value.
         this.write_immediate(old, dest)?;
-        Ok(())
+        interp_ok(())
     }
 
     fn atomic_compare_exchange(
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index b8352b575a4..665dd7c441a 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -5,17 +5,15 @@ mod simd;
 
 use rand::Rng;
 use rustc_apfloat::{Float, Round};
-use rustc_middle::{
-    mir,
-    ty::{self, FloatTy},
-};
+use rustc_middle::mir;
+use rustc_middle::ty::{self, FloatTy};
 use rustc_span::{Symbol, sym};
 use rustc_target::abi::Size;
 
-use crate::*;
 use self::atomic::EvalContextExt as _;
 use self::helpers::{ToHost, ToSoft, check_arg_count};
 use self::simd::EvalContextExt as _;
+use crate::*;
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
@@ -31,7 +29,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // See if the core engine can handle this intrinsic.
         if this.eval_intrinsic(instance, args, dest, ret)? {
-            return Ok(None);
+            return interp_ok(None);
         }
         let intrinsic_name = this.tcx.item_name(instance.def_id());
         let intrinsic_name = intrinsic_name.as_str();
@@ -53,7 +51,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         "Miri can only use intrinsic fallback bodies that exactly reflect the specification: they fully check for UB and are as non-deterministic as possible. After verifying that `{intrinsic_name}` does so, add the `#[miri::intrinsic_fallback_is_spec]` attribute to it; also ping @rust-lang/miri when you do that"
                     );
                 }
-                Ok(Some(ty::Instance {
+                interp_ok(Some(ty::Instance {
                     def: ty::InstanceKind::Item(instance.def_id()),
                     args: instance.args,
                 }))
@@ -61,14 +59,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             EmulateItemResult::NeedsReturn => {
                 trace!("{:?}", this.dump_place(&dest.clone().into()));
                 this.return_to_block(ret)?;
-                Ok(None)
+                interp_ok(None)
             }
             EmulateItemResult::NeedsUnwind => {
                 // Jump to the unwind block to begin unwinding.
                 this.unwind_to_block(unwind)?;
-                Ok(None)
+                interp_ok(None)
             }
-            EmulateItemResult::AlreadyJumped => Ok(None),
+            EmulateItemResult::AlreadyJumped => interp_ok(None),
         }
     }
 
@@ -101,7 +99,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "catch_unwind" => {
                 this.handle_catch_unwind(args, dest, ret)?;
                 // This pushed a stack frame, don't jump to `ret`.
-                return Ok(EmulateItemResult::AlreadyJumped);
+                return interp_ok(EmulateItemResult::AlreadyJumped);
             }
 
             // Raw memory accesses
@@ -380,7 +378,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     let ty::Float(fty) = x.layout.ty.kind() else {
                         bug!("float_finite: non-float input type {}", x.layout.ty)
                     };
-                    Ok(match fty {
+                    interp_ok(match fty {
                         FloatTy::F16 => x.to_scalar().to_f16()?.is_finite(),
                         FloatTy::F32 => x.to_scalar().to_f32()?.is_finite(),
                         FloatTy::F64 => x.to_scalar().to_f64()?.is_finite(),
@@ -431,9 +429,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 throw_machine_stop!(TerminationInfo::Abort(format!("trace/breakpoint trap")))
             }
 
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
 
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index 2bc11d63a39..de293495e86 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -1,8 +1,8 @@
 use either::Either;
-
 use rustc_apfloat::{Float, Round};
+use rustc_middle::ty::FloatTy;
 use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
-use rustc_middle::{mir, ty, ty::FloatTy};
+use rustc_middle::{mir, ty};
 use rustc_span::{Symbol, sym};
 use rustc_target::abi::{Endian, HasDataLayout};
 
@@ -247,7 +247,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                             // This does NaN adjustments.
                             let val = this.binary_op(mir_op, &left, &right).map_err(|err| {
                                 match err.kind() {
-                                    InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ShiftOverflow { shift_amount, .. }) => {
+                                    &InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ShiftOverflow { shift_amount, .. }) => {
                                         // This resets the interpreter backtrace, but it's not worth avoiding that.
                                         let shift_amount = match shift_amount {
                                             Either::Left(v) => v.to_string(),
@@ -786,9 +786,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
             }
 
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 
     fn fminmax_op(
@@ -804,7 +804,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
         let left = left.to_scalar();
         let right = right.to_scalar();
-        Ok(match float_ty {
+        interp_ok(match float_ty {
             FloatTy::F16 => unimplemented!("f16_f128"),
             FloatTy::F32 => {
                 let left = left.to_f32()?;
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 6e015813e77..330147c8f1c 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -32,10 +32,7 @@
     clippy::derived_hash_with_manual_eq,
     clippy::too_many_arguments,
     clippy::type_complexity,
-    clippy::single_element_loop,
-    clippy::needless_return,
     clippy::bool_to_int_with_if,
-    clippy::box_default,
     clippy::needless_question_mark,
     clippy::needless_lifetimes,
     clippy::too_long_first_doc_paragraph,
@@ -95,15 +92,14 @@ mod range_map;
 mod shims;
 
 // Establish a "crate-wide prelude": we often import `crate::*`.
-use rustc_middle::{bug, span_bug};
-use tracing::{info, trace};
-
 // Make all those symbols available in the same place as our own.
 #[doc(no_inline)]
 pub use rustc_const_eval::interpret::*;
 // Resolve ambiguity.
 #[doc(no_inline)]
 pub use rustc_const_eval::interpret::{self, AllocMap, Provenance as _};
+use rustc_middle::{bug, span_bug};
+use tracing::{info, trace};
 
 // Type aliases that set the provenance parameter.
 pub type Pointer = interpret::Pointer<Option<machine::Provenance>>;
@@ -114,15 +110,6 @@ pub type OpTy<'tcx> = interpret::OpTy<'tcx, machine::Provenance>;
 pub type PlaceTy<'tcx> = interpret::PlaceTy<'tcx, machine::Provenance>;
 pub type MPlaceTy<'tcx> = interpret::MPlaceTy<'tcx, machine::Provenance>;
 
-pub use crate::intrinsics::EvalContextExt as _;
-pub use crate::shims::EmulateItemResult;
-pub use crate::shims::env::{EnvVars, EvalContextExt as _};
-pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _};
-pub use crate::shims::os_str::EvalContextExt as _;
-pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _};
-pub use crate::shims::time::EvalContextExt as _;
-pub use crate::shims::tls::TlsData;
-
 pub use crate::alloc_addresses::{EvalContextExt as _, ProvenanceMode};
 pub use crate::alloc_bytes::MiriAllocBytes;
 pub use crate::borrow_tracker::stacked_borrows::{
@@ -131,15 +118,17 @@ pub use crate::borrow_tracker::stacked_borrows::{
 pub use crate::borrow_tracker::tree_borrows::{EvalContextExt as _, Tree};
 pub use crate::borrow_tracker::{BorTag, BorrowTrackerMethod, EvalContextExt as _, RetagFields};
 pub use crate::clock::{Clock, Instant};
-pub use crate::concurrency::{
-    cpu_affinity::MAX_CPUS,
-    data_race::{AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as _},
-    init_once::{EvalContextExt as _, InitOnceId},
-    sync::{CondvarId, EvalContextExt as _, MutexId, RwLockId, SynchronizationObjects},
-    thread::{
-        BlockReason, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager,
-        TimeoutAnchor, TimeoutClock, UnblockCallback,
-    },
+pub use crate::concurrency::cpu_affinity::MAX_CPUS;
+pub use crate::concurrency::data_race::{
+    AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as _,
+};
+pub use crate::concurrency::init_once::{EvalContextExt as _, InitOnceId};
+pub use crate::concurrency::sync::{
+    CondvarId, EvalContextExt as _, MutexId, RwLockId, SynchronizationObjects,
+};
+pub use crate::concurrency::thread::{
+    BlockReason, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, TimeoutAnchor,
+    TimeoutClock, UnblockCallback,
 };
 pub use crate::diagnostics::{
     EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo, report_error,
@@ -149,6 +138,7 @@ pub use crate::eval::{
     create_ecx, eval_entry,
 };
 pub use crate::helpers::{AccessKind, EvalContextExt as _};
+pub use crate::intrinsics::EvalContextExt as _;
 pub use crate::machine::{
     AllocExtra, FrameExtra, MemoryKind, MiriInterpCx, MiriInterpCxExt, MiriMachine, MiriMemoryKind,
     PrimitiveLayouts, Provenance, ProvenanceExtra,
@@ -157,6 +147,14 @@ pub use crate::mono_hash_map::MonoHashMap;
 pub use crate::operator::EvalContextExt as _;
 pub use crate::provenance_gc::{EvalContextExt as _, LiveAllocs, VisitProvenance, VisitWith};
 pub use crate::range_map::RangeMap;
+pub use crate::shims::EmulateItemResult;
+pub use crate::shims::env::{EnvVars, EvalContextExt as _};
+pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _};
+pub use crate::shims::io_error::{EvalContextExt as _, LibcError};
+pub use crate::shims::os_str::EvalContextExt as _;
+pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _};
+pub use crate::shims::time::EvalContextExt as _;
+pub use crate::shims::tls::TlsData;
 
 /// Insert rustc arguments at the beginning of the argument list that Miri wants to be
 /// set per default, for maximal validation power.
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index b93feeeee33..b9cebcfe9cd 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -4,40 +4,29 @@
 use std::borrow::Cow;
 use std::cell::RefCell;
 use std::collections::hash_map::Entry;
-use std::fmt;
 use std::path::Path;
-use std::process;
+use std::{fmt, process};
 
-use rand::Rng;
-use rand::SeedableRng;
 use rand::rngs::StdRng;
-
+use rand::{Rng, SeedableRng};
 use rustc_attr::InlineAttr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 #[allow(unused)]
 use rustc_data_structures::static_assert_size;
-use rustc_middle::{
-    mir,
-    query::TyCtxtAt,
-    ty::{
-        self, Instance, Ty, TyCtxt,
-        layout::{HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout},
-    },
-};
+use rustc_middle::mir;
+use rustc_middle::query::TyCtxtAt;
+use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_session::config::InliningThreshold;
 use rustc_span::def_id::{CrateNum, DefId};
 use rustc_span::{Span, SpanData, Symbol};
 use rustc_target::abi::{Align, Size};
 use rustc_target::spec::abi::Abi;
 
-use crate::{
-    concurrency::{
-        cpu_affinity::{self, CpuAffinityMask},
-        data_race::{self, NaReadType, NaWriteType},
-        weak_memory,
-    },
-    *,
-};
+use crate::concurrency::cpu_affinity::{self, CpuAffinityMask};
+use crate::concurrency::data_race::{self, NaReadType, NaWriteType};
+use crate::concurrency::weak_memory;
+use crate::*;
 
 /// First real-time signal.
 /// `signal(7)` says this must be between 32 and 64 and specifies 34 or 35
@@ -741,7 +730,7 @@ impl<'tcx> MiriMachine<'tcx> {
         EnvVars::init(this, config)?;
         MiriMachine::init_extern_statics(this)?;
         ThreadManager::init(this, on_main_stack_empty);
-        Ok(())
+        interp_ok(())
     }
 
     pub(crate) fn add_extern_static(this: &mut MiriInterpCx<'tcx>, name: &str, ptr: Pointer) {
@@ -1003,7 +992,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
                 throw_ub_format!("{msg}");
             }
         }
-        Ok(())
+        interp_ok(())
     }
 
     #[inline(always)]
@@ -1030,7 +1019,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         }
 
         // Otherwise, load the MIR.
-        Ok(Some((ecx.load_mir(instance.def, None)?, instance)))
+        interp_ok(Some((ecx.load_mir(instance.def, None)?, instance)))
     }
 
     #[inline(always)]
@@ -1083,7 +1072,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             ret: None,
             unwind: mir::UnwindAction::Unreachable,
         })?;
-        Ok(())
+        interp_ok(())
     }
 
     #[inline(always)]
@@ -1108,7 +1097,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
     }
 
     fn ub_checks(ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool> {
-        Ok(ecx.tcx.sess.ub_checks())
+        interp_ok(ecx.tcx.sess.ub_checks())
     }
 
     fn thread_local_static_pointer(
@@ -1147,7 +1136,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
                     shim_align = shim_align.bytes(),
                 )
             }
-            Ok(ptr)
+            interp_ok(ptr)
         } else {
             throw_unsup_format!("extern static `{link_name}` is not supported by Miri",)
         }
@@ -1197,7 +1186,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
                 .insert(id, (ecx.machine.current_span(), None));
         }
 
-        Ok(AllocExtra { borrow_tracker, data_race, weak_memory, backtrace })
+        interp_ok(AllocExtra { borrow_tracker, data_race, weak_memory, backtrace })
     }
 
     fn adjust_alloc_root_pointer(
@@ -1244,7 +1233,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             Provenance::Wildcard => {
                 // No need to do anything for wildcard pointers as
                 // their provenances have already been previously exposed.
-                Ok(())
+                interp_ok(())
             }
         }
     }
@@ -1297,7 +1286,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             |ptr| ecx.global_root_pointer(ptr),
         )?;
         let extra = Self::init_alloc_extra(ecx, id, kind, alloc.size(), alloc.align)?;
-        Ok(Cow::Owned(alloc.with_extra(extra)))
+        interp_ok(Cow::Owned(alloc.with_extra(extra)))
     }
 
     #[inline(always)]
@@ -1321,7 +1310,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         if let Some(weak_memory) = &alloc_extra.weak_memory {
             weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap());
         }
-        Ok(())
+        interp_ok(())
     }
 
     #[inline(always)]
@@ -1345,7 +1334,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         if let Some(weak_memory) = &alloc_extra.weak_memory {
             weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap());
         }
-        Ok(())
+        interp_ok(())
     }
 
     #[inline(always)]
@@ -1378,7 +1367,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             *deallocated_at = Some(machine.current_span());
         }
         machine.free_alloc_id(alloc_id, size, align, kind);
-        Ok(())
+        interp_ok(())
     }
 
     #[inline(always)]
@@ -1390,7 +1379,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         if ecx.machine.borrow_tracker.is_some() {
             ecx.retag_ptr_value(kind, val)
         } else {
-            Ok(val.clone())
+            interp_ok(val.clone())
         }
     }
 
@@ -1403,7 +1392,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         if ecx.machine.borrow_tracker.is_some() {
             ecx.retag_place_contents(kind, place)?;
         }
-        Ok(())
+        interp_ok(())
     }
 
     fn protect_in_place_function_argument(
@@ -1424,7 +1413,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         // Conveniently this also ensures that the place actually points to suitable memory.
         ecx.write_uninit(&protected_place)?;
         // Now we throw away the protected place, ensuring its tag is never used again.
-        Ok(())
+        interp_ok(())
     }
 
     #[inline(always)]
@@ -1458,7 +1447,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             data_race: ecx.machine.data_race.as_ref().map(|_| data_race::FrameState::default()),
         };
 
-        Ok(frame.with_extra(extra))
+        interp_ok(frame.with_extra(extra))
     }
 
     fn stack<'a>(
@@ -1500,7 +1489,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         // Make sure some time passes.
         ecx.machine.clock.tick();
 
-        Ok(())
+        interp_ok(())
     }
 
     #[inline(always)]
@@ -1511,7 +1500,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             let stack_len = ecx.active_thread_stack().len();
             ecx.active_thread_mut().set_top_user_relevant_frame(stack_len - 1);
         }
-        Ok(())
+        interp_ok(())
     }
 
     fn before_stack_pop(
@@ -1527,7 +1516,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         // concurrency and what it prints is just plain wrong. So we print our own information
         // instead. (Cc https://github.com/rust-lang/miri/issues/2266)
         info!("Leaving {}", ecx.frame().instance());
-        Ok(())
+        interp_ok(())
     }
 
     #[inline(always)]
@@ -1565,7 +1554,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         if let Some(data_race) = &ecx.frame().extra.data_race {
             data_race.local_read(local, &ecx.machine);
         }
-        Ok(())
+        interp_ok(())
     }
 
     fn after_local_write(
@@ -1576,7 +1565,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         if let Some(data_race) = &ecx.frame().extra.data_race {
             data_race.local_write(local, storage_live, &ecx.machine);
         }
-        Ok(())
+        interp_ok(())
     }
 
     fn after_local_moved_to_memory(
@@ -1598,7 +1587,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         {
             data_race.local_moved_to_memory(local, alloc_info.data_race.as_mut().unwrap(), machine);
         }
-        Ok(())
+        interp_ok(())
     }
 
     fn eval_mir_constant<F>(
@@ -1622,9 +1611,9 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             Entry::Vacant(ve) => {
                 let op = eval(ecx, val, span, layout)?;
                 ve.insert(op.clone());
-                Ok(op)
+                interp_ok(op)
             }
-            Entry::Occupied(oe) => Ok(oe.get().clone()),
+            Entry::Occupied(oe) => interp_ok(oe.get().clone()),
         }
     }
 
diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs
index 1b6a7255eef..c0911fa717f 100644
--- a/src/tools/miri/src/operator.rs
+++ b/src/tools/miri/src/operator.rs
@@ -1,6 +1,7 @@
 use std::iter;
 
-use rand::{Rng, seq::IteratorRandom};
+use rand::Rng;
+use rand::seq::IteratorRandom;
 use rustc_apfloat::{Float, FloatConvert};
 use rustc_middle::mir;
 use rustc_target::abi::Size;
@@ -20,7 +21,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_ref();
         trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right);
 
-        Ok(match bin_op {
+        interp_ok(match bin_op {
             Eq | Ne | Lt | Le | Gt | Ge => {
                 assert_eq!(left.layout.abi, right.layout.abi); // types can differ, e.g. fn ptrs with different `for`
                 let size = this.pointer_size();
diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs
index d4bed69c670..c5a35bc14f5 100644
--- a/src/tools/miri/src/provenance_gc.rs
+++ b/src/tools/miri/src/provenance_gc.rs
@@ -1,5 +1,4 @@
 use either::Either;
-
 use rustc_data_structures::fx::FxHashSet;
 
 use crate::*;
diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs
index a33657d33a2..e73344367ec 100644
--- a/src/tools/miri/src/shims/alloc.rs
+++ b/src/tools/miri/src/shims/alloc.rs
@@ -61,7 +61,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let Some(allocator_kind) = this.tcx.allocator_kind(()) else {
             // in real code, this symbol does not exist without an allocator
-            return Ok(EmulateItemResult::NotSupported);
+            return interp_ok(EmulateItemResult::NotSupported);
         };
 
         match allocator_kind {
@@ -71,11 +71,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // and not execute any Miri shim. Somewhat unintuitively doing so is done
                 // by returning `NotSupported`, which triggers the `lookup_exported_symbol`
                 // fallback case in `emulate_foreign_item`.
-                return Ok(EmulateItemResult::NotSupported);
+                interp_ok(EmulateItemResult::NotSupported)
             }
             AllocatorKind::Default => {
                 default(this)?;
-                Ok(EmulateItemResult::NeedsReturn)
+                interp_ok(EmulateItemResult::NeedsReturn)
             }
         }
     }
@@ -92,7 +92,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             )
             .unwrap();
         }
-        Ok(ptr.into())
+        interp_ok(ptr.into())
     }
 
     fn posix_memalign(
@@ -109,7 +109,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Align must be power of 2, and also at least ptr-sized (POSIX rules).
         // But failure to adhere to this is not UB, it's an error condition.
         if !align.is_power_of_two() || align < this.pointer_size().bytes() {
-            Ok(this.eval_libc("EINVAL"))
+            interp_ok(this.eval_libc("EINVAL"))
         } else {
             let ptr = this.allocate_ptr(
                 Size::from_bytes(size),
@@ -117,7 +117,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 MiriMemoryKind::C.into(),
             )?;
             this.write_pointer(ptr, &memptr)?;
-            Ok(Scalar::from_i32(0))
+            interp_ok(Scalar::from_i32(0))
         }
     }
 
@@ -126,7 +126,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if !this.ptr_is_null(ptr)? {
             this.deallocate_ptr(ptr, None, MiriMemoryKind::C.into())?;
         }
-        Ok(())
+        interp_ok(())
     }
 
     fn realloc(&mut self, old_ptr: Pointer, new_size: u64) -> InterpResult<'tcx, Pointer> {
@@ -148,7 +148,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     new_align,
                     MiriMemoryKind::C.into(),
                 )?;
-                Ok(new_ptr.into())
+                interp_ok(new_ptr.into())
             }
         }
     }
@@ -188,9 +188,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     Align::from_bytes(align).unwrap(),
                     MiriMemoryKind::C.into(),
                 )?;
-                Ok(ptr.into())
+                interp_ok(ptr.into())
             }
-            _ => Ok(Pointer::null()),
+            _ => interp_ok(Pointer::null()),
         }
     }
 }
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index edff17c0514..25afda4edc8 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -1,9 +1,11 @@
-use crate::*;
 use rustc_ast::ast::Mutability;
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_span::{BytePos, Loc, Symbol, hygiene};
-use rustc_target::{abi::Size, spec::abi::Abi};
+use rustc_target::abi::Size;
+use rustc_target::spec::abi::Abi;
+
+use crate::*;
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
@@ -105,7 +107,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             _ => throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags),
         };
 
-        Ok(())
+        interp_ok(())
     }
 
     fn resolve_frame_pointer(
@@ -133,7 +135,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let name = fn_instance.to_string();
         let filename = lo.file.name.prefer_remapped_unconditionaly().to_string();
 
-        Ok((fn_instance, lo, name, filename))
+        interp_ok((fn_instance, lo, name, filename))
     }
 
     fn handle_miri_resolve_frame(
@@ -211,7 +213,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.write_pointer(fn_ptr, &this.project_field(dest, 4)?)?;
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     fn handle_miri_resolve_frame_names(
@@ -235,6 +237,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.write_bytes_ptr(this.read_pointer(name_ptr)?, name.bytes())?;
         this.write_bytes_ptr(this.read_pointer(filename_ptr)?, filename.bytes())?;
 
-        Ok(())
+        interp_ok(())
     }
 }
diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs
index 279df042dea..e99a8fd6e8c 100644
--- a/src/tools/miri/src/shims/env.rs
+++ b/src/tools/miri/src/shims/env.rs
@@ -2,8 +2,9 @@ use std::ffi::{OsStr, OsString};
 
 use rustc_data_structures::fx::FxHashMap;
 
+use self::shims::unix::UnixEnvVars;
+use self::shims::windows::WindowsEnvVars;
 use crate::*;
-use self::shims::{unix::UnixEnvVars, windows::WindowsEnvVars};
 
 #[derive(Default)]
 pub enum EnvVars<'tcx> {
@@ -55,15 +56,15 @@ impl<'tcx> EnvVars<'tcx> {
         };
         ecx.machine.env_vars = env_vars;
 
-        Ok(())
+        interp_ok(())
     }
 
     pub(crate) fn cleanup(ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>) -> InterpResult<'tcx> {
         let this = ecx.eval_context_mut();
         match this.machine.env_vars {
             EnvVars::Unix(_) => UnixEnvVars::cleanup(this),
-            EnvVars::Windows(_) => Ok(()), // no cleanup needed
-            EnvVars::Uninit => Ok(()),
+            EnvVars::Windows(_) => interp_ok(()), // no cleanup needed
+            EnvVars::Uninit => interp_ok(()),
         }
     }
 
@@ -103,7 +104,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn get_env_var(&mut self, name: &OsStr) -> InterpResult<'tcx, Option<OsString>> {
         let this = self.eval_context_ref();
         match &this.machine.env_vars {
-            EnvVars::Uninit => return Ok(None),
+            EnvVars::Uninit => interp_ok(None),
             EnvVars::Unix(vars) => vars.get(this, name),
             EnvVars::Windows(vars) => vars.get(name),
         }
diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs
index 788de8162cb..5559ea2750b 100644
--- a/src/tools/miri/src/shims/extern_static.rs
+++ b/src/tools/miri/src/shims/extern_static.rs
@@ -11,7 +11,7 @@ impl<'tcx> MiriMachine<'tcx> {
         let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?;
         this.write_immediate(*val, &place)?;
         Self::add_extern_static(this, name, place.ptr());
-        Ok(())
+        interp_ok(())
     }
 
     /// Zero-initialized pointer-sized extern statics are pretty common.
@@ -26,7 +26,7 @@ impl<'tcx> MiriMachine<'tcx> {
             let val = ImmTy::from_int(0, this.machine.layouts.usize);
             Self::alloc_extern_static(this, name, val)?;
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Extern statics that are initialized with function pointers to the symbols of the same name.
@@ -41,7 +41,7 @@ impl<'tcx> MiriMachine<'tcx> {
             let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout);
             Self::alloc_extern_static(this, name, val)?;
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// Sets up the "extern statics" for this machine.
@@ -87,6 +87,6 @@ impl<'tcx> MiriMachine<'tcx> {
             }
             _ => {} // No "extern statics" supported on this target
         }
-        Ok(())
+        interp_ok(())
     }
 }
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 11cb9740e3e..78b07f68b44 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -1,21 +1,22 @@
-use std::{collections::hash_map::Entry, io::Write, iter, path::Path};
+use std::collections::hash_map::Entry;
+use std::io::Write;
+use std::iter;
+use std::path::Path;
 
 use rustc_apfloat::Float;
 use rustc_ast::expand::allocator::alloc_error_handler_name;
-use rustc_hir::{def::DefKind, def_id::CrateNum};
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::CrateNum;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::mir;
-use rustc_middle::ty;
+use rustc_middle::{mir, ty};
 use rustc_span::Symbol;
-use rustc_target::{
-    abi::{Align, AlignFromBytesError, Size},
-    spec::abi::Abi,
-};
+use rustc_target::abi::{Align, AlignFromBytesError, Size};
+use rustc_target::spec::abi::Abi;
 
+use self::helpers::{ToHost, ToSoft};
 use super::alloc::EvalContextExt as _;
 use super::backtrace::EvalContextExt as _;
 use crate::*;
-use self::helpers::{ToHost, ToSoft};
 
 /// Type of dynamic symbols (for `dlsym` et al)
 #[derive(Debug, Copy, Clone)]
@@ -61,7 +62,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let handler = this
                     .lookup_exported_symbol(Symbol::intern(name))?
                     .expect("missing alloc error handler symbol");
-                return Ok(Some(handler));
+                return interp_ok(Some(handler));
             }
             _ => {}
         }
@@ -79,18 +80,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             EmulateItemResult::AlreadyJumped => (),
             EmulateItemResult::NotSupported => {
                 if let Some(body) = this.lookup_exported_symbol(link_name)? {
-                    return Ok(Some(body));
+                    return interp_ok(Some(body));
                 }
 
                 this.handle_unsupported_foreign_item(format!(
                     "can't call foreign function `{link_name}` on OS `{os}`",
                     os = this.tcx.sess.target.os,
                 ))?;
-                return Ok(None);
+                return interp_ok(None);
             }
         }
 
-        Ok(None)
+        interp_ok(None)
     }
 
     fn is_dyn_sym(&self, name: &str) -> bool {
@@ -115,7 +116,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx> {
         let res = self.emulate_foreign_item(sym.0, abi, args, dest, ret, unwind)?;
         assert!(res.is_none(), "DynSyms that delegate are not supported");
-        Ok(())
+        interp_ok(())
     }
 
     /// Lookup the body of a function that has `link_name` as the symbol name.
@@ -142,7 +143,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         tcx.item_name(def_id)
                     } else {
                         // Skip over items without an explicitly defined symbol name.
-                        return Ok(());
+                        return interp_ok(());
                     };
                     if symbol_name == link_name {
                         if let Some((original_instance, original_cnum)) = instance_and_crate {
@@ -174,15 +175,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         }
                         instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum));
                     }
-                    Ok(())
+                    interp_ok(())
                 })?;
 
                 e.insert(instance_and_crate.map(|ic| ic.0))
             }
         };
         match instance {
-            None => Ok(None), // no symbol with this name
-            Some(instance) => Ok(Some((this.load_mir(instance.def, None)?, instance))),
+            None => interp_ok(None), // no symbol with this name
+            Some(instance) => interp_ok(Some((this.load_mir(instance.def, None)?, instance))),
         }
     }
 }
@@ -213,7 +214,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     fn emulate_foreign_item_inner(
@@ -233,7 +234,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // by the specified `.so` file; we should continue and check if it corresponds to
             // a provided shim.
             if this.call_native_fn(link_name, dest, args)? {
-                return Ok(EmulateItemResult::NeedsReturn);
+                return interp_ok(EmulateItemResult::NeedsReturn);
             }
         }
 
@@ -267,7 +268,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
         //
         //     // ...
         //
-        //     Ok(Scalar::from_u32(42))
+        //     interp_ok(Scalar::from_u32(42))
         // }
         // ```
         // You might find existing shims not following this pattern, most
@@ -280,7 +281,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "miri_start_unwind" => {
                 let [payload] = this.check_shim(abi, Abi::Rust, link_name, args)?;
                 this.handle_miri_start_unwind(payload)?;
-                return Ok(EmulateItemResult::NeedsUnwind);
+                return interp_ok(EmulateItemResult::NeedsUnwind);
             }
             "miri_run_provenance_gc" => {
                 let [] = this.check_shim(abi, Abi::Rust, link_name, args)?;
@@ -293,6 +294,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     err_machine_stop!(TerminationInfo::Abort(format!(
                         "pointer passed to `miri_get_alloc_id` must not be dangling, got {ptr:?}"
                     )))
+                    .into()
                 })?;
                 this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?;
             }
@@ -523,7 +525,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     "__rust_alloc" => return this.emulate_allocator(default),
                     "miri_alloc" => {
                         default(this)?;
-                        return Ok(EmulateItemResult::NeedsReturn);
+                        return interp_ok(EmulateItemResult::NeedsReturn);
                     }
                     _ => unreachable!(),
                 }
@@ -583,7 +585,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     }
                     "miri_dealloc" => {
                         default(this)?;
-                        return Ok(EmulateItemResult::NeedsReturn);
+                        return interp_ok(EmulateItemResult::NeedsReturn);
                     }
                     _ => unreachable!(),
                 }
@@ -999,11 +1001,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_inner(
                             this, link_name, abi, args, dest,
                         ),
-                    _ => Ok(EmulateItemResult::NotSupported),
+                    _ => interp_ok(EmulateItemResult::NotSupported),
                 },
         };
         // We only fall through to here if we did *not* hit the `_` arm above,
         // i.e., if we actually emulated the function with one of the shims.
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs
new file mode 100644
index 00000000000..38aa181cb4f
--- /dev/null
+++ b/src/tools/miri/src/shims/io_error.rs
@@ -0,0 +1,228 @@
+use std::io;
+
+use crate::*;
+
+/// A representation of an IO error: either a libc error name,
+/// or a host error.
+#[derive(Debug)]
+pub enum IoError {
+    LibcError(&'static str),
+    HostError(io::Error),
+    Raw(Scalar),
+}
+pub use self::IoError::*;
+
+impl From<io::Error> for IoError {
+    fn from(value: io::Error) -> Self {
+        IoError::HostError(value)
+    }
+}
+
+impl From<io::ErrorKind> for IoError {
+    fn from(value: io::ErrorKind) -> Self {
+        IoError::HostError(value.into())
+    }
+}
+
+impl From<Scalar> for IoError {
+    fn from(value: Scalar) -> Self {
+        IoError::Raw(value)
+    }
+}
+
+// This mapping should match `decode_error_kind` in
+// <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/pal/unix/mod.rs>.
+const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = {
+    use std::io::ErrorKind::*;
+    &[
+        ("E2BIG", ArgumentListTooLong),
+        ("EADDRINUSE", AddrInUse),
+        ("EADDRNOTAVAIL", AddrNotAvailable),
+        ("EBUSY", ResourceBusy),
+        ("ECONNABORTED", ConnectionAborted),
+        ("ECONNREFUSED", ConnectionRefused),
+        ("ECONNRESET", ConnectionReset),
+        ("EDEADLK", Deadlock),
+        ("EDQUOT", FilesystemQuotaExceeded),
+        ("EEXIST", AlreadyExists),
+        ("EFBIG", FileTooLarge),
+        ("EHOSTUNREACH", HostUnreachable),
+        ("EINTR", Interrupted),
+        ("EINVAL", InvalidInput),
+        ("EISDIR", IsADirectory),
+        ("ELOOP", FilesystemLoop),
+        ("ENOENT", NotFound),
+        ("ENOMEM", OutOfMemory),
+        ("ENOSPC", StorageFull),
+        ("ENOSYS", Unsupported),
+        ("EMLINK", TooManyLinks),
+        ("ENAMETOOLONG", InvalidFilename),
+        ("ENETDOWN", NetworkDown),
+        ("ENETUNREACH", NetworkUnreachable),
+        ("ENOTCONN", NotConnected),
+        ("ENOTDIR", NotADirectory),
+        ("ENOTEMPTY", DirectoryNotEmpty),
+        ("EPIPE", BrokenPipe),
+        ("EROFS", ReadOnlyFilesystem),
+        ("ESPIPE", NotSeekable),
+        ("ESTALE", StaleNetworkFileHandle),
+        ("ETIMEDOUT", TimedOut),
+        ("ETXTBSY", ExecutableFileBusy),
+        ("EXDEV", CrossesDevices),
+        // The following have two valid options. We have both for the forwards mapping; only the
+        // first one will be used for the backwards mapping.
+        ("EPERM", PermissionDenied),
+        ("EACCES", PermissionDenied),
+        ("EWOULDBLOCK", WouldBlock),
+        ("EAGAIN", WouldBlock),
+    ]
+};
+// This mapping should match `decode_error_kind` in
+// <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/pal/windows/mod.rs>.
+const WINDOWS_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = {
+    use std::io::ErrorKind::*;
+    // FIXME: this is still incomplete.
+    &[
+        ("ERROR_ACCESS_DENIED", PermissionDenied),
+        ("ERROR_FILE_NOT_FOUND", NotFound),
+        ("ERROR_INVALID_PARAMETER", InvalidInput),
+    ]
+};
+
+impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
+pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
+    /// Get last error variable as a place, lazily allocating thread-local storage for it if
+    /// necessary.
+    fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
+        let this = self.eval_context_mut();
+        if let Some(errno_place) = this.active_thread_ref().last_error.as_ref() {
+            interp_ok(errno_place.clone())
+        } else {
+            // Allocate new place, set initial value to 0.
+            let errno_layout = this.machine.layouts.u32;
+            let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into())?;
+            this.write_scalar(Scalar::from_u32(0), &errno_place)?;
+            this.active_thread_mut().last_error = Some(errno_place.clone());
+            interp_ok(errno_place)
+        }
+    }
+
+    /// Sets the last error variable.
+    fn set_last_error(&mut self, err: impl Into<IoError>) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let errno = match err.into() {
+            HostError(err) => this.io_error_to_errnum(err)?,
+            LibcError(name) => this.eval_libc(name),
+            Raw(val) => val,
+        };
+        let errno_place = this.last_error_place()?;
+        this.write_scalar(errno, &errno_place)
+    }
+
+    /// Sets the last OS error and writes -1 to dest place.
+    fn set_last_error_and_return(
+        &mut self,
+        err: impl Into<IoError>,
+        dest: &MPlaceTy<'tcx>,
+    ) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        this.set_last_error(err)?;
+        this.write_int(-1, dest)?;
+        interp_ok(())
+    }
+
+    /// Sets the last OS error and return `-1` as a `i32`-typed Scalar
+    fn set_last_error_and_return_i32(
+        &mut self,
+        err: impl Into<IoError>,
+    ) -> InterpResult<'tcx, Scalar> {
+        let this = self.eval_context_mut();
+        this.set_last_error(err)?;
+        interp_ok(Scalar::from_i32(-1))
+    }
+
+    /// Gets the last error variable.
+    fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> {
+        let this = self.eval_context_mut();
+        let errno_place = this.last_error_place()?;
+        this.read_scalar(&errno_place)
+    }
+
+    /// This function tries to produce the most similar OS error from the `std::io::ErrorKind`
+    /// as a platform-specific errnum.
+    fn io_error_to_errnum(&self, err: std::io::Error) -> InterpResult<'tcx, Scalar> {
+        let this = self.eval_context_ref();
+        let target = &this.tcx.sess.target;
+        if target.families.iter().any(|f| f == "unix") {
+            for &(name, kind) in UNIX_IO_ERROR_TABLE {
+                if err.kind() == kind {
+                    return interp_ok(this.eval_libc(name));
+                }
+            }
+            throw_unsup_format!("unsupported io error: {err}")
+        } else if target.families.iter().any(|f| f == "windows") {
+            for &(name, kind) in WINDOWS_IO_ERROR_TABLE {
+                if err.kind() == kind {
+                    return interp_ok(this.eval_windows("c", name));
+                }
+            }
+            throw_unsup_format!("unsupported io error: {err}");
+        } else {
+            throw_unsup_format!(
+                "converting io::Error into errnum is unsupported for OS {}",
+                target.os
+            )
+        }
+    }
+
+    /// The inverse of `io_error_to_errnum`.
+    #[allow(clippy::needless_return)]
+    fn try_errnum_to_io_error(
+        &self,
+        errnum: Scalar,
+    ) -> InterpResult<'tcx, Option<std::io::ErrorKind>> {
+        let this = self.eval_context_ref();
+        let target = &this.tcx.sess.target;
+        if target.families.iter().any(|f| f == "unix") {
+            let errnum = errnum.to_i32()?;
+            for &(name, kind) in UNIX_IO_ERROR_TABLE {
+                if errnum == this.eval_libc_i32(name) {
+                    return interp_ok(Some(kind));
+                }
+            }
+            return interp_ok(None);
+        } else if target.families.iter().any(|f| f == "windows") {
+            let errnum = errnum.to_u32()?;
+            for &(name, kind) in WINDOWS_IO_ERROR_TABLE {
+                if errnum == this.eval_windows("c", name).to_u32()? {
+                    return interp_ok(Some(kind));
+                }
+            }
+            return interp_ok(None);
+        } else {
+            throw_unsup_format!(
+                "converting errnum into io::Error is unsupported for OS {}",
+                target.os
+            )
+        }
+    }
+
+    /// Helper function that consumes an `std::io::Result<T>` and returns an
+    /// `InterpResult<'tcx,T>::Ok` instead. In case the result is an error, this function returns
+    /// `Ok(-1)` and sets the last OS error accordingly.
+    ///
+    /// This function uses `T: From<i32>` instead of `i32` directly because some IO related
+    /// functions return different integer types (like `read`, that returns an `i64`).
+    fn try_unwrap_io_result<T: From<i32>>(
+        &mut self,
+        result: std::io::Result<T>,
+    ) -> InterpResult<'tcx, T> {
+        match result {
+            Ok(ok) => interp_ok(ok),
+            Err(e) => {
+                self.eval_context_mut().set_last_error(e)?;
+                interp_ok((-1).into())
+            }
+        }
+    }
+}
diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs
index a689ac2b378..b9317ac1a15 100644
--- a/src/tools/miri/src/shims/mod.rs
+++ b/src/tools/miri/src/shims/mod.rs
@@ -12,6 +12,7 @@ mod x86;
 pub mod env;
 pub mod extern_static;
 pub mod foreign_items;
+pub mod io_error;
 pub mod os_str;
 pub mod panic;
 pub mod time;
diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs
index e4998c37f3f..3f282017bb7 100644
--- a/src/tools/miri/src/shims/native_lib.rs
+++ b/src/tools/miri/src/shims/native_lib.rs
@@ -1,7 +1,8 @@
 //! Implements calling functions from a native library.
-use libffi::{high::call as ffi, low::CodePtr};
 use std::ops::Deref;
 
+use libffi::high::call as ffi;
+use libffi::low::CodePtr;
 use rustc_middle::ty::{self as ty, IntTy, UintTy};
 use rustc_span::Symbol;
 use rustc_target::abi::{Abi, HasDataLayout};
@@ -72,11 +73,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // have the output_type `Tuple([])`.
             ty::Tuple(t_list) if t_list.len() == 0 => {
                 unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) };
-                return Ok(ImmTy::uninit(dest.layout));
+                return interp_ok(ImmTy::uninit(dest.layout));
             }
             _ => throw_unsup_format!("unsupported return type for native call: {:?}", link_name),
         };
-        Ok(ImmTy::from_scalar(scalar, dest.layout))
+        interp_ok(ImmTy::from_scalar(scalar, dest.layout))
     }
 
     /// Get the pointer to the function of the specified name in the shared object file,
@@ -141,7 +142,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Some(ptr) => ptr,
             None => {
                 // Shared object file does not export this function -- try the shims next.
-                return Ok(false);
+                return interp_ok(false);
             }
         };
 
@@ -163,7 +164,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Call the function and store output, depending on return type in the function signature.
         let ret = this.call_native_with_args(link_name, dest, code_ptr, libffi_args)?;
         this.write_immediate(*ret, dest)?;
-        Ok(true)
+        interp_ok(true)
     }
 }
 
@@ -220,7 +221,7 @@ impl<'a> CArg {
 /// Extract the scalar value from the result of reading a scalar from the machine,
 /// and convert it to a `CArg`.
 fn imm_to_carg<'tcx>(v: ImmTy<'tcx>, cx: &impl HasDataLayout) -> InterpResult<'tcx, CArg> {
-    Ok(match v.layout.ty.kind() {
+    interp_ok(match v.layout.ty.kind() {
         // If the primitive provided can be converted to a type matching the type pattern
         // then create a `CArg` of this primitive value with the corresponding `CArg` constructor.
         // the ints
diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs
index a1be2ae8b58..7080edb26a5 100644
--- a/src/tools/miri/src/shims/os_str.rs
+++ b/src/tools/miri/src/shims/os_str.rs
@@ -1,11 +1,10 @@
 use std::borrow::Cow;
 use std::ffi::{OsStr, OsString};
-use std::path::{Path, PathBuf};
-
 #[cfg(unix)]
 use std::os::unix::ffi::{OsStrExt, OsStringExt};
 #[cfg(windows)]
 use std::os::windows::ffi::{OsStrExt, OsStringExt};
+use std::path::{Path, PathBuf};
 
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf;
@@ -20,14 +19,14 @@ pub enum PathConversion {
 
 #[cfg(unix)]
 pub fn bytes_to_os_str<'tcx>(bytes: &[u8]) -> InterpResult<'tcx, &OsStr> {
-    Ok(OsStr::from_bytes(bytes))
+    interp_ok(OsStr::from_bytes(bytes))
 }
 #[cfg(not(unix))]
 pub fn bytes_to_os_str<'tcx>(bytes: &[u8]) -> InterpResult<'tcx, &OsStr> {
     // We cannot use `from_encoded_bytes_unchecked` here since we can't trust `bytes`.
     let s = std::str::from_utf8(bytes)
         .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?;
-    Ok(OsStr::new(s))
+    interp_ok(OsStr::new(s))
 }
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
@@ -51,13 +50,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     {
         #[cfg(windows)]
         pub fn u16vec_to_osstring<'tcx>(u16_vec: Vec<u16>) -> InterpResult<'tcx, OsString> {
-            Ok(OsString::from_wide(&u16_vec[..]))
+            interp_ok(OsString::from_wide(&u16_vec[..]))
         }
         #[cfg(not(windows))]
         pub fn u16vec_to_osstring<'tcx>(u16_vec: Vec<u16>) -> InterpResult<'tcx, OsString> {
             let s = String::from_utf16(&u16_vec[..])
                 .map_err(|_| err_unsup_format!("{:?} is not a valid utf-16 string", u16_vec))?;
-            Ok(s.into())
+            interp_ok(s.into())
         }
 
         let u16_vec = self.eval_context_ref().read_wide_str(ptr)?;
@@ -88,7 +87,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx, (bool, u64)> {
         #[cfg(windows)]
         fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec<u16>> {
-            Ok(os_str.encode_wide().collect())
+            interp_ok(os_str.encode_wide().collect())
         }
         #[cfg(not(windows))]
         fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec<u16>> {
@@ -98,7 +97,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             os_str
                 .to_str()
                 .map(|s| s.encode_utf16().collect())
-                .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into())
+                .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str))
+                .into()
         }
 
         let u16_vec = os_str_to_u16vec(os_str)?;
@@ -110,7 +110,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 self.eval_context_mut().write_wide_str(truncated_data, ptr, size)?;
             assert!(written && written_len == size);
         }
-        Ok((written, size_needed))
+        interp_ok((written, size_needed))
     }
 
     /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what the
@@ -149,7 +149,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
         let (written, _) = self.write_os_str_to_c_str(os_str, arg_place.ptr(), size).unwrap();
         assert!(written);
-        Ok(arg_place.ptr())
+        interp_ok(arg_place.ptr())
     }
 
     /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of `u16`.
@@ -165,7 +165,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
         let (written, _) = self.write_os_str_to_wide_str(os_str, arg_place.ptr(), size).unwrap();
         assert!(written);
-        Ok(arg_place.ptr())
+        interp_ok(arg_place.ptr())
     }
 
     /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed.
@@ -176,7 +176,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_ref();
         let os_str = this.read_os_str_from_c_str(ptr)?;
 
-        Ok(match this.convert_path(Cow::Borrowed(os_str), PathConversion::TargetToHost) {
+        interp_ok(match this.convert_path(Cow::Borrowed(os_str), PathConversion::TargetToHost) {
             Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)),
             Cow::Owned(y) => Cow::Owned(PathBuf::from(y)),
         })
@@ -187,7 +187,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_ref();
         let os_str = this.read_os_str_from_wide_str(ptr)?;
 
-        Ok(this.convert_path(Cow::Owned(os_str), PathConversion::TargetToHost).into_owned().into())
+        interp_ok(
+            this.convert_path(Cow::Owned(os_str), PathConversion::TargetToHost).into_owned().into(),
+        )
     }
 
     /// Write a Path to the machine memory (as a null-terminated sequence of bytes),
diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs
index 52c4394591c..9bb0d7d0ce6 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -16,8 +16,8 @@ use rustc_middle::{mir, ty};
 use rustc_target::spec::PanicStrategy;
 use rustc_target::spec::abi::Abi;
 
-use crate::*;
 use self::helpers::check_arg_count;
+use crate::*;
 
 /// Holds all of the relevant data for when unwinding hits a `try` frame.
 #[derive(Debug)]
@@ -54,7 +54,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let thread = this.active_thread_mut();
         thread.panic_payloads.push(payload);
 
-        Ok(())
+        interp_ok(())
     }
 
     /// Handles the `try` intrinsic, the underlying implementation of `std::panicking::try`.
@@ -106,7 +106,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 Some(CatchUnwindData { catch_fn, data, dest: dest.clone(), ret });
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     fn handle_stack_pop_unwind(
@@ -150,9 +150,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             )?;
 
             // We pushed a new stack frame, the engine should not do any jumping now!
-            Ok(ReturnAction::NoJump)
+            interp_ok(ReturnAction::NoJump)
         } else {
-            Ok(ReturnAction::Normal)
+            interp_ok(ReturnAction::Normal)
         }
     }
 
@@ -254,6 +254,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 })?;
             }
         }
-        Ok(())
+        interp_ok(())
     }
 }
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index ebec1a70c5c..12c7679608d 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -11,7 +11,8 @@ use crate::*;
 /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`.
 pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> {
     time.duration_since(SystemTime::UNIX_EPOCH)
-        .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported").into())
+        .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported"))
+        .into()
 }
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
@@ -36,8 +37,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let mut relative_clocks;
 
         match this.tcx.sess.target.os.as_ref() {
-            "linux" | "freebsd" => {
-                // Linux and FreeBSD have two main kinds of clocks. REALTIME clocks return the actual time since the
+            "linux" | "freebsd" | "android" => {
+                // Linux, Android, and FreeBSD have two main kinds of clocks. REALTIME clocks return the actual time since the
                 // Unix epoch, including effects which may cause time to move backwards such as NTP.
                 // Linux further distinguishes regular and "coarse" clocks, but the "coarse" version
                 // is just specified to be "faster and less precise", so we implement both the same way.
@@ -82,7 +83,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         } else {
             let einval = this.eval_libc("EINVAL");
             this.set_last_error(einval)?;
-            return Ok(Scalar::from_i32(-1));
+            return interp_ok(Scalar::from_i32(-1));
         };
 
         let tv_sec = duration.as_secs();
@@ -90,7 +91,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         this.write_int_fields(&[tv_sec.into(), tv_nsec.into()], &tp)?;
 
-        Ok(Scalar::from_i32(0))
+        interp_ok(Scalar::from_i32(0))
     }
 
     fn gettimeofday(
@@ -110,7 +111,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if !this.ptr_is_null(tz)? {
             let einval = this.eval_libc("EINVAL");
             this.set_last_error(einval)?;
-            return Ok(Scalar::from_i32(-1));
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         let duration = system_time_to_duration(&SystemTime::now())?;
@@ -119,7 +120,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         this.write_int_fields(&[tv_sec.into(), tv_usec.into()], &tv)?;
 
-        Ok(Scalar::from_i32(0))
+        interp_ok(Scalar::from_i32(0))
     }
 
     // The localtime() function shall convert the time in seconds since the Epoch pointed to by
@@ -206,7 +207,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.write_pointer(tm_zone_ptr, &this.project_field_named(&result, "tm_zone")?)?;
             this.write_int_fields_named(&[("tm_gmtoff", tm_gmtoff.into())], &result)?;
         }
-        Ok(result.ptr())
+        interp_ok(result.ptr())
     }
     #[allow(non_snake_case, clippy::arithmetic_side_effects)]
     fn GetSystemTimeAsFileTime(
@@ -236,7 +237,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap();
         this.write_int_fields(&[dwLowDateTime.into(), dwHighDateTime.into()], &filetime)?;
 
-        Ok(())
+        interp_ok(())
     }
 
     #[allow(non_snake_case)]
@@ -255,7 +256,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported")
         })?;
         this.write_scalar(Scalar::from_i64(qpc), &this.deref_pointer(lpPerformanceCount_op)?)?;
-        Ok(Scalar::from_i32(-1)) // return non-zero on success
+        interp_ok(Scalar::from_i32(-1)) // return non-zero on success
     }
 
     #[allow(non_snake_case)]
@@ -276,7 +277,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Scalar::from_i64(1_000_000_000),
             &this.deref_pointer_as(lpFrequency_op, this.machine.layouts.u64)?,
         )?;
-        Ok(Scalar::from_i32(-1)) // Return non-zero on success
+        interp_ok(Scalar::from_i32(-1)) // Return non-zero on success
     }
 
     fn mach_absolute_time(&self) -> InterpResult<'tcx, Scalar> {
@@ -290,7 +291,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let res = u64::try_from(duration.as_nanos()).map_err(|_| {
             err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported")
         })?;
-        Ok(Scalar::from_u64(res))
+        interp_ok(Scalar::from_u64(res))
     }
 
     fn mach_timebase_info(&mut self, info_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@@ -305,7 +306,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let (numer, denom) = (1, 1);
         this.write_int_fields(&[numer.into(), denom.into()], &info)?;
 
-        Ok(Scalar::from_i32(0)) // KERN_SUCCESS
+        interp_ok(Scalar::from_i32(0)) // KERN_SUCCESS
     }
 
     fn nanosleep(
@@ -324,7 +325,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             None => {
                 let einval = this.eval_libc("EINVAL");
                 this.set_last_error(einval)?;
-                return Ok(Scalar::from_i32(-1));
+                return interp_ok(Scalar::from_i32(-1));
             }
         };
 
@@ -334,10 +335,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             callback!(
                 @capture<'tcx> {}
                 @unblock = |_this| { panic!("sleeping thread unblocked before time is up") }
-                @timeout = |_this| { Ok(()) }
+                @timeout = |_this| { interp_ok(()) }
             ),
         );
-        Ok(Scalar::from_i32(0))
+        interp_ok(Scalar::from_i32(0))
     }
 
     #[allow(non_snake_case)]
@@ -356,9 +357,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             callback!(
                 @capture<'tcx> {}
                 @unblock = |_this| { panic!("sleeping thread unblocked before time is up") }
-                @timeout = |_this| { Ok(()) }
+                @timeout = |_this| { interp_ok(()) }
             ),
         );
-        Ok(())
+        interp_ok(())
     }
 }
diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs
index b3ea7098dfe..94b2d1bc782 100644
--- a/src/tools/miri/src/shims/tls.rs
+++ b/src/tools/miri/src/shims/tls.rs
@@ -68,14 +68,14 @@ impl<'tcx> TlsData<'tcx> {
         if max_size.bits() < 128 && new_key >= (1u128 << max_size.bits()) {
             throw_unsup_format!("we ran out of TLS key space");
         }
-        Ok(new_key)
+        interp_ok(new_key)
     }
 
     pub fn delete_tls_key(&mut self, key: TlsKey) -> InterpResult<'tcx> {
         match self.keys.remove(&key) {
             Some(_) => {
                 trace!("TLS key {} removed", key);
-                Ok(())
+                interp_ok(())
             }
             None => throw_ub_format!("removing a nonexistent TLS key: {}", key),
         }
@@ -91,7 +91,7 @@ impl<'tcx> TlsData<'tcx> {
             Some(TlsEntry { data, .. }) => {
                 let value = data.get(&thread_id).copied();
                 trace!("TLS key {} for thread {:?} loaded: {:?}", key, thread_id, value);
-                Ok(value.unwrap_or_else(|| Scalar::null_ptr(cx)))
+                interp_ok(value.unwrap_or_else(|| Scalar::null_ptr(cx)))
             }
             None => throw_ub_format!("loading from a non-existing TLS key: {}", key),
         }
@@ -113,7 +113,7 @@ impl<'tcx> TlsData<'tcx> {
                     trace!("TLS key {} for thread {:?} removed", key, thread_id);
                     data.remove(&thread_id);
                 }
-                Ok(())
+                interp_ok(())
             }
             None => throw_ub_format!("storing to a non-existing TLS key: {}", key),
         }
@@ -128,7 +128,7 @@ impl<'tcx> TlsData<'tcx> {
         data: Scalar,
     ) -> InterpResult<'tcx> {
         self.macos_thread_dtors.entry(thread).or_default().push((dtor, data));
-        Ok(())
+        interp_ok(())
     }
 
     /// Returns a dtor, its argument and its index, if one is supposed to run.
@@ -261,7 +261,7 @@ impl<'tcx> TlsDtorsState<'tcx> {
                 }
                 MacOsDtors => {
                     match this.schedule_macos_tls_dtor()? {
-                        Poll::Pending => return Ok(Poll::Pending),
+                        Poll::Pending => return interp_ok(Poll::Pending),
                         // After all macOS destructors are run, the system switches
                         // to destroying the pthread destructors.
                         Poll::Ready(()) => break 'new_state PthreadDtors(Default::default()),
@@ -269,14 +269,14 @@ impl<'tcx> TlsDtorsState<'tcx> {
                 }
                 PthreadDtors(state) => {
                     match this.schedule_next_pthread_tls_dtor(state)? {
-                        Poll::Pending => return Ok(Poll::Pending), // just keep going
+                        Poll::Pending => return interp_ok(Poll::Pending), // just keep going
                         Poll::Ready(()) => break 'new_state Done,
                     }
                 }
                 WindowsDtors(dtors) => {
                     if let Some(dtor) = dtors.pop() {
                         this.schedule_windows_tls_dtor(dtor)?;
-                        return Ok(Poll::Pending); // we stay in this state (but `dtors` got shorter)
+                        return interp_ok(Poll::Pending); // we stay in this state (but `dtors` got shorter)
                     } else {
                         // No more destructors to run.
                         break 'new_state Done;
@@ -284,13 +284,13 @@ impl<'tcx> TlsDtorsState<'tcx> {
                 }
                 Done => {
                     this.machine.tls.delete_all_thread_tls(this.active_thread());
-                    return Ok(Poll::Ready(()));
+                    return interp_ok(Poll::Ready(()));
                 }
             }
         };
 
         self.0 = new_state;
-        Ok(Poll::Pending)
+        interp_ok(Poll::Pending)
     }
 }
 
@@ -303,7 +303,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // Windows has a special magic linker section that is run on certain events.
         // We don't support most of that, but just enough to make thread-local dtors in `std` work.
-        Ok(this.lookup_link_section(".CRT$XLB")?)
+        interp_ok(this.lookup_link_section(".CRT$XLB")?)
     }
 
     fn schedule_windows_tls_dtor(&mut self, dtor: ImmTy<'tcx>) -> InterpResult<'tcx> {
@@ -328,7 +328,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             None,
             StackPopCleanup::Root { cleanup: true },
         )?;
-        Ok(())
+        interp_ok(())
     }
 
     /// Schedule the macOS thread local storage destructors to be executed.
@@ -350,10 +350,10 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 StackPopCleanup::Root { cleanup: true },
             )?;
 
-            return Ok(Poll::Pending);
+            return interp_ok(Poll::Pending);
         }
 
-        Ok(Poll::Ready(()))
+        interp_ok(Poll::Ready(()))
     }
 
     /// Schedule a pthread TLS destructor. Returns `true` if found
@@ -387,9 +387,9 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 StackPopCleanup::Root { cleanup: true },
             )?;
 
-            return Ok(Poll::Pending);
+            return interp_ok(Poll::Pending);
         }
 
-        Ok(Poll::Ready(()))
+        interp_ok(Poll::Ready(()))
     }
 }
diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs
index 42552a51eda..583a1f65009 100644
--- a/src/tools/miri/src/shims/unix/android/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs
@@ -25,8 +25,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
             }
 
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs
index 324607cc1ed..96c5a9fad9b 100644
--- a/src/tools/miri/src/shims/unix/env.rs
+++ b/src/tools/miri/src/shims/unix/env.rs
@@ -1,7 +1,6 @@
-use std::env;
 use std::ffi::{OsStr, OsString};
 use std::io::ErrorKind;
-use std::mem;
+use std::{env, mem};
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::ty::Ty;
@@ -48,7 +47,7 @@ impl<'tcx> UnixEnvVars<'tcx> {
         let environ_block = alloc_environ_block(ecx, env_vars_machine.values().copied().collect())?;
         ecx.write_pointer(environ_block, &environ)?;
 
-        Ok(UnixEnvVars { map: env_vars_machine, environ })
+        interp_ok(UnixEnvVars { map: env_vars_machine, environ })
     }
 
     pub(crate) fn cleanup(ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>) -> InterpResult<'tcx> {
@@ -62,7 +61,7 @@ impl<'tcx> UnixEnvVars<'tcx> {
         let old_vars_ptr = ecx.read_pointer(environ)?;
         ecx.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?;
 
-        Ok(())
+        interp_ok(())
     }
 
     pub(crate) fn environ(&self) -> Pointer {
@@ -78,14 +77,14 @@ impl<'tcx> UnixEnvVars<'tcx> {
         // but we do want to do this read so it shows up as a data race.
         let _vars_ptr = ecx.read_pointer(&self.environ)?;
         let Some(var_ptr) = self.map.get(name) else {
-            return Ok(None);
+            return interp_ok(None);
         };
         // The offset is used to strip the "{name}=" part of the string.
         let var_ptr = var_ptr.wrapping_offset(
             Size::from_bytes(u64::try_from(name.len()).unwrap().strict_add(1)),
             ecx,
         );
-        Ok(Some(var_ptr))
+        interp_ok(Some(var_ptr))
     }
 
     /// Implementation detail for [`InterpCx::get_env_var`]. This basically does `getenv`, complete
@@ -98,9 +97,9 @@ impl<'tcx> UnixEnvVars<'tcx> {
         let var_ptr = self.get_ptr(ecx, name)?;
         if let Some(ptr) = var_ptr {
             let var = ecx.read_os_str_from_c_str(ptr)?;
-            Ok(Some(var.to_owned()))
+            interp_ok(Some(var.to_owned()))
         } else {
-            Ok(None)
+            interp_ok(None)
         }
     }
 }
@@ -134,7 +133,7 @@ fn alloc_environ_block<'tcx>(
         let place = ecx.project_field(&vars_place, idx)?;
         ecx.write_pointer(var, &place)?;
     }
-    Ok(vars_place.ptr())
+    interp_ok(vars_place.ptr())
 }
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
@@ -147,7 +146,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let name = this.read_os_str_from_c_str(name_ptr)?;
 
         let var_ptr = this.machine.env_vars.unix().get_ptr(this, name)?;
-        Ok(var_ptr.unwrap_or_else(Pointer::null))
+        interp_ok(var_ptr.unwrap_or_else(Pointer::null))
     }
 
     fn setenv(
@@ -175,12 +174,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
             }
             this.update_environ()?;
-            Ok(Scalar::from_i32(0)) // return zero on success
+            interp_ok(Scalar::from_i32(0)) // return zero on success
         } else {
             // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
-            let einval = this.eval_libc("EINVAL");
-            this.set_last_error(einval)?;
-            Ok(Scalar::from_i32(-1))
+            this.set_last_error_and_return_i32(LibcError("EINVAL"))
         }
     }
 
@@ -201,12 +198,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
             }
             this.update_environ()?;
-            Ok(Scalar::from_i32(0))
+            interp_ok(Scalar::from_i32(0))
         } else {
             // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
-            let einval = this.eval_libc("EINVAL");
-            this.set_last_error(einval)?;
-            Ok(Scalar::from_i32(-1))
+            this.set_last_error_and_return_i32(LibcError("EINVAL"))
         }
     }
 
@@ -219,23 +214,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`getcwd`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(Pointer::null());
+            this.set_last_error(ErrorKind::PermissionDenied)?;
+            return interp_ok(Pointer::null());
         }
 
         // If we cannot get the current directory, we return null
         match env::current_dir() {
             Ok(cwd) => {
                 if this.write_path_to_c_str(&cwd, buf, size)?.0 {
-                    return Ok(buf);
+                    return interp_ok(buf);
                 }
-                let erange = this.eval_libc("ERANGE");
-                this.set_last_error(erange)?;
+                this.set_last_error(LibcError("ERANGE"))?;
             }
-            Err(e) => this.set_last_error_from_io_error(e)?,
+            Err(e) => this.set_last_error(e)?,
         }
 
-        Ok(Pointer::null())
+        interp_ok(Pointer::null())
     }
 
     fn chdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@@ -246,13 +240,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`chdir`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-
-            return Ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
         }
 
         let result = env::set_current_dir(path).map(|()| 0);
-        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
+        interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     /// Updates the `environ` static.
@@ -268,7 +260,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let environ_block = alloc_environ_block(this, vals)?;
         this.write_pointer(environ_block, &environ)?;
 
-        Ok(())
+        interp_ok(())
     }
 
     fn getpid(&mut self) -> InterpResult<'tcx, Scalar> {
@@ -279,7 +271,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // `libc::getpid` returns an i32, however, `std::process::id()` return an u32.
         // So we un-do the conversion that stdlib does and turn it back into an i32.
         // In `Scalar` representation, these are the same, so we don't need to anything else.
-        Ok(Scalar::from_u32(this.get_pid()))
+        interp_ok(Scalar::from_u32(this.get_pid()))
     }
 
     fn linux_gettid(&mut self) -> InterpResult<'tcx, Scalar> {
@@ -291,6 +283,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Compute a TID for this thread, ensuring that the main thread has PID == TID.
         let tid = this.get_pid().strict_add(index);
 
-        Ok(Scalar::from_u32(tid))
+        interp_ok(Scalar::from_u32(tid))
     }
 }
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index 6b78ce7ad47..34e29760da7 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -5,8 +5,7 @@ use std::any::Any;
 use std::collections::BTreeMap;
 use std::io::{self, ErrorKind, IsTerminal, Read, SeekFrom, Write};
 use std::ops::Deref;
-use std::rc::Rc;
-use std::rc::Weak;
+use std::rc::{Rc, Weak};
 
 use rustc_target::abi::Size;
 
@@ -151,7 +150,10 @@ impl FileDescription for io::Stdin {
             helpers::isolation_abort_error("`read` from stdin")?;
         }
         let result = Read::read(&mut { self }, &mut bytes);
-        ecx.return_read_bytes_and_count(ptr, &bytes, result, dest)
+        match result {
+            Ok(read_size) => ecx.return_read_success(ptr, &bytes, read_size, dest),
+            Err(e) => ecx.set_last_error_and_return(e, dest),
+        }
     }
 
     fn is_tty(&self, communicate_allowed: bool) -> bool {
@@ -182,7 +184,10 @@ impl FileDescription for io::Stdout {
         // the host -- there is no good in adding extra buffering
         // here.
         io::stdout().flush().unwrap();
-        ecx.return_written_byte_count_or_error(result, dest)
+        match result {
+            Ok(write_size) => ecx.return_write_success(write_size, dest),
+            Err(e) => ecx.set_last_error_and_return(e, dest),
+        }
     }
 
     fn is_tty(&self, communicate_allowed: bool) -> bool {
@@ -208,7 +213,10 @@ impl FileDescription for io::Stderr {
         // We allow writing to stderr even with isolation enabled.
         // No need to flush, stderr is not buffered.
         let result = Write::write(&mut { self }, bytes);
-        ecx.return_written_byte_count_or_error(result, dest)
+        match result {
+            Ok(write_size) => ecx.return_write_success(write_size, dest),
+            Err(e) => ecx.set_last_error_and_return(e, dest),
+        }
     }
 
     fn is_tty(&self, communicate_allowed: bool) -> bool {
@@ -235,8 +243,7 @@ impl FileDescription for NullOutput {
         ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx> {
         // We just don't write anything, but report to the user that we did.
-        let result = Ok(len);
-        ecx.return_written_byte_count_or_error(result, dest)
+        ecx.return_write_success(len, dest)
     }
 }
 
@@ -278,7 +285,7 @@ impl FileDescriptionRef {
 
                 fd.file_description.close(communicate_allowed, ecx)
             }
-            None => Ok(Ok(())),
+            None => interp_ok(Ok(())),
         }
     }
 
@@ -415,16 +422,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         let Some(fd) = this.machine.fds.get(old_fd_num) else {
-            return Ok(Scalar::from_i32(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
         };
-        Ok(Scalar::from_i32(this.machine.fds.insert(fd)))
+        interp_ok(Scalar::from_i32(this.machine.fds.insert(fd)))
     }
 
     fn dup2(&mut self, old_fd_num: i32, new_fd_num: i32) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let Some(fd) = this.machine.fds.get(old_fd_num) else {
-            return Ok(Scalar::from_i32(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
         };
         if new_fd_num != old_fd_num {
             // Close new_fd if it is previously opened.
@@ -434,13 +441,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 old_new_fd.close(this.machine.communicate(), this)?.ok();
             }
         }
-        Ok(Scalar::from_i32(new_fd_num))
+        interp_ok(Scalar::from_i32(new_fd_num))
     }
 
     fn flock(&mut self, fd_num: i32, op: i32) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
         let Some(fd) = this.machine.fds.get(fd_num) else {
-            return Ok(Scalar::from_i32(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
         };
 
         // We need to check that there aren't unsupported options in `op`.
@@ -468,20 +475,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         drop(fd);
         // return `0` if flock is successful
         let result = result.map(|()| 0i32);
-        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
+        interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
-        if args.len() < 2 {
+        let [fd_num, cmd, ..] = args else {
             throw_ub_format!(
                 "incorrect number of arguments for fcntl: got {}, expected at least 2",
                 args.len()
             );
-        }
-        let fd_num = this.read_scalar(&args[0])?.to_i32()?;
-        let cmd = this.read_scalar(&args[1])?.to_i32()?;
+        };
+        let fd_num = this.read_scalar(fd_num)?.to_i32()?;
+        let cmd = this.read_scalar(cmd)?.to_i32()?;
 
         // We only support getting the flags for a descriptor.
         if cmd == this.eval_libc_i32("F_GETFD") {
@@ -489,7 +496,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
             // always sets this flag when opening a file. However we still need to check that the
             // file itself is open.
-            Ok(Scalar::from_i32(if this.machine.fds.is_fd_num(fd_num) {
+            interp_ok(Scalar::from_i32(if this.machine.fds.is_fd_num(fd_num) {
                 this.eval_libc_i32("FD_CLOEXEC")
             } else {
                 this.fd_not_found()?
@@ -501,24 +508,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only
             // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor,
             // thus they can share the same implementation here.
-            if args.len() < 3 {
+            let [_, _, start, ..] = args else {
                 throw_ub_format!(
                     "incorrect number of arguments for fcntl with cmd=`F_DUPFD`/`F_DUPFD_CLOEXEC`: got {}, expected at least 3",
                     args.len()
                 );
-            }
-            let start = this.read_scalar(&args[2])?.to_i32()?;
+            };
+            let start = this.read_scalar(start)?.to_i32()?;
 
             match this.machine.fds.get(fd_num) {
-                Some(fd) => Ok(Scalar::from_i32(this.machine.fds.insert_with_min_num(fd, start))),
-                None => Ok(Scalar::from_i32(this.fd_not_found()?)),
+                Some(fd) =>
+                    interp_ok(Scalar::from_i32(this.machine.fds.insert_with_min_num(fd, start))),
+                None => interp_ok(Scalar::from_i32(this.fd_not_found()?)),
             }
         } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") {
             // Reject if isolation is enabled.
             if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
                 this.reject_in_isolation("`fcntl`", reject_with)?;
-                this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-                return Ok(Scalar::from_i32(-1));
+                return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
             }
 
             this.ffullsync_fd(fd_num)
@@ -533,12 +540,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let fd_num = this.read_scalar(fd_op)?.to_i32()?;
 
         let Some(fd) = this.machine.fds.remove(fd_num) else {
-            return Ok(Scalar::from_i32(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
         };
         let result = fd.close(this.machine.communicate(), this)?;
         // return `0` if close is successful
         let result = result.map(|()| 0i32);
-        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
+        interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     /// Function used when a file descriptor does not exist. It returns `Ok(-1)`and sets
@@ -549,7 +556,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         let ebadf = this.eval_libc("EBADF");
         this.set_last_error(ebadf)?;
-        Ok((-1).into())
+        interp_ok((-1).into())
     }
 
     /// Read data from `fd` into buffer specified by `buf` and `count`.
@@ -587,7 +594,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             trace!("read: FD not found");
             let res: i32 = this.fd_not_found()?;
             this.write_int(res, dest)?;
-            return Ok(());
+            return interp_ok(());
         };
 
         trace!("read: FD mapped to {fd:?}");
@@ -599,15 +606,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             None => fd.read(&fd, communicate, buf, count, dest, this)?,
             Some(offset) => {
                 let Ok(offset) = u64::try_from(offset) else {
-                    let einval = this.eval_libc("EINVAL");
-                    this.set_last_error(einval)?;
-                    this.write_int(-1, dest)?;
-                    return Ok(());
+                    return this.set_last_error_and_return(LibcError("EINVAL"), dest);
                 };
                 fd.pread(communicate, offset, buf, count, dest, this)?
             }
         };
-        Ok(())
+        interp_ok(())
     }
 
     fn write(
@@ -637,65 +641,55 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let Some(fd) = this.machine.fds.get(fd_num) else {
             let res: i32 = this.fd_not_found()?;
             this.write_int(res, dest)?;
-            return Ok(());
+            return interp_ok(());
         };
 
         match offset {
             None => fd.write(&fd, communicate, buf, count, dest, this)?,
             Some(offset) => {
                 let Ok(offset) = u64::try_from(offset) else {
-                    let einval = this.eval_libc("EINVAL");
-                    this.set_last_error(einval)?;
-                    this.write_int(-1, dest)?;
-                    return Ok(());
+                    return this.set_last_error_and_return(LibcError("EINVAL"), dest);
                 };
                 fd.pwrite(communicate, buf, count, offset, dest, this)?
             }
         };
-        Ok(())
+        interp_ok(())
     }
 
     /// Helper to implement `FileDescription::read`:
-    /// `result` should be the return value of some underlying `read` call that used `bytes` as its output buffer.
+    /// This is only used when `read` is successful.
+    /// `actual_read_size` should be the return value of some underlying `read` call that used
+    /// `bytes` as its output buffer.
     /// The length of `bytes` must not exceed either the host's or the target's `isize`.
-    /// If `Result` indicates success, `bytes` is written to `buf` and the size is written to `dest`.
-    /// Otherwise, `-1` is written to `dest` and the last libc error is set appropriately.
-    fn return_read_bytes_and_count(
+    /// `bytes` is written to `buf` and the size is written to `dest`.
+    fn return_read_success(
         &mut self,
         buf: Pointer,
         bytes: &[u8],
-        result: io::Result<usize>,
+        actual_read_size: usize,
         dest: &MPlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        match result {
-            Ok(read_bytes) => {
-                // If reading to `bytes` did not fail, we write those bytes to the buffer.
-                // Crucially, if fewer than `bytes.len()` bytes were read, only write
-                // that much into the output buffer!
-                this.write_bytes_ptr(buf, bytes[..read_bytes].iter().copied())?;
-                // The actual read size is always less than what got originally requested so this cannot fail.
-                this.write_int(u64::try_from(read_bytes).unwrap(), dest)?;
-                return Ok(());
-            }
-            Err(e) => {
-                this.set_last_error_from_io_error(e)?;
-                this.write_int(-1, dest)?;
-                return Ok(());
-            }
-        }
+        // If reading to `bytes` did not fail, we write those bytes to the buffer.
+        // Crucially, if fewer than `bytes.len()` bytes were read, only write
+        // that much into the output buffer!
+        this.write_bytes_ptr(buf, bytes[..actual_read_size].iter().copied())?;
+
+        // The actual read size is always less than what got originally requested so this cannot fail.
+        this.write_int(u64::try_from(actual_read_size).unwrap(), dest)?;
+        interp_ok(())
     }
 
-    /// This function writes the number of written bytes (given in `result`) to `dest`, or sets the
-    /// last libc error and writes -1 to dest.
-    fn return_written_byte_count_or_error(
+    /// Helper to implement `FileDescription::write`:
+    /// This function is only used when `write` is successful, and writes `actual_write_size` to `dest`
+    fn return_write_success(
         &mut self,
-        result: io::Result<usize>,
+        actual_write_size: usize,
         dest: &MPlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        let result = this.try_unwrap_io_result(result.map(|c| i64::try_from(c).unwrap()))?;
-        this.write_int(result, dest)?;
-        Ok(())
+        // The actual write size is always less than what got originally requested so this cannot fail.
+        this.write_int(u64::try_from(actual_write_size).unwrap(), dest)?;
+        interp_ok(())
     }
 }
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index c06ce57e610..908f91a3bd6 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -6,16 +6,15 @@ use rustc_span::Symbol;
 use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
 
-use crate::concurrency::cpu_affinity::CpuAffinityMask;
-use crate::shims::alloc::EvalContextExt as _;
-use crate::shims::unix::*;
-use crate::*;
-
 use self::shims::unix::android::foreign_items as android;
 use self::shims::unix::freebsd::foreign_items as freebsd;
 use self::shims::unix::linux::foreign_items as linux;
 use self::shims::unix::macos::foreign_items as macos;
 use self::shims::unix::solarish::foreign_items as solarish;
+use crate::concurrency::cpu_affinity::CpuAffinityMask;
+use crate::shims::alloc::EvalContextExt as _;
+use crate::shims::unix::*;
+use crate::*;
 
 pub fn is_dyn_sym(name: &str, target_os: &str) -> bool {
     match name {
@@ -356,8 +355,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=reallocarray
                 match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) {
                     None => {
-                        let einval = this.eval_libc("ENOMEM");
-                        this.set_last_error(einval)?;
+                        let enmem = this.eval_libc("ENOMEM");
+                        this.set_last_error(enmem)?;
                         this.write_null(dest)?;
                     }
                     Some(len) => {
@@ -647,13 +646,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let chunk_size = CpuAffinityMask::chunk_size(this);
 
                 if this.ptr_is_null(mask)? {
-                    let einval = this.eval_libc("EFAULT");
-                    this.set_last_error(einval)?;
+                    let efault = this.eval_libc("EFAULT");
+                    this.set_last_error(efault)?;
                     this.write_int(-1, dest)?;
                 } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
                     // we only copy whole chunks of size_of::<c_ulong>()
-                    let einval = this.eval_libc("EINVAL");
-                    this.set_last_error(einval)?;
+                    this.set_last_error(LibcError("EINVAL"))?;
                     this.write_int(-1, dest)?;
                 } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
                     let cpuset = cpuset.clone();
@@ -663,8 +661,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     this.write_null(dest)?;
                 } else {
                     // The thread whose ID is pid could not be found
-                    let einval = this.eval_libc("ESRCH");
-                    this.set_last_error(einval)?;
+                    let esrch = this.eval_libc("ESRCH");
+                    this.set_last_error(esrch)?;
                     this.write_int(-1, dest)?;
                 }
             }
@@ -690,8 +688,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 };
 
                 if this.ptr_is_null(mask)? {
-                    let einval = this.eval_libc("EFAULT");
-                    this.set_last_error(einval)?;
+                    let efault = this.eval_libc("EFAULT");
+                    this.set_last_error(efault)?;
                     this.write_int(-1, dest)?;
                 } else {
                     // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`.
@@ -708,8 +706,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         }
                         None => {
                             // The intersection between the mask and the available CPUs was empty.
-                            let einval = this.eval_libc("EINVAL");
-                            this.set_last_error(einval)?;
+                            this.set_last_error(LibcError("EINVAL"))?;
                             this.write_int(-1, dest)?;
                         }
                     }
@@ -792,6 +789,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.gen_random(ptr, len)?;
                 this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
             }
+            "arc4random_buf" => {
+                // This function is non-standard but exists with the same signature and
+                // same behavior (eg never fails) on FreeBSD and Solaris/Illumos.
+                if !matches!(&*this.tcx.sess.target.os, "freebsd" | "illumos" | "solaris") {
+                    throw_unsup_format!(
+                        "`arc4random_buf` is not supported on {}",
+                        this.tcx.sess.target.os
+                    );
+                }
+                let [ptr, len] = this.check_shim(abi, Abi::C { unwind: false}, link_name, args)?;
+                let ptr = this.read_pointer(ptr)?;
+                let len = this.read_target_usize(len)?;
+                this.gen_random(ptr, len)?;
+            }
             "_Unwind_RaiseException" => {
                 // This is not formally part of POSIX, but it is very wide-spread on POSIX systems.
                 // It was originally specified as part of the Itanium C++ ABI:
@@ -815,7 +826,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // This function looks and behaves excatly like miri_start_unwind.
                 let [payload] = this.check_shim(abi, Abi::C { unwind: true }, link_name, args)?;
                 this.handle_miri_start_unwind(payload)?;
-                return Ok(EmulateItemResult::NeedsUnwind);
+                return interp_ok(EmulateItemResult::NeedsUnwind);
             }
             "getuid" => {
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -931,11 +942,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     "linux" => linux::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
                     "macos" => macos::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
                     "solaris" | "illumos" => solarish::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
-                    _ => Ok(EmulateItemResult::NotSupported),
+                    _ => interp_ok(EmulateItemResult::NotSupported),
                 };
             }
         };
 
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
index 36f25767a8e..e89dd488a2f 100644
--- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
@@ -84,8 +84,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_null(dest)?;
             }
 
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index c90839138ce..6c9a2beac2d 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -11,13 +11,12 @@ use std::time::SystemTime;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_target::abi::Size;
 
+use self::fd::FlockOp;
+use self::shims::time::system_time_to_duration;
 use crate::shims::os_str::bytes_to_os_str;
 use crate::shims::unix::fd::FileDescriptionRef;
 use crate::shims::unix::*;
 use crate::*;
-use self::shims::time::system_time_to_duration;
-
-use self::fd::FlockOp;
 
 #[derive(Debug)]
 struct FileHandle {
@@ -42,7 +41,10 @@ impl FileDescription for FileHandle {
         assert!(communicate_allowed, "isolation should have prevented even opening a file");
         let mut bytes = vec![0; len];
         let result = (&mut &self.file).read(&mut bytes);
-        ecx.return_read_bytes_and_count(ptr, &bytes, result, dest)
+        match result {
+            Ok(read_size) => ecx.return_read_success(ptr, &bytes, read_size, dest),
+            Err(e) => ecx.set_last_error_and_return(e, dest),
+        }
     }
 
     fn write<'tcx>(
@@ -57,7 +59,10 @@ impl FileDescription for FileHandle {
         assert!(communicate_allowed, "isolation should have prevented even opening a file");
         let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?;
         let result = (&mut &self.file).write(bytes);
-        ecx.return_written_byte_count_or_error(result, dest)
+        match result {
+            Ok(write_size) => ecx.return_write_success(write_size, dest),
+            Err(e) => ecx.set_last_error_and_return(e, dest),
+        }
     }
 
     fn pread<'tcx>(
@@ -85,7 +90,10 @@ impl FileDescription for FileHandle {
             res
         };
         let result = f();
-        ecx.return_read_bytes_and_count(ptr, &bytes, result, dest)
+        match result {
+            Ok(read_size) => ecx.return_read_success(ptr, &bytes, read_size, dest),
+            Err(e) => ecx.set_last_error_and_return(e, dest),
+        }
     }
 
     fn pwrite<'tcx>(
@@ -113,7 +121,10 @@ impl FileDescription for FileHandle {
             res
         };
         let result = f();
-        ecx.return_written_byte_count_or_error(result, dest)
+        match result {
+            Ok(write_size) => ecx.return_write_success(write_size, dest),
+            Err(e) => ecx.set_last_error_and_return(e, dest),
+        }
     }
 
     fn seek<'tcx>(
@@ -122,7 +133,7 @@ impl FileDescription for FileHandle {
         offset: SeekFrom,
     ) -> InterpResult<'tcx, io::Result<u64>> {
         assert!(communicate_allowed, "isolation should have prevented even opening a file");
-        Ok((&mut &self.file).seek(offset))
+        interp_ok((&mut &self.file).seek(offset))
     }
 
     fn close<'tcx>(
@@ -137,7 +148,7 @@ impl FileDescription for FileHandle {
             // to handle possible errors correctly.
             let result = self.file.sync_all();
             // Now we actually close the file and return the result.
-            Ok(result)
+            interp_ok(result)
         } else {
             // We drop the file, this closes it but ignores any errors
             // produced when closing it. This is done because
@@ -145,7 +156,7 @@ impl FileDescription for FileHandle {
             // `/dev/urandom` which are read-only. Check
             // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439
             // for a deeper discussion.
-            Ok(Ok(()))
+            interp_ok(Ok(()))
         }
     }
 
@@ -180,18 +191,20 @@ impl FileDescription for FileHandle {
                 }
                 ret => panic!("Unexpected return value from flock: {ret}"),
             };
-            Ok(res)
+            interp_ok(res)
         }
 
         #[cfg(target_family = "windows")]
         {
             use std::os::windows::io::AsRawHandle;
-            use windows_sys::Win32::{
-                Foundation::{ERROR_IO_PENDING, ERROR_LOCK_VIOLATION, FALSE, HANDLE, TRUE},
-                Storage::FileSystem::{
-                    LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY, LockFileEx, UnlockFile,
-                },
+
+            use windows_sys::Win32::Foundation::{
+                ERROR_IO_PENDING, ERROR_LOCK_VIOLATION, FALSE, HANDLE, TRUE,
+            };
+            use windows_sys::Win32::Storage::FileSystem::{
+                LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY, LockFileEx, UnlockFile,
             };
+
             let fh = self.file.as_raw_handle() as HANDLE;
 
             use FlockOp::*;
@@ -230,7 +243,7 @@ impl FileDescription for FileHandle {
                 }
                 _ => panic!("Unexpected return value: {ret}"),
             };
-            Ok(res)
+            interp_ok(res)
         }
 
         #[cfg(not(any(target_family = "unix", target_family = "windows")))]
@@ -288,7 +301,7 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> {
             &buf,
         )?;
 
-        Ok(0)
+        interp_ok(0)
     }
 
     fn file_type_to_d_type(
@@ -302,26 +315,30 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match file_type {
             Ok(file_type) => {
                 match () {
-                    _ if file_type.is_dir() => Ok(this.eval_libc("DT_DIR").to_u8()?.into()),
-                    _ if file_type.is_file() => Ok(this.eval_libc("DT_REG").to_u8()?.into()),
-                    _ if file_type.is_symlink() => Ok(this.eval_libc("DT_LNK").to_u8()?.into()),
+                    _ if file_type.is_dir() => interp_ok(this.eval_libc("DT_DIR").to_u8()?.into()),
+                    _ if file_type.is_file() => interp_ok(this.eval_libc("DT_REG").to_u8()?.into()),
+                    _ if file_type.is_symlink() =>
+                        interp_ok(this.eval_libc("DT_LNK").to_u8()?.into()),
                     // Certain file types are only supported when the host is a Unix system.
                     #[cfg(unix)]
                     _ if file_type.is_block_device() =>
-                        Ok(this.eval_libc("DT_BLK").to_u8()?.into()),
+                        interp_ok(this.eval_libc("DT_BLK").to_u8()?.into()),
                     #[cfg(unix)]
-                    _ if file_type.is_char_device() => Ok(this.eval_libc("DT_CHR").to_u8()?.into()),
+                    _ if file_type.is_char_device() =>
+                        interp_ok(this.eval_libc("DT_CHR").to_u8()?.into()),
                     #[cfg(unix)]
-                    _ if file_type.is_fifo() => Ok(this.eval_libc("DT_FIFO").to_u8()?.into()),
+                    _ if file_type.is_fifo() =>
+                        interp_ok(this.eval_libc("DT_FIFO").to_u8()?.into()),
                     #[cfg(unix)]
-                    _ if file_type.is_socket() => Ok(this.eval_libc("DT_SOCK").to_u8()?.into()),
+                    _ if file_type.is_socket() =>
+                        interp_ok(this.eval_libc("DT_SOCK").to_u8()?.into()),
                     // Fallback
-                    _ => Ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into()),
+                    _ => interp_ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into()),
                 }
             }
             Err(e) =>
                 match e.raw_os_error() {
-                    Some(error) => Ok(error),
+                    Some(error) => interp_ok(error),
                     None =>
                         throw_unsup_format!(
                             "the error {} couldn't be converted to a return value",
@@ -416,18 +433,18 @@ fn maybe_sync_file(
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn open(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
-        if args.len() < 2 {
+        let [path_raw, flag, ..] = args else {
             throw_ub_format!(
                 "incorrect number of arguments for `open`: got {}, expected at least 2",
                 args.len()
             );
-        }
+        };
 
         let this = self.eval_context_mut();
 
-        let path_raw = this.read_pointer(&args[0])?;
+        let path_raw = this.read_pointer(path_raw)?;
         let path = this.read_path_from_c_str(path_raw)?;
-        let flag = this.read_scalar(&args[1])?.to_i32()?;
+        let flag = this.read_scalar(flag)?.to_i32()?;
 
         let mut options = OpenOptions::new();
 
@@ -521,9 +538,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             let o_tmpfile = this.eval_libc_i32("O_TMPFILE");
             if flag & o_tmpfile == o_tmpfile {
                 // if the flag contains `O_TMPFILE` then we return a graceful error
-                let eopnotsupp = this.eval_libc("EOPNOTSUPP");
-                this.set_last_error(eopnotsupp)?;
-                return Ok(Scalar::from_i32(-1));
+                this.set_last_error(LibcError("EOPNOTSUPP"))?;
+                return interp_ok(Scalar::from_i32(-1));
             }
         }
 
@@ -544,7 +560,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 if path.is_symlink() {
                     let eloop = this.eval_libc("ELOOP");
                     this.set_last_error(eloop)?;
-                    return Ok(Scalar::from_i32(-1));
+                    return interp_ok(Scalar::from_i32(-1));
                 }
             }
             mirror |= o_nofollow;
@@ -559,15 +575,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`open`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(Scalar::from_i32(-1));
+            this.set_last_error(ErrorKind::PermissionDenied)?;
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         let fd = options
             .open(path)
             .map(|file| this.machine.fds.insert_new(FileHandle { file, writable }));
 
-        Ok(Scalar::from_i32(this.try_unwrap_io_result(fd)?))
+        interp_ok(Scalar::from_i32(this.try_unwrap_io_result(fd)?))
     }
 
     fn lseek64(&mut self, fd_num: i32, offset: i128, whence: i32) -> InterpResult<'tcx, Scalar> {
@@ -578,9 +594,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let seek_from = if whence == this.eval_libc_i32("SEEK_SET") {
             if offset < 0 {
                 // Negative offsets return `EINVAL`.
-                let einval = this.eval_libc("EINVAL");
-                this.set_last_error(einval)?;
-                return Ok(Scalar::from_i64(-1));
+                this.set_last_error(LibcError("EINVAL"))?;
+                return interp_ok(Scalar::from_i64(-1));
             } else {
                 SeekFrom::Start(u64::try_from(offset).unwrap())
             }
@@ -589,21 +604,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         } else if whence == this.eval_libc_i32("SEEK_END") {
             SeekFrom::End(i64::try_from(offset).unwrap())
         } else {
-            let einval = this.eval_libc("EINVAL");
-            this.set_last_error(einval)?;
-            return Ok(Scalar::from_i64(-1));
+            this.set_last_error(LibcError("EINVAL"))?;
+            return interp_ok(Scalar::from_i64(-1));
         };
 
         let communicate = this.machine.communicate();
 
         let Some(fd) = this.machine.fds.get(fd_num) else {
-            return Ok(Scalar::from_i64(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i64(this.fd_not_found()?));
         };
         let result = fd.seek(communicate, seek_from)?.map(|offset| i64::try_from(offset).unwrap());
         drop(fd);
 
         let result = this.try_unwrap_io_result(result)?;
-        Ok(Scalar::from_i64(result))
+        interp_ok(Scalar::from_i64(result))
     }
 
     fn unlink(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@@ -614,12 +628,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`unlink`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(Scalar::from_i32(-1));
+            this.set_last_error(ErrorKind::PermissionDenied)?;
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         let result = remove_file(path).map(|_| 0);
-        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
+        interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     fn symlink(
@@ -645,12 +659,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`symlink`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(Scalar::from_i32(-1));
+            this.set_last_error(ErrorKind::PermissionDenied)?;
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         let result = create_link(&target, &linkpath).map(|_| 0);
-        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
+        interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     fn macos_fbsd_stat(
@@ -672,16 +686,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.reject_in_isolation("`stat`", reject_with)?;
             let eacc = this.eval_libc("EACCES");
             this.set_last_error(eacc)?;
-            return Ok(Scalar::from_i32(-1));
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         // `stat` always follows symlinks.
         let metadata = match FileMetadata::from_path(this, &path, true)? {
             Some(metadata) => metadata,
-            None => return Ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno
+            None => return interp_ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno
         };
 
-        Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
+        interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
     }
 
     // `lstat` is used to get symlink metadata.
@@ -704,15 +718,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.reject_in_isolation("`lstat`", reject_with)?;
             let eacc = this.eval_libc("EACCES");
             this.set_last_error(eacc)?;
-            return Ok(Scalar::from_i32(-1));
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         let metadata = match FileMetadata::from_path(this, &path, false)? {
             Some(metadata) => metadata,
-            None => return Ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno
+            None => return interp_ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno
         };
 
-        Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
+        interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
     }
 
     fn macos_fbsd_fstat(
@@ -732,14 +746,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`fstat`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return Ok(Scalar::from_i32(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
         }
 
         let metadata = match FileMetadata::from_fd_num(this, fd)? {
             Some(metadata) => metadata,
-            None => return Ok(Scalar::from_i32(-1)),
+            None => return interp_ok(Scalar::from_i32(-1)),
         };
-        Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
+        interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
     }
 
     fn linux_statx(
@@ -764,7 +778,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if this.ptr_is_null(statxbuf_ptr)? || this.ptr_is_null(pathname_ptr)? {
             let efault = this.eval_libc("EFAULT");
             this.set_last_error(efault)?;
-            return Ok(Scalar::from_i32(-1));
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         let statxbuf = this.deref_pointer_as(statxbuf_op, this.libc_ty_layout("statx"))?;
@@ -806,7 +820,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.eval_libc("EBADF")
             };
             this.set_last_error(ecode)?;
-            return Ok(Scalar::from_i32(-1));
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         // the `_mask_op` parameter specifies the file information that the caller requested.
@@ -828,7 +842,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
         let metadata = match metadata {
             Some(metadata) => metadata,
-            None => return Ok(Scalar::from_i32(-1)),
+            None => return interp_ok(Scalar::from_i32(-1)),
         };
 
         // The `mode` field specifies the type of the file and the permissions over the file for
@@ -847,25 +861,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             .accessed
             .map(|tup| {
                 mask |= this.eval_libc_u32("STATX_ATIME");
-                InterpResult::Ok(tup)
+                interp_ok(tup)
             })
-            .unwrap_or_else(|| Ok((0, 0)))?;
+            .unwrap_or_else(|| interp_ok((0, 0)))?;
 
         let (created_sec, created_nsec) = metadata
             .created
             .map(|tup| {
                 mask |= this.eval_libc_u32("STATX_BTIME");
-                InterpResult::Ok(tup)
+                interp_ok(tup)
             })
-            .unwrap_or_else(|| Ok((0, 0)))?;
+            .unwrap_or_else(|| interp_ok((0, 0)))?;
 
         let (modified_sec, modified_nsec) = metadata
             .modified
             .map(|tup| {
                 mask |= this.eval_libc_u32("STATX_MTIME");
-                InterpResult::Ok(tup)
+                interp_ok(tup)
             })
-            .unwrap_or_else(|| Ok((0, 0)))?;
+            .unwrap_or_else(|| interp_ok((0, 0)))?;
 
         // Now we write everything to `statxbuf`. We write a zero for the unavailable fields.
         this.write_int_fields_named(
@@ -921,7 +935,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             &this.project_field_named(&statxbuf, "stx_mtime")?,
         )?;
 
-        Ok(Scalar::from_i32(0))
+        interp_ok(Scalar::from_i32(0))
     }
 
     fn rename(
@@ -937,7 +951,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if this.ptr_is_null(oldpath_ptr)? || this.ptr_is_null(newpath_ptr)? {
             let efault = this.eval_libc("EFAULT");
             this.set_last_error(efault)?;
-            return Ok(Scalar::from_i32(-1));
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         let oldpath = this.read_path_from_c_str(oldpath_ptr)?;
@@ -946,13 +960,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`rename`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(Scalar::from_i32(-1));
+            this.set_last_error(ErrorKind::PermissionDenied)?;
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         let result = rename(oldpath, newpath).map(|_| 0);
 
-        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
+        interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     fn mkdir(&mut self, path_op: &OpTy<'tcx>, mode_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@@ -970,8 +984,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`mkdir`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(Scalar::from_i32(-1));
+            this.set_last_error(ErrorKind::PermissionDenied)?;
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         #[cfg_attr(not(unix), allow(unused_mut))]
@@ -987,7 +1001,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let result = builder.create(path).map(|_| 0i32);
 
-        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
+        interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     fn rmdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@@ -998,13 +1012,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`rmdir`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(Scalar::from_i32(-1));
+            this.set_last_error(ErrorKind::PermissionDenied)?;
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         let result = remove_dir(path).map(|_| 0i32);
 
-        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
+        interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     fn opendir(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@@ -1017,7 +1031,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.reject_in_isolation("`opendir`", reject_with)?;
             let eacc = this.eval_libc("EACCES");
             this.set_last_error(eacc)?;
-            return Ok(Scalar::null_ptr(this));
+            return interp_ok(Scalar::null_ptr(this));
         }
 
         let result = read_dir(name);
@@ -1029,11 +1043,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // The libc API for opendir says that this method returns a pointer to an opaque
                 // structure, but we are returning an ID number. Thus, pass it as a scalar of
                 // pointer width.
-                Ok(Scalar::from_target_usize(id, this))
+                interp_ok(Scalar::from_target_usize(id, this))
             }
             Err(e) => {
-                this.set_last_error_from_io_error(e)?;
-                Ok(Scalar::null_ptr(this))
+                this.set_last_error(e)?;
+                interp_ok(Scalar::null_ptr(this))
             }
         }
     }
@@ -1050,7 +1064,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.reject_in_isolation("`readdir`", reject_with)?;
             let eacc = this.eval_libc("EBADF");
             this.set_last_error(eacc)?;
-            return Ok(Scalar::null_ptr(this));
+            return interp_ok(Scalar::null_ptr(this));
         }
 
         let open_dir = this.machine.dirs.streams.get_mut(&dirp).ok_or_else(|| {
@@ -1117,7 +1131,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 None
             }
             Some(Err(e)) => {
-                this.set_last_error_from_io_error(e)?;
+                this.set_last_error(e)?;
                 None
             }
         };
@@ -1128,7 +1142,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.deallocate_ptr(old_entry, None, MiriMemoryKind::Runtime.into())?;
         }
 
-        Ok(Scalar::from_maybe_pointer(entry.unwrap_or_else(Pointer::null), this))
+        interp_ok(Scalar::from_maybe_pointer(entry.unwrap_or_else(Pointer::null), this))
     }
 
     fn macos_fbsd_readdir_r(
@@ -1149,13 +1163,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`readdir_r`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return Ok(Scalar::from_i32(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
         }
 
         let open_dir = this.machine.dirs.streams.get_mut(&dirp).ok_or_else(|| {
             err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir")
         })?;
-        Ok(Scalar::from_i32(match open_dir.read_dir.next() {
+        interp_ok(Scalar::from_i32(match open_dir.read_dir.next() {
             Some(Ok(dir_entry)) => {
                 // Write into entry, write pointer to result, return 0 on success.
                 // The name is written with write_os_str_to_c_str, while the rest of the
@@ -1260,18 +1274,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let dirp = this.read_target_usize(dirp_op)?;
 
         // Reject if isolation is enabled.
-        Ok(Scalar::from_i32(if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
-            this.reject_in_isolation("`closedir`", reject_with)?;
-            this.fd_not_found()?
-        } else if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) {
-            if let Some(entry) = open_dir.entry {
-                this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?;
-            }
-            drop(open_dir);
-            0
-        } else {
-            this.fd_not_found()?
-        }))
+        interp_ok(Scalar::from_i32(
+            if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
+                this.reject_in_isolation("`closedir`", reject_with)?;
+                this.fd_not_found()?
+            } else if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) {
+                if let Some(entry) = open_dir.entry {
+                    this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?;
+                }
+                drop(open_dir);
+                0
+            } else {
+                this.fd_not_found()?
+            },
+        ))
     }
 
     fn ftruncate64(&mut self, fd_num: i32, length: i128) -> InterpResult<'tcx, Scalar> {
@@ -1281,11 +1297,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`ftruncate64`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return Ok(Scalar::from_i32(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
         }
 
         let Some(fd) = this.machine.fds.get(fd_num) else {
-            return Ok(Scalar::from_i32(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
         };
 
         // FIXME: Support ftruncate64 for all FDs
@@ -1298,19 +1314,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let result = file.set_len(length);
                 drop(fd);
                 let result = this.try_unwrap_io_result(result.map(|_| 0i32))?;
-                Ok(Scalar::from_i32(result))
+                interp_ok(Scalar::from_i32(result))
             } else {
                 drop(fd);
-                let einval = this.eval_libc("EINVAL");
-                this.set_last_error(einval)?;
-                Ok(Scalar::from_i32(-1))
+                this.set_last_error(LibcError("EINVAL"))?;
+                interp_ok(Scalar::from_i32(-1))
             }
         } else {
             drop(fd);
             // The file is not writable
-            let einval = this.eval_libc("EINVAL");
-            this.set_last_error(einval)?;
-            Ok(Scalar::from_i32(-1))
+            this.set_last_error(LibcError("EINVAL"))?;
+            interp_ok(Scalar::from_i32(-1))
         }
     }
 
@@ -1328,7 +1342,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`fsync`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return Ok(Scalar::from_i32(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
         }
 
         self.ffullsync_fd(fd)
@@ -1337,7 +1351,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn ffullsync_fd(&mut self, fd_num: i32) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
         let Some(fd) = this.machine.fds.get(fd_num) else {
-            return Ok(Scalar::from_i32(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
         };
         // Only regular files support synchronization.
         let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
@@ -1345,7 +1359,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         })?;
         let io_result = maybe_sync_file(file, *writable, File::sync_all);
         drop(fd);
-        Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
+        interp_ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
     }
 
     fn fdatasync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@@ -1357,11 +1371,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`fdatasync`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return Ok(Scalar::from_i32(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
         }
 
         let Some(fd) = this.machine.fds.get(fd) else {
-            return Ok(Scalar::from_i32(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
         };
         // Only regular files support synchronization.
         let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
@@ -1369,7 +1383,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         })?;
         let io_result = maybe_sync_file(file, *writable, File::sync_data);
         drop(fd);
-        Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
+        interp_ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
     }
 
     fn sync_file_range(
@@ -1387,28 +1401,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let flags = this.read_scalar(flags_op)?.to_i32()?;
 
         if offset < 0 || nbytes < 0 {
-            let einval = this.eval_libc("EINVAL");
-            this.set_last_error(einval)?;
-            return Ok(Scalar::from_i32(-1));
+            this.set_last_error(LibcError("EINVAL"))?;
+            return interp_ok(Scalar::from_i32(-1));
         }
         let allowed_flags = this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_BEFORE")
             | this.eval_libc_i32("SYNC_FILE_RANGE_WRITE")
             | this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_AFTER");
         if flags & allowed_flags != flags {
-            let einval = this.eval_libc("EINVAL");
-            this.set_last_error(einval)?;
-            return Ok(Scalar::from_i32(-1));
+            this.set_last_error(LibcError("EINVAL"))?;
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`sync_file_range`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return Ok(Scalar::from_i32(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
         }
 
         let Some(fd) = this.machine.fds.get(fd) else {
-            return Ok(Scalar::from_i32(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
         };
         // Only regular files support synchronization.
         let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
@@ -1416,7 +1428,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         })?;
         let io_result = maybe_sync_file(file, *writable, File::sync_data);
         drop(fd);
-        Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
+        interp_ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
     }
 
     fn readlink(
@@ -1436,7 +1448,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.reject_in_isolation("`readlink`", reject_with)?;
             let eacc = this.eval_libc("EACCES");
             this.set_last_error(eacc)?;
-            return Ok(-1);
+            return interp_ok(-1);
         }
 
         let result = std::fs::read_link(pathname);
@@ -1455,11 +1467,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     path_bytes = &path_bytes[..bufsize]
                 }
                 this.write_bytes_ptr(buf, path_bytes.iter().copied())?;
-                Ok(path_bytes.len().try_into().unwrap())
+                interp_ok(path_bytes.len().try_into().unwrap())
             }
             Err(e) => {
-                this.set_last_error_from_io_error(e)?;
-                Ok(-1)
+                this.set_last_error(e)?;
+                interp_ok(-1)
             }
         }
     }
@@ -1471,7 +1483,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let fd = this.read_scalar(miri_fd)?.to_i32()?;
         let error = if let Some(fd) = this.machine.fds.get(fd) {
             if fd.is_tty(this.machine.communicate()) {
-                return Ok(Scalar::from_i32(1));
+                return interp_ok(Scalar::from_i32(1));
             } else {
                 this.eval_libc("ENOTTY")
             }
@@ -1480,7 +1492,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.eval_libc("EBADF")
         };
         this.set_last_error(error)?;
-        Ok(Scalar::from_i32(0))
+        interp_ok(Scalar::from_i32(0))
     }
 
     fn realpath(
@@ -1499,7 +1511,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.reject_in_isolation("`realpath`", reject_with)?;
             let eacc = this.eval_libc("EACCES");
             this.set_last_error(eacc)?;
-            return Ok(Scalar::from_target_usize(0, this));
+            return interp_ok(Scalar::from_target_usize(0, this));
         }
 
         let result = std::fs::canonicalize(pathname);
@@ -1530,16 +1542,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         // seems like a bit of a mess anyway: <https://eklitzke.org/path-max-is-tricky>.
                         let enametoolong = this.eval_libc("ENAMETOOLONG");
                         this.set_last_error(enametoolong)?;
-                        return Ok(Scalar::from_target_usize(0, this));
+                        return interp_ok(Scalar::from_target_usize(0, this));
                     }
                     processed_ptr
                 };
 
-                Ok(Scalar::from_maybe_pointer(dest, this))
+                interp_ok(Scalar::from_maybe_pointer(dest, this))
             }
             Err(e) => {
-                this.set_last_error_from_io_error(e)?;
-                Ok(Scalar::from_target_usize(0, this))
+                this.set_last_error(e)?;
+                interp_ok(Scalar::from_target_usize(0, this))
             }
         }
     }
@@ -1574,7 +1586,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.reject_in_isolation("`mkstemp`", reject_with)?;
             let eacc = this.eval_libc("EACCES");
             this.set_last_error(eacc)?;
-            return Ok(Scalar::from_i32(-1));
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         // Get the bytes of the suffix we expect in _target_ encoding.
@@ -1590,9 +1602,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // If we don't find the suffix, it is an error.
         if last_six_char_bytes != suffix_bytes {
-            let einval = this.eval_libc("EINVAL");
-            this.set_last_error(einval)?;
-            return Ok(Scalar::from_i32(-1));
+            this.set_last_error(LibcError("EINVAL"))?;
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         // At this point we know we have 6 ASCII 'X' characters as a suffix.
@@ -1647,7 +1658,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             match file {
                 Ok(f) => {
                     let fd = this.machine.fds.insert_new(FileHandle { file: f, writable: true });
-                    return Ok(Scalar::from_i32(fd));
+                    return interp_ok(Scalar::from_i32(fd));
                 }
                 Err(e) =>
                     match e.kind() {
@@ -1657,8 +1668,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         _ => {
                             // "On error, -1 is returned, and errno is set to
                             // indicate the error"
-                            this.set_last_error_from_io_error(e)?;
-                            return Ok(Scalar::from_i32(-1));
+                            this.set_last_error(e)?;
+                            return interp_ok(Scalar::from_i32(-1));
                         }
                     },
             }
@@ -1667,7 +1678,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // We ran out of attempts to create the file, return an error.
         let eexist = this.eval_libc("EEXIST");
         this.set_last_error(eexist)?;
-        Ok(Scalar::from_i32(-1))
+        interp_ok(Scalar::from_i32(-1))
     }
 }
 
@@ -1677,12 +1688,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 fn extract_sec_and_nsec<'tcx>(
     time: std::io::Result<SystemTime>,
 ) -> InterpResult<'tcx, Option<(u64, u32)>> {
-    time.ok()
-        .map(|time| {
+    match time.ok() {
+        Some(time) => {
             let duration = system_time_to_duration(&time)?;
-            Ok((duration.as_secs(), duration.subsec_nanos()))
-        })
-        .transpose()
+            interp_ok(Some((duration.as_secs(), duration.subsec_nanos())))
+        }
+        None => interp_ok(None),
+    }
 }
 
 /// Stores a file's metadata in order to avoid code duplication in the different metadata related
@@ -1736,8 +1748,8 @@ impl FileMetadata {
         let metadata = match metadata {
             Ok(metadata) => metadata,
             Err(e) => {
-                ecx.set_last_error_from_io_error(e)?;
-                return Ok(None);
+                ecx.set_last_error(e)?;
+                return interp_ok(None);
             }
         };
 
@@ -1760,6 +1772,6 @@ impl FileMetadata {
         let modified = extract_sec_and_nsec(metadata.modified())?;
 
         // FIXME: Provide more fields using platform specific methods.
-        Ok(Some(FileMetadata { mode, size, created, accessed, modified }))
+        interp_ok(Some(FileMetadata { mode, size, created, accessed, modified }))
     }
 }
diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs
index 3d4fe770e99..b57347abffa 100644
--- a/src/tools/miri/src/shims/unix/linux/epoll.rs
+++ b/src/tools/miri/src/shims/unix/linux/epoll.rs
@@ -4,6 +4,7 @@ use std::io;
 use std::rc::{Rc, Weak};
 use std::time::Duration;
 
+use crate::concurrency::VClock;
 use crate::shims::unix::fd::{FdId, FileDescriptionRef, WeakFileDescriptionRef};
 use crate::shims::unix::*;
 use crate::*;
@@ -19,7 +20,7 @@ struct Epoll {
     /// and file descriptor value.
     // This is an Rc because EpollInterest need to hold a reference to update
     // it.
-    ready_list: Rc<RefCell<BTreeMap<(FdId, i32), EpollEventInstance>>>,
+    ready_list: Rc<ReadyList>,
     /// A list of thread ids blocked on this epoll instance.
     thread_id: RefCell<Vec<ThreadId>>,
 }
@@ -63,7 +64,7 @@ pub struct EpollEventInterest {
     /// <https://man7.org/linux/man-pages/man3/epoll_event.3type.html>
     data: u64,
     /// Ready list of the epoll instance under which this EpollEventInterest is registered.
-    ready_list: Rc<RefCell<BTreeMap<(FdId, i32), EpollEventInstance>>>,
+    ready_list: Rc<ReadyList>,
     /// The epoll file description that this EpollEventInterest is registered under.
     weak_epfd: WeakFileDescriptionRef,
 }
@@ -88,6 +89,12 @@ pub struct EpollReadyEvents {
     pub epollerr: bool,
 }
 
+#[derive(Debug, Default)]
+struct ReadyList {
+    mapping: RefCell<BTreeMap<(FdId, i32), EpollEventInstance>>,
+    clock: RefCell<VClock>,
+}
+
 impl EpollReadyEvents {
     pub fn new() -> Self {
         EpollReadyEvents {
@@ -127,7 +134,7 @@ impl EpollReadyEvents {
 }
 
 impl Epoll {
-    fn get_ready_list(&self) -> Rc<RefCell<BTreeMap<(FdId, i32), EpollEventInstance>>> {
+    fn get_ready_list(&self) -> Rc<ReadyList> {
         Rc::clone(&self.ready_list)
     }
 }
@@ -142,7 +149,7 @@ impl FileDescription for Epoll {
         _communicate_allowed: bool,
         _ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx, io::Result<()>> {
-        Ok(Ok(()))
+        interp_ok(Ok(()))
     }
 }
 
@@ -207,11 +214,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             );
         }
 
-        let mut epoll_instance = Epoll::default();
-        epoll_instance.ready_list = Rc::new(RefCell::new(BTreeMap::new()));
-
         let fd = this.machine.fds.insert_new(Epoll::default());
-        Ok(Scalar::from_i32(fd))
+        interp_ok(Scalar::from_i32(fd))
     }
 
     /// This function performs control operations on the `Epoll` instance referred to by the file
@@ -261,14 +265,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // Throw EINVAL if epfd and fd have the same value.
         if epfd_value == fd {
-            let einval = this.eval_libc("EINVAL");
-            this.set_last_error(einval)?;
-            return Ok(Scalar::from_i32(-1));
+            this.set_last_error(LibcError("EINVAL"))?;
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         // Check if epfd is a valid epoll file descriptor.
         let Some(epfd) = this.machine.fds.get(epfd_value) else {
-            return Ok(Scalar::from_i32(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
         };
         let epoll_file_description = epfd
             .downcast::<Epoll>()
@@ -278,7 +281,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let ready_list = &epoll_file_description.ready_list;
 
         let Some(fd_ref) = this.machine.fds.get(fd) else {
-            return Ok(Scalar::from_i32(this.fd_not_found()?));
+            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
         };
         let id = fd_ref.get_id();
 
@@ -330,13 +333,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 if interest_list.contains_key(&epoll_key) {
                     let eexist = this.eval_libc("EEXIST");
                     this.set_last_error(eexist)?;
-                    return Ok(Scalar::from_i32(-1));
+                    return interp_ok(Scalar::from_i32(-1));
                 }
             } else {
                 if !interest_list.contains_key(&epoll_key) {
                     let enoent = this.eval_libc("ENOENT");
                     this.set_last_error(enoent)?;
-                    return Ok(Scalar::from_i32(-1));
+                    return interp_ok(Scalar::from_i32(-1));
                 }
             }
 
@@ -364,7 +367,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Notification will be returned for current epfd if there is event in the file
             // descriptor we registered.
             check_and_update_one_event_interest(&fd_ref, interest, id, this)?;
-            return Ok(Scalar::from_i32(0));
+            return interp_ok(Scalar::from_i32(0));
         } else if op == epoll_ctl_del {
             let epoll_key = (id, fd);
 
@@ -372,13 +375,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             let Some(epoll_interest) = interest_list.remove(&epoll_key) else {
                 let enoent = this.eval_libc("ENOENT");
                 this.set_last_error(enoent)?;
-                return Ok(Scalar::from_i32(-1));
+                return interp_ok(Scalar::from_i32(-1));
             };
             // All related Weak<EpollEventInterest> will fail to upgrade after the drop.
             drop(epoll_interest);
 
             // Remove related epoll_interest from ready list.
-            ready_list.borrow_mut().remove(&epoll_key);
+            ready_list.mapping.borrow_mut().remove(&epoll_key);
 
             // Remove dangling EpollEventInterest from its global table.
             // .unwrap() below should succeed because the file description id must have registered
@@ -390,9 +393,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 .unwrap()
                 .retain(|event| event.upgrade().is_some());
 
-            return Ok(Scalar::from_i32(0));
+            return interp_ok(Scalar::from_i32(0));
         }
-        Ok(Scalar::from_i32(-1))
+        interp_ok(Scalar::from_i32(-1))
     }
 
     /// The `epoll_wait()` system call waits for events on the `Epoll`
@@ -401,19 +404,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// list about file descriptors in the interest list that have some
     /// events available. Up to `maxevents` are returned by `epoll_wait()`.
     /// The `maxevents` argument must be greater than zero.
-
+    ///
     /// The `timeout` argument specifies the number of milliseconds that
     /// `epoll_wait()` will block. Time is measured against the
     /// CLOCK_MONOTONIC clock. If the timeout is zero, the function will not block,
     /// while if the timeout is -1, the function will block
     /// until at least one event has been retrieved (or an error
     /// occurred).
-
+    ///
     /// A call to `epoll_wait()` will block until either:
     /// • a file descriptor delivers an event;
     /// • the call is interrupted by a signal handler; or
     /// • the timeout expires.
-
+    ///
     /// Note that the timeout interval will be rounded up to the system
     /// clock granularity, and kernel scheduling delays mean that the
     /// blocking interval may overrun by a small amount. Specifying a
@@ -443,10 +446,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let timeout = this.read_scalar(timeout)?.to_i32()?;
 
         if epfd_value <= 0 || maxevents <= 0 {
-            let einval = this.eval_libc("EINVAL");
-            this.set_last_error(einval)?;
+            this.set_last_error(LibcError("EINVAL"))?;
             this.write_int(-1, dest)?;
-            return Ok(());
+            return interp_ok(());
         }
 
         // This needs to come after the maxevents value check, or else maxevents.try_into().unwrap()
@@ -459,7 +461,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let Some(epfd) = this.machine.fds.get(epfd_value) else {
             let result_value: i32 = this.fd_not_found()?;
             this.write_int(result_value, dest)?;
-            return Ok(());
+            return interp_ok(());
         };
         // Create a weak ref of epfd and pass it to callback so we will make sure that epfd
         // is not close after the thread unblocks.
@@ -473,8 +475,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             let epoll_file_description = epfd
                 .downcast::<Epoll>()
                 .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?;
-            let binding = epoll_file_description.get_ready_list();
-            ready_list_empty = binding.borrow_mut().is_empty();
+            ready_list_empty = epoll_file_description.ready_list.mapping.borrow().is_empty();
             thread_ids = epoll_file_description.thread_id.borrow_mut();
         }
         if timeout == 0 || !ready_list_empty {
@@ -508,7 +509,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     }
                     @unblock = |this| {
                         blocking_epoll_callback(epfd_value, weak_epfd, &dest, &event, this)?;
-                        Ok(())
+                        interp_ok(())
                     }
                     @timeout = |this| {
                         // No notification after blocking timeout.
@@ -521,12 +522,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                             .thread_id.borrow_mut()
                             .retain(|&id| id != this.active_thread());
                         this.write_int(0, &dest)?;
-                        Ok(())
+                        interp_ok(())
                     }
                 ),
             );
         }
-        Ok(())
+        interp_ok(())
     }
 
     /// For a specific file description, get its ready events and update the corresponding ready
@@ -563,9 +564,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         // holds a strong ref to epoll_interest.
                         let epfd = epoll_interest.borrow().weak_epfd.upgrade().unwrap();
                         // FIXME: We can randomly pick a thread to unblock.
-                        if let Some(thread_id) =
-                            epfd.downcast::<Epoll>().unwrap().thread_id.borrow_mut().pop()
-                        {
+
+                        let epoll = epfd.downcast::<Epoll>().unwrap();
+
+                        // Synchronize running thread to the epoll ready list.
+                        if let Some(clock) = &this.release_clock() {
+                            epoll.ready_list.clock.borrow_mut().join(clock);
+                        }
+
+                        if let Some(thread_id) = epoll.thread_id.borrow_mut().pop() {
                             waiter.push(thread_id);
                         };
                     }
@@ -577,7 +584,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         for thread_id in waiter {
             this.unblock_thread(thread_id, BlockReason::Epoll)?;
         }
-        Ok(())
+        interp_ok(())
     }
 }
 
@@ -596,7 +603,7 @@ fn ready_list_next(
             return Some(epoll_event_instance);
         }
     }
-    return None;
+    None
 }
 
 /// This helper function checks whether an epoll notification should be triggered for a specific
@@ -619,13 +626,14 @@ fn check_and_update_one_event_interest<'tcx>(
     // insert an epoll_return to the ready list.
     if flags != 0 {
         let epoll_key = (id, epoll_event_interest.fd_num);
-        let ready_list = &mut epoll_event_interest.ready_list.borrow_mut();
+        let ready_list = &mut epoll_event_interest.ready_list.mapping.borrow_mut();
         let event_instance = EpollEventInstance::new(flags, epoll_event_interest.data);
         // Triggers the notification by inserting it to the ready list.
         ready_list.insert(epoll_key, event_instance);
-        return Ok(true);
+        interp_ok(true)
+    } else {
+        interp_ok(false)
     }
-    return Ok(false);
 }
 
 /// Callback function after epoll_wait unblocks
@@ -645,7 +653,11 @@ fn blocking_epoll_callback<'tcx>(
         .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?;
 
     let ready_list = epoll_file_description.get_ready_list();
-    let mut ready_list = ready_list.borrow_mut();
+
+    // Synchronize waking thread from the epoll ready list.
+    ecx.acquire_clock(&ready_list.clock.borrow());
+
+    let mut ready_list = ready_list.mapping.borrow_mut();
     let mut num_of_events: i32 = 0;
     let mut array_iter = ecx.project_array_fields(events)?;
 
@@ -664,5 +676,5 @@ fn blocking_epoll_callback<'tcx>(
         }
     }
     ecx.write_int(num_of_events, dest)?;
-    Ok(())
+    interp_ok(())
 }
diff --git a/src/tools/miri/src/shims/unix/linux/eventfd.rs b/src/tools/miri/src/shims/unix/linux/eventfd.rs
index d1d461daa99..910ab7e90f2 100644
--- a/src/tools/miri/src/shims/unix/linux/eventfd.rs
+++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs
@@ -1,12 +1,13 @@
 //! Linux `eventfd` implementation.
 use std::cell::{Cell, RefCell};
 use std::io;
-use std::io::{Error, ErrorKind};
+use std::io::ErrorKind;
 
+use crate::concurrency::VClock;
 use crate::shims::unix::fd::FileDescriptionRef;
 use crate::shims::unix::linux::epoll::{EpollReadyEvents, EvalContextExt as _};
 use crate::shims::unix::*;
-use crate::{concurrency::VClock, *};
+use crate::*;
 
 /// Maximum value that the eventfd counter can hold.
 const MAX_COUNTER: u64 = u64::MAX - 1;
@@ -36,7 +37,7 @@ impl FileDescription for Event {
         // We only check the status of EPOLLIN and EPOLLOUT flags for eventfd. If other event flags
         // need to be supported in the future, the check should be added here.
 
-        Ok(EpollReadyEvents {
+        interp_ok(EpollReadyEvents {
             epollin: self.counter.get() != 0,
             epollout: self.counter.get() != MAX_COUNTER,
             ..EpollReadyEvents::new()
@@ -48,7 +49,7 @@ impl FileDescription for Event {
         _communicate_allowed: bool,
         _ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx, io::Result<()>> {
-        Ok(Ok(()))
+        interp_ok(Ok(()))
     }
 
     /// Read the counter in the buffer and return the counter if succeeded.
@@ -65,9 +66,7 @@ impl FileDescription for Event {
         let ty = ecx.machine.layouts.u64;
         // Check the size of slice, and return error only if the size of the slice < 8.
         if len < ty.size.bytes_usize() {
-            ecx.set_last_error_from_io_error(Error::from(ErrorKind::InvalidInput))?;
-            ecx.write_int(-1, dest)?;
-            return Ok(());
+            return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
         }
 
         // eventfd read at the size of u64.
@@ -77,9 +76,7 @@ impl FileDescription for Event {
         let counter = self.counter.get();
         if counter == 0 {
             if self.is_nonblock {
-                ecx.set_last_error_from_io_error(Error::from(ErrorKind::WouldBlock))?;
-                ecx.write_int(-1, dest)?;
-                return Ok(());
+                return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
             }
 
             throw_unsup_format!("eventfd: blocking is unsupported");
@@ -99,7 +96,7 @@ impl FileDescription for Event {
             ecx.write_int(buf_place.layout.size.bytes(), dest)?;
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     /// A write call adds the 8-byte integer value supplied in
@@ -110,7 +107,7 @@ impl FileDescription for Event {
     /// write either blocks until a read is performed on the
     /// file descriptor, or fails with the error EAGAIN if the
     /// file descriptor has been made nonblocking.
-
+    ///
     /// A write fails with the error EINVAL if the size of the
     /// supplied buffer is less than 8 bytes, or if an attempt is
     /// made to write the value 0xffffffffffffffff.
@@ -127,8 +124,7 @@ impl FileDescription for Event {
         let ty = ecx.machine.layouts.u64;
         // Check the size of slice, and return error only if the size of the slice < 8.
         if len < ty.layout.size.bytes_usize() {
-            let result = Err(Error::from(ErrorKind::InvalidInput));
-            return ecx.return_written_byte_count_or_error(result, dest);
+            return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
         }
 
         // Read the user supplied value from the pointer.
@@ -137,8 +133,7 @@ impl FileDescription for Event {
 
         // u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1.
         if num == u64::MAX {
-            let result = Err(Error::from(ErrorKind::InvalidInput));
-            return ecx.return_written_byte_count_or_error(result, dest);
+            return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
         }
         // If the addition does not let the counter to exceed the maximum value, update the counter.
         // Else, block.
@@ -152,8 +147,7 @@ impl FileDescription for Event {
             }
             None | Some(u64::MAX) =>
                 if self.is_nonblock {
-                    let result = Err(Error::from(ErrorKind::WouldBlock));
-                    return ecx.return_written_byte_count_or_error(result, dest);
+                    return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
                 } else {
                     throw_unsup_format!("eventfd: blocking is unsupported");
                 },
@@ -225,6 +219,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             clock: RefCell::new(VClock::default()),
         });
 
-        Ok(Scalar::from_i32(fd_value))
+        interp_ok(Scalar::from_i32(fd_value))
     }
 }
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index 6418280d035..4b5f3b6c81b 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -1,14 +1,13 @@
 use rustc_span::Symbol;
 use rustc_target::spec::abi::Abi;
 
-use crate::machine::SIGRTMAX;
-use crate::machine::SIGRTMIN;
-use crate::shims::unix::*;
-use crate::*;
 use self::shims::unix::linux::epoll::EvalContextExt as _;
 use self::shims::unix::linux::eventfd::EvalContextExt as _;
 use self::shims::unix::linux::mem::EvalContextExt as _;
 use self::shims::unix::linux::sync::futex;
+use crate::machine::{SIGRTMAX, SIGRTMIN};
+use crate::shims::unix::*;
+use crate::*;
 
 pub fn is_dyn_sym(name: &str) -> bool {
     matches!(name, "statx")
@@ -123,19 +122,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     id if id == sys_getrandom => {
                         // Used by getrandom 0.1
                         // The first argument is the syscall id, so skip over it.
-                        if args.len() < 4 {
+                        let [_, ptr, len, flags, ..] = args else {
                             throw_ub_format!(
                                 "incorrect number of arguments for `getrandom` syscall: got {}, expected at least 4",
                                 args.len()
                             );
-                        }
+                        };
 
-                        let ptr = this.read_pointer(&args[1])?;
-                        let len = this.read_target_usize(&args[2])?;
+                        let ptr = this.read_pointer(ptr)?;
+                        let len = this.read_target_usize(len)?;
                         // The only supported flags are GRND_RANDOM and GRND_NONBLOCK,
                         // neither of which have any effect on our current PRNG.
                         // See <https://github.com/rust-lang/rust/pull/79196> for a discussion of argument sizes.
-                        let _flags = this.read_scalar(&args[3])?.to_i32();
+                        let _flags = this.read_scalar(flags)?.to_i32()?;
 
                         this.gen_random(ptr, len)?;
                         this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
@@ -148,7 +147,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         this.handle_unsupported_foreign_item(format!(
                             "can't execute syscall with ID {id}"
                         ))?;
-                        return Ok(EmulateItemResult::AlreadyJumped);
+                        return interp_ok(EmulateItemResult::AlreadyJumped);
                     }
                 }
             }
@@ -191,9 +190,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_null(dest)?;
             }
 
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         };
 
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs
index 3b32612e8ba..4f2e17d50c8 100644
--- a/src/tools/miri/src/shims/unix/linux/mem.rs
+++ b/src/tools/miri/src/shims/unix/linux/mem.rs
@@ -1,9 +1,10 @@
 //! This follows the pattern in src/shims/unix/mem.rs: We only support uses of mremap that would
 //! correspond to valid uses of realloc.
 
-use crate::*;
 use rustc_target::abi::Size;
 
+use crate::*;
+
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn mremap(
@@ -24,7 +25,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero
         if old_address.addr().bytes() % this.machine.page_size != 0 || new_size == 0 {
             this.set_last_error(this.eval_libc("EINVAL"))?;
-            return Ok(this.eval_libc("MAP_FAILED"));
+            return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
         if flags & this.eval_libc_i32("MREMAP_FIXED") != 0 {
@@ -38,7 +39,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if flags & this.eval_libc_i32("MREMAP_MAYMOVE") == 0 {
             // We only support MREMAP_MAYMOVE, so not passing the flag is just a failure
             this.set_last_error(this.eval_libc("EINVAL"))?;
-            return Ok(this.eval_libc("MAP_FAILED"));
+            return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
         let align = this.machine.page_align();
@@ -59,6 +60,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             .unwrap();
         }
 
-        Ok(Scalar::from_pointer(ptr, this))
+        interp_ok(Scalar::from_pointer(ptr, this))
     }
 }
diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs
index bd212039074..5833ec64fc6 100644
--- a/src/tools/miri/src/shims/unix/linux/sync.rs
+++ b/src/tools/miri/src/shims/unix/linux/sync.rs
@@ -15,19 +15,19 @@ pub fn futex<'tcx>(
     // may or may not be left out from the `syscall()` call.
     // Therefore we don't use `check_arg_count` here, but only check for the
     // number of arguments to fall within a range.
-    if args.len() < 3 {
+    let [addr, op, val, ..] = args else {
         throw_ub_format!(
             "incorrect number of arguments for `futex` syscall: got {}, expected at least 3",
             args.len()
         );
-    }
+    };
 
     // The first three arguments (after the syscall number itself) are the same to all futex operations:
     //     (int *addr, int op, int val).
     // We checked above that these definitely exist.
-    let addr = this.read_pointer(&args[0])?;
-    let op = this.read_scalar(&args[1])?.to_i32()?;
-    let val = this.read_scalar(&args[2])?.to_i32()?;
+    let addr = this.read_pointer(addr)?;
+    let op = this.read_scalar(op)?.to_i32()?;
+    let val = this.read_scalar(val)?.to_i32()?;
 
     // This is a vararg function so we have to bring our own type for this pointer.
     let addr = this.ptr_to_mplace(addr, this.machine.layouts.i32);
@@ -55,15 +55,15 @@ pub fn futex<'tcx>(
             let wait_bitset = op & !futex_realtime == futex_wait_bitset;
 
             let bitset = if wait_bitset {
-                if args.len() < 6 {
+                let [_, _, _, timeout, uaddr2, bitset, ..] = args else {
                     throw_ub_format!(
                         "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT_BITSET`: got {}, expected at least 6",
                         args.len()
                     );
-                }
-                let _timeout = this.read_pointer(&args[3])?;
-                let _uaddr2 = this.read_pointer(&args[4])?;
-                this.read_scalar(&args[5])?.to_u32()?
+                };
+                let _timeout = this.read_pointer(timeout)?;
+                let _uaddr2 = this.read_pointer(uaddr2)?;
+                this.read_scalar(bitset)?.to_u32()?
             } else {
                 if args.len() < 4 {
                     throw_ub_format!(
@@ -75,10 +75,9 @@ pub fn futex<'tcx>(
             };
 
             if bitset == 0 {
-                let einval = this.eval_libc("EINVAL");
-                this.set_last_error(einval)?;
+                this.set_last_error(LibcError("EINVAL"))?;
                 this.write_scalar(Scalar::from_target_isize(-1, this), dest)?;
-                return Ok(());
+                return interp_ok(());
             }
 
             let timeout = this.deref_pointer_as(&args[3], this.libc_ty_layout("timespec"))?;
@@ -88,10 +87,9 @@ pub fn futex<'tcx>(
                 let duration = match this.read_timespec(&timeout)? {
                     Some(duration) => duration,
                     None => {
-                        let einval = this.eval_libc("EINVAL");
-                        this.set_last_error(einval)?;
+                        this.set_last_error(LibcError("EINVAL"))?;
                         this.write_scalar(Scalar::from_target_isize(-1, this), dest)?;
-                        return Ok(());
+                        return interp_ok(());
                     }
                 };
                 let timeout_clock = if op & futex_realtime == futex_realtime {
@@ -185,23 +183,22 @@ pub fn futex<'tcx>(
         // Same as FUTEX_WAKE, but allows you to specify a bitset to select which threads to wake up.
         op if op == futex_wake || op == futex_wake_bitset => {
             let bitset = if op == futex_wake_bitset {
-                if args.len() < 6 {
+                let [_, _, _, timeout, uaddr2, bitset, ..] = args else {
                     throw_ub_format!(
                         "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAKE_BITSET`: got {}, expected at least 6",
                         args.len()
                     );
-                }
-                let _timeout = this.read_pointer(&args[3])?;
-                let _uaddr2 = this.read_pointer(&args[4])?;
-                this.read_scalar(&args[5])?.to_u32()?
+                };
+                let _timeout = this.read_pointer(timeout)?;
+                let _uaddr2 = this.read_pointer(uaddr2)?;
+                this.read_scalar(bitset)?.to_u32()?
             } else {
                 u32::MAX
             };
             if bitset == 0 {
-                let einval = this.eval_libc("EINVAL");
-                this.set_last_error(einval)?;
+                this.set_last_error(LibcError("EINVAL"))?;
                 this.write_scalar(Scalar::from_target_isize(-1, this), dest)?;
-                return Ok(());
+                return interp_ok(());
             }
             // Together with the SeqCst fence in futex_wait, this makes sure that futex_wait
             // will see the latest value on addr which could be changed by our caller
@@ -221,5 +218,5 @@ pub fn futex<'tcx>(
         op => throw_unsup_format!("Miri does not support `futex` syscall with op={}", op),
     }
 
-    Ok(())
+    interp_ok(())
 }
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index 95a41752059..2751d379dc0 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -80,7 +80,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Random data generation
             "CCRandomGenerateBytes" => {
-                let [bytes, count] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let [bytes, count] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let bytes = this.read_pointer(bytes)?;
                 let count = this.read_target_usize(count)?;
                 let success = this.eval_libc_i32("kCCSuccess");
@@ -206,9 +207,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.os_unfair_lock_assert_not_owner(lock_op)?;
             }
 
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         };
 
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/unix/macos/sync.rs b/src/tools/miri/src/shims/unix/macos/sync.rs
index 8f9237a1d46..2f96849d0d2 100644
--- a/src/tools/miri/src/shims/unix/macos/sync.rs
+++ b/src/tools/miri/src/shims/unix/macos/sync.rs
@@ -20,7 +20,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // os_unfair_lock holds a 32-bit value, is initialized with zero and
         // must be assumed to be opaque. Therefore, we can just store our
         // internal mutex ID in the structure without anyone noticing.
-        this.mutex_get_or_create_id(&lock, 0, |_| Ok(None))
+        this.mutex_get_or_create_id(&lock, 0, |_| interp_ok(None))
     }
 }
 
@@ -43,7 +43,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.mutex_lock(id);
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     fn os_unfair_lock_trylock(
@@ -63,7 +63,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.write_scalar(Scalar::from_bool(true), dest)?;
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     fn os_unfair_lock_unlock(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
@@ -77,7 +77,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             ));
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     fn os_unfair_lock_assert_owner(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
@@ -90,7 +90,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             ));
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     fn os_unfair_lock_assert_not_owner(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
@@ -103,6 +103,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             ));
         }
 
-        Ok(())
+        interp_ok(())
     }
 }
diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs
index 33ed0e26982..9273748ef3b 100644
--- a/src/tools/miri/src/shims/unix/mem.rs
+++ b/src/tools/miri/src/shims/unix/mem.rs
@@ -14,9 +14,10 @@
 //! munmap shim which would partially unmap a region of address space previously mapped by mmap will
 //! report UB.
 
-use crate::*;
 use rustc_target::abi::Size;
 
+use crate::*;
+
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn mmap(
@@ -48,7 +49,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             && matches!(&*this.tcx.sess.target.os, "macos" | "solaris" | "illumos")
             && (flags & map_fixed) != 0
         {
-            return Ok(Scalar::from_maybe_pointer(Pointer::from_addr_invalid(addr), this));
+            return interp_ok(Scalar::from_maybe_pointer(Pointer::from_addr_invalid(addr), this));
         }
 
         let prot_read = this.eval_libc_i32("PROT_READ");
@@ -57,11 +58,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // First, we do some basic argument validation as required by mmap
         if (flags & (map_private | map_shared)).count_ones() != 1 {
             this.set_last_error(this.eval_libc("EINVAL"))?;
-            return Ok(this.eval_libc("MAP_FAILED"));
+            return interp_ok(this.eval_libc("MAP_FAILED"));
         }
         if length == 0 {
             this.set_last_error(this.eval_libc("EINVAL"))?;
-            return Ok(this.eval_libc("MAP_FAILED"));
+            return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
         // If a user tries to map a file, we want to loudly inform them that this is not going
@@ -103,11 +104,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let align = this.machine.page_align();
         let Some(map_length) = length.checked_next_multiple_of(this.machine.page_size) else {
             this.set_last_error(this.eval_libc("EINVAL"))?;
-            return Ok(this.eval_libc("MAP_FAILED"));
+            return interp_ok(this.eval_libc("MAP_FAILED"));
         };
         if map_length > this.target_usize_max() {
             this.set_last_error(this.eval_libc("EINVAL"))?;
-            return Ok(this.eval_libc("MAP_FAILED"));
+            return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
         let ptr =
@@ -120,7 +121,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         )
         .unwrap();
 
-        Ok(Scalar::from_pointer(ptr, this))
+        interp_ok(Scalar::from_pointer(ptr, this))
     }
 
     fn munmap(&mut self, addr: &OpTy<'tcx>, length: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@@ -134,16 +135,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero
         if addr.addr().bytes() % this.machine.page_size != 0 {
             this.set_last_error(this.eval_libc("EINVAL"))?;
-            return Ok(Scalar::from_i32(-1));
+            return interp_ok(Scalar::from_i32(-1));
         }
 
         let Some(length) = length.checked_next_multiple_of(this.machine.page_size) else {
             this.set_last_error(this.eval_libc("EINVAL"))?;
-            return Ok(Scalar::from_i32(-1));
+            return interp_ok(Scalar::from_i32(-1));
         };
         if length > this.target_usize_max() {
             this.set_last_error(this.eval_libc("EINVAL"))?;
-            return Ok(this.eval_libc("MAP_FAILED"));
+            return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
         let length = Size::from_bytes(length);
@@ -153,6 +154,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             MemoryKind::Machine(MiriMemoryKind::Mmap),
         )?;
 
-        Ok(Scalar::from_i32(0))
+        interp_ok(Scalar::from_i32(0))
     }
 }
diff --git a/src/tools/miri/src/shims/unix/mod.rs b/src/tools/miri/src/shims/unix/mod.rs
index a95b4d3d307..9bc310e8d0a 100644
--- a/src/tools/miri/src/shims/unix/mod.rs
+++ b/src/tools/miri/src/shims/unix/mod.rs
@@ -14,14 +14,11 @@ mod linux;
 mod macos;
 mod solarish;
 
-pub use self::env::UnixEnvVars;
-pub use self::fd::{FdTable, FileDescription};
-pub use self::fs::DirTable;
-pub use self::linux::epoll::EpollInterestTable;
 // All the Unix-specific extension traits
-pub use self::env::EvalContextExt as _;
-pub use self::fd::EvalContextExt as _;
-pub use self::fs::EvalContextExt as _;
+pub use self::env::{EvalContextExt as _, UnixEnvVars};
+pub use self::fd::{EvalContextExt as _, FdTable, FileDescription};
+pub use self::fs::{DirTable, EvalContextExt as _};
+pub use self::linux::epoll::EpollInterestTable;
 pub use self::mem::EvalContextExt as _;
 pub use self::sync::EvalContextExt as _;
 pub use self::thread::EvalContextExt as _;
diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
index a0cc4a62bfd..c10098f2733 100644
--- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
@@ -99,8 +99,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_null(dest)?;
             }
 
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs
index fea994663c0..b05f340861e 100644
--- a/src/tools/miri/src/shims/unix/sync.rs
+++ b/src/tools/miri/src/shims/unix/sync.rs
@@ -10,7 +10,7 @@ use crate::*;
 
 #[inline]
 fn mutexattr_kind_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
-    Ok(match &*ecx.tcx.sess.target.os {
+    interp_ok(match &*ecx.tcx.sess.target.os {
         "linux" | "illumos" | "solaris" | "macos" | "freebsd" | "android" => 0,
         os => throw_unsup_format!("`pthread_mutexattr` is not supported on {os}"),
     })
@@ -112,7 +112,7 @@ fn mutex_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
         }
     }
 
-    Ok(offset)
+    interp_ok(offset)
 }
 
 /// Eagerly create and initialize a new mutex.
@@ -125,7 +125,7 @@ fn mutex_create<'tcx>(
     let address = mutex.ptr().addr().bytes();
     let data = Box::new(AdditionalMutexData { address, kind });
     ecx.mutex_create(&mutex, mutex_id_offset(ecx)?, Some(data))?;
-    Ok(())
+    interp_ok(())
 }
 
 /// Returns the `MutexId` of the mutex stored at `mutex_op`.
@@ -144,7 +144,7 @@ fn mutex_get_id<'tcx>(
         // an ID yet. We have to determine the mutex kind from the static initializer.
         let kind = mutex_kind_from_static_initializer(ecx, &mutex)?;
 
-        Ok(Some(Box::new(AdditionalMutexData { kind, address })))
+        interp_ok(Some(Box::new(AdditionalMutexData { kind, address })))
     })?;
 
     // Check that the mutex has not been moved since last use.
@@ -155,7 +155,7 @@ fn mutex_get_id<'tcx>(
         throw_ub_format!("pthread_mutex_t can't be moved after first use")
     }
 
-    Ok(id)
+    interp_ok(id)
 }
 
 /// Returns the kind of a static initializer.
@@ -163,7 +163,7 @@ fn mutex_kind_from_static_initializer<'tcx>(
     ecx: &MiriInterpCx<'tcx>,
     mutex: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx, MutexKind> {
-    Ok(match &*ecx.tcx.sess.target.os {
+    interp_ok(match &*ecx.tcx.sess.target.os {
         // Only linux has static initializers other than PTHREAD_MUTEX_DEFAULT.
         "linux" => {
             let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 };
@@ -186,7 +186,7 @@ fn mutex_translate_kind<'tcx>(
     ecx: &MiriInterpCx<'tcx>,
     kind: i32,
 ) -> InterpResult<'tcx, MutexKind> {
-    Ok(if kind == (ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL")) {
+    interp_ok(if kind == (ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL")) {
         MutexKind::Normal
     } else if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK") {
         MutexKind::ErrorCheck
@@ -237,7 +237,7 @@ fn rwlock_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
         );
     }
 
-    Ok(offset)
+    interp_ok(offset)
 }
 
 fn rwlock_get_id<'tcx>(
@@ -248,7 +248,7 @@ fn rwlock_get_id<'tcx>(
     let address = rwlock.ptr().addr().bytes();
 
     let id = ecx.rwlock_get_or_create_id(&rwlock, rwlock_id_offset(ecx)?, |_| {
-        Ok(Some(Box::new(AdditionalRwLockData { address })))
+        interp_ok(Some(Box::new(AdditionalRwLockData { address })))
     })?;
 
     // Check that the rwlock has not been moved since last use.
@@ -259,7 +259,7 @@ fn rwlock_get_id<'tcx>(
         throw_ub_format!("pthread_rwlock_t can't be moved after first use")
     }
 
-    Ok(id)
+    interp_ok(id)
 }
 
 // pthread_condattr_t.
@@ -268,7 +268,7 @@ fn rwlock_get_id<'tcx>(
 
 #[inline]
 fn condattr_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
-    Ok(match &*ecx.tcx.sess.target.os {
+    interp_ok(match &*ecx.tcx.sess.target.os {
         "linux" | "illumos" | "solaris" | "freebsd" | "android" => 0,
         // macOS does not have a clock attribute.
         os => throw_unsup_format!("`pthread_condattr` clock field is not supported on {os}"),
@@ -292,7 +292,7 @@ fn cond_translate_clock_id<'tcx>(
     ecx: &MiriInterpCx<'tcx>,
     raw_id: i32,
 ) -> InterpResult<'tcx, ClockId> {
-    Ok(if raw_id == ecx.eval_libc_i32("CLOCK_REALTIME") {
+    interp_ok(if raw_id == ecx.eval_libc_i32("CLOCK_REALTIME") {
         ClockId::Realtime
     } else if raw_id == ecx.eval_libc_i32("CLOCK_MONOTONIC") {
         ClockId::Monotonic
@@ -342,7 +342,7 @@ fn cond_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
         );
     }
 
-    Ok(offset)
+    interp_ok(offset)
 }
 
 #[derive(Debug, Clone, Copy)]
@@ -369,7 +369,7 @@ fn cond_get_id<'tcx>(
     let address = cond.ptr().addr().bytes();
     let id = ecx.condvar_get_or_create_id(&cond, cond_id_offset(ecx)?, |_ecx| {
         // This used the static initializer. The clock there is always CLOCK_REALTIME.
-        Ok(Some(Box::new(AdditionalCondData { address, clock_id: ClockId::Realtime })))
+        interp_ok(Some(Box::new(AdditionalCondData { address, clock_id: ClockId::Realtime })))
     })?;
 
     // Check that the mutex has not been moved since last use.
@@ -380,7 +380,7 @@ fn cond_get_id<'tcx>(
         throw_ub_format!("pthread_cond_t can't be moved after first use")
     }
 
-    Ok(id)
+    interp_ok(id)
 }
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
@@ -390,7 +390,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         mutexattr_set_kind(this, attr_op, PTHREAD_MUTEX_KIND_UNCHANGED)?;
 
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_mutexattr_settype(
@@ -411,10 +411,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             mutexattr_set_kind(this, attr_op, kind)?;
         } else {
             let einval = this.eval_libc_i32("EINVAL");
-            return Ok(Scalar::from_i32(einval));
+            return interp_ok(Scalar::from_i32(einval));
         }
 
-        Ok(Scalar::from_i32(0))
+        interp_ok(Scalar::from_i32(0))
     }
 
     fn pthread_mutexattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
@@ -439,7 +439,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             &this.deref_pointer_as(attr_op, this.libc_ty_layout("pthread_mutexattr_t"))?,
         )?;
 
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_mutex_init(
@@ -458,7 +458,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         mutex_create(this, mutex_op, kind)?;
 
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_mutex_lock(
@@ -478,12 +478,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             let owner_thread = this.mutex_get_owner(id);
             if owner_thread != this.active_thread() {
                 this.mutex_enqueue_and_block(id, Some((Scalar::from_i32(0), dest.clone())));
-                return Ok(());
+                return interp_ok(());
             } else {
                 // Trying to acquire the same mutex again.
                 match kind {
                     MutexKind::Default =>
-                        throw_ub_format!("trying to acquire already locked default mutex"),
+                        throw_ub_format!(
+                            "trying to acquire default mutex already locked by the current thread"
+                        ),
                     MutexKind::Normal => throw_machine_stop!(TerminationInfo::Deadlock),
                     MutexKind::ErrorCheck => this.eval_libc_i32("EDEADLK"),
                     MutexKind::Recursive => {
@@ -498,7 +500,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             0
         };
         this.write_scalar(Scalar::from_i32(ret), dest)?;
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@@ -510,7 +512,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             .expect("data should always exist for pthread mutexes")
             .kind;
 
-        Ok(Scalar::from_i32(if this.mutex_is_locked(id) {
+        interp_ok(Scalar::from_i32(if this.mutex_is_locked(id) {
             let owner_thread = this.mutex_get_owner(id);
             if owner_thread != this.active_thread() {
                 this.eval_libc_i32("EBUSY")
@@ -542,7 +544,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         if let Some(_old_locked_count) = this.mutex_unlock(id)? {
             // The mutex was locked by the current thread.
-            Ok(Scalar::from_i32(0))
+            interp_ok(Scalar::from_i32(0))
         } else {
             // The mutex was locked by another thread or not locked at all. See
             // the “Unlock When Not Owner” column in
@@ -557,7 +559,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         "unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread"
                     ),
                 MutexKind::ErrorCheck | MutexKind::Recursive =>
-                    Ok(Scalar::from_i32(this.eval_libc_i32("EPERM"))),
+                    interp_ok(Scalar::from_i32(this.eval_libc_i32("EPERM"))),
             }
         }
     }
@@ -579,7 +581,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         )?;
         // FIXME: delete interpreter state associated with this mutex.
 
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_rwlock_rdlock(
@@ -598,7 +600,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.write_null(dest)?;
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@@ -607,10 +609,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let id = rwlock_get_id(this, rwlock_op)?;
 
         if this.rwlock_is_write_locked(id) {
-            Ok(Scalar::from_i32(this.eval_libc_i32("EBUSY")))
+            interp_ok(Scalar::from_i32(this.eval_libc_i32("EBUSY")))
         } else {
             this.rwlock_reader_lock(id);
-            Ok(Scalar::from_i32(0))
+            interp_ok(Scalar::from_i32(0))
         }
     }
 
@@ -642,7 +644,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.write_null(dest)?;
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_rwlock_trywrlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@@ -651,10 +653,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let id = rwlock_get_id(this, rwlock_op)?;
 
         if this.rwlock_is_locked(id) {
-            Ok(Scalar::from_i32(this.eval_libc_i32("EBUSY")))
+            interp_ok(Scalar::from_i32(this.eval_libc_i32("EBUSY")))
         } else {
             this.rwlock_writer_lock(id);
-            Ok(Scalar::from_i32(0))
+            interp_ok(Scalar::from_i32(0))
         }
     }
 
@@ -665,7 +667,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         #[allow(clippy::if_same_then_else)]
         if this.rwlock_reader_unlock(id)? || this.rwlock_writer_unlock(id)? {
-            Ok(())
+            interp_ok(())
         } else {
             throw_ub_format!("unlocked an rwlock that was not locked by the active thread");
         }
@@ -688,7 +690,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         )?;
         // FIXME: delete interpreter state associated with this rwlock.
 
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_condattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
@@ -703,7 +705,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             condattr_set_clock_id(this, attr_op, default_clock_id)?;
         }
 
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_condattr_setclock(
@@ -720,10 +722,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             condattr_set_clock_id(this, attr_op, clock_id)?;
         } else {
             let einval = this.eval_libc_i32("EINVAL");
-            return Ok(Scalar::from_i32(einval));
+            return interp_ok(Scalar::from_i32(einval));
         }
 
-        Ok(Scalar::from_i32(0))
+        interp_ok(Scalar::from_i32(0))
     }
 
     fn pthread_condattr_getclock(
@@ -736,7 +738,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let clock_id = condattr_get_clock_id(this, attr_op)?;
         this.write_scalar(Scalar::from_i32(clock_id), &this.deref_pointer(clk_id_op)?)?;
 
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
@@ -754,7 +756,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             &this.deref_pointer_as(attr_op, this.libc_ty_layout("pthread_condattr_t"))?,
         )?;
 
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_cond_init(
@@ -781,21 +783,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Some(Box::new(AdditionalCondData { address, clock_id })),
         )?;
 
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
         let id = cond_get_id(this, cond_op)?;
         this.condvar_signal(id)?;
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_cond_broadcast(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
         let id = cond_get_id(this, cond_op)?;
         while this.condvar_signal(id)? {}
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_cond_wait(
@@ -818,7 +820,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             dest.clone(),
         )?;
 
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_cond_timedwait(
@@ -845,7 +847,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             None => {
                 let einval = this.eval_libc("EINVAL");
                 this.write_scalar(einval, dest)?;
-                return Ok(());
+                return interp_ok(());
             }
         };
         let timeout_clock = match clock_id {
@@ -865,7 +867,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             dest.clone(),
         )?;
 
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
@@ -882,6 +884,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.write_uninit(&this.deref_pointer_as(cond_op, this.libc_ty_layout("pthread_cond_t"))?)?;
         // FIXME: delete interpreter state associated with this condvar.
 
-        Ok(())
+        interp_ok(())
     }
 }
diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs
index 56e8270aa62..5515524f2f1 100644
--- a/src/tools/miri/src/shims/unix/thread.rs
+++ b/src/tools/miri/src/shims/unix/thread.rs
@@ -1,6 +1,7 @@
-use crate::*;
 use rustc_target::spec::abi::Abi;
 
+use crate::*;
+
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn pthread_create(
@@ -26,7 +27,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.machine.layouts.mut_raw_ptr,
         )?;
 
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_join(&mut self, thread: &OpTy<'tcx>, retval: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
@@ -40,7 +41,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let thread_id = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?;
         this.join_thread_exclusive(thread_id.try_into().expect("thread ID should fit in u32"))?;
 
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
@@ -52,14 +53,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             /*allow_terminated_joined*/ false,
         )?;
 
-        Ok(())
+        interp_ok(())
     }
 
     fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let thread_id = this.active_thread();
-        Ok(Scalar::from_uint(thread_id.to_u32(), this.libc_ty_layout("pthread_t").size))
+        interp_ok(Scalar::from_uint(thread_id.to_u32(), this.libc_ty_layout("pthread_t").size))
     }
 
     /// Set the name of the current thread. `max_name_len` is the maximal length of the name
@@ -80,12 +81,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // Comparing with `>=` to account for null terminator.
         if name.len() >= max_name_len {
-            return Ok(this.eval_libc("ERANGE"));
+            return interp_ok(this.eval_libc("ERANGE"));
         }
 
         this.set_thread_name(thread, name);
 
-        Ok(Scalar::from_u32(0))
+        interp_ok(Scalar::from_u32(0))
     }
 
     fn pthread_getname_np(
@@ -105,7 +106,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let name = this.get_thread_name(thread).unwrap_or(b"<unnamed>").to_owned();
         let (success, _written) = this.write_c_str(&name, name_out, len)?;
 
-        Ok(if success { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") })
+        interp_ok(if success { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") })
     }
 
     fn sched_yield(&mut self) -> InterpResult<'tcx, ()> {
@@ -113,6 +114,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         this.yield_active_thread();
 
-        Ok(())
+        interp_ok(())
     }
 }
diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs
index db6872319ea..faa54c6a75e 100644
--- a/src/tools/miri/src/shims/unix/unnamed_socket.rs
+++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs
@@ -5,14 +5,15 @@
 use std::cell::{Cell, OnceCell, RefCell};
 use std::collections::VecDeque;
 use std::io;
-use std::io::{Error, ErrorKind, Read};
+use std::io::{ErrorKind, Read};
 
 use rustc_target::abi::Size;
 
+use crate::concurrency::VClock;
 use crate::shims::unix::fd::{FileDescriptionRef, WeakFileDescriptionRef};
 use crate::shims::unix::linux::epoll::{EpollReadyEvents, EvalContextExt as _};
 use crate::shims::unix::*;
-use crate::{concurrency::VClock, *};
+use crate::*;
 
 /// The maximum capacity of the socketpair buffer in bytes.
 /// This number is arbitrary as the value can always
@@ -102,7 +103,7 @@ impl FileDescription for AnonSocket {
                 epoll_ready_events.epollerr = true;
             }
         }
-        Ok(epoll_ready_events)
+        interp_ok(epoll_ready_events)
     }
 
     fn close<'tcx>(
@@ -121,7 +122,7 @@ impl FileDescription for AnonSocket {
             // Notify peer fd that close has happened, since that can unblock reads and writes.
             ecx.check_and_update_readiness(&peer_fd)?;
         }
-        Ok(Ok(()))
+        interp_ok(Ok(()))
     }
 
     fn read<'tcx>(
@@ -137,8 +138,7 @@ impl FileDescription for AnonSocket {
 
         // Always succeed on read size 0.
         if len == 0 {
-            let result = Ok(0);
-            return ecx.return_read_bytes_and_count(ptr, &bytes, result, dest);
+            return ecx.return_read_success(ptr, &bytes, 0, dest);
         }
 
         let Some(readbuf) = &self.readbuf else {
@@ -151,8 +151,7 @@ impl FileDescription for AnonSocket {
             if self.peer_fd().upgrade().is_none() {
                 // Socketpair with no peer and empty buffer.
                 // 0 bytes successfully read indicates end-of-file.
-                let result = Ok(0);
-                return ecx.return_read_bytes_and_count(ptr, &bytes, result, dest);
+                return ecx.return_read_success(ptr, &bytes, 0, dest);
             } else {
                 if self.is_nonblock {
                     // Non-blocking socketpair with writer and empty buffer.
@@ -160,8 +159,7 @@ impl FileDescription for AnonSocket {
                     // EAGAIN or EWOULDBLOCK can be returned for socket,
                     // POSIX.1-2001 allows either error to be returned for this case.
                     // Since there is no ErrorKind for EAGAIN, WouldBlock is used.
-                    let result = Err(Error::from(ErrorKind::WouldBlock));
-                    return ecx.return_read_bytes_and_count(ptr, &bytes, result, dest);
+                    return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
                 } else {
                     // Blocking socketpair with writer and empty buffer.
                     // FIXME: blocking is currently not supported
@@ -193,8 +191,7 @@ impl FileDescription for AnonSocket {
             ecx.check_and_update_readiness(&peer_fd)?;
         }
 
-        let result = Ok(actual_read_size);
-        ecx.return_read_bytes_and_count(ptr, &bytes, result, dest)
+        ecx.return_read_success(ptr, &bytes, actual_read_size, dest)
     }
 
     fn write<'tcx>(
@@ -209,16 +206,14 @@ impl FileDescription for AnonSocket {
         // Always succeed on write size 0.
         // ("If count is zero and fd refers to a file other than a regular file, the results are not specified.")
         if len == 0 {
-            let result = Ok(0);
-            return ecx.return_written_byte_count_or_error(result, dest);
+            return ecx.return_write_success(0, dest);
         }
 
         // We are writing to our peer's readbuf.
         let Some(peer_fd) = self.peer_fd().upgrade() else {
             // If the upgrade from Weak to Rc fails, it indicates that all read ends have been
             // closed.
-            let result = Err(Error::from(ErrorKind::BrokenPipe));
-            return ecx.return_written_byte_count_or_error(result, dest);
+            return ecx.set_last_error_and_return(ErrorKind::BrokenPipe, dest);
         };
 
         let Some(writebuf) = &peer_fd.downcast::<AnonSocket>().unwrap().readbuf else {
@@ -232,8 +227,7 @@ impl FileDescription for AnonSocket {
         if available_space == 0 {
             if self.is_nonblock {
                 // Non-blocking socketpair with a full buffer.
-                let result = Err(Error::from(ErrorKind::WouldBlock));
-                return ecx.return_written_byte_count_or_error(result, dest);
+                return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
             } else {
                 // Blocking socketpair with a full buffer.
                 throw_unsup_format!("socketpair write: blocking isn't supported yet");
@@ -255,8 +249,7 @@ impl FileDescription for AnonSocket {
         // The kernel does this even if the fd was already readable before, so we follow suit.
         ecx.check_and_update_readiness(&peer_fd)?;
 
-        let result = Ok(actual_write_size);
-        ecx.return_written_byte_count_or_error(result, dest)
+        ecx.return_write_success(actual_write_size, dest)
     }
 }
 
@@ -343,7 +336,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.write_scalar(sv0, &sv)?;
         this.write_scalar(sv1, &sv.offset(sv.layout.size, sv.layout, this)?)?;
 
-        Ok(Scalar::from_i32(0))
+        interp_ok(Scalar::from_i32(0))
     }
 
     fn pipe2(
@@ -395,6 +388,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.write_scalar(pipefd0, &pipefd)?;
         this.write_scalar(pipefd1, &pipefd.offset(pipefd.layout.size, pipefd.layout, this)?)?;
 
-        Ok(Scalar::from_i32(0))
+        interp_ok(Scalar::from_i32(0))
     }
 }
diff --git a/src/tools/miri/src/shims/wasi/foreign_items.rs b/src/tools/miri/src/shims/wasi/foreign_items.rs
index e9fe90081d0..b5de950de9a 100644
--- a/src/tools/miri/src/shims/wasi/foreign_items.rs
+++ b/src/tools/miri/src/shims/wasi/foreign_items.rs
@@ -33,8 +33,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_pointer(res, dest)?;
             }
 
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs
index 178b0a1a461..72c1fb58023 100644
--- a/src/tools/miri/src/shims/windows/env.rs
+++ b/src/tools/miri/src/shims/windows/env.rs
@@ -4,8 +4,8 @@ use std::io::ErrorKind;
 
 use rustc_data_structures::fx::FxHashMap;
 
-use crate::*;
 use self::helpers::windows_check_buffer_size;
+use crate::*;
 
 #[derive(Default)]
 pub struct WindowsEnvVars {
@@ -24,12 +24,12 @@ impl WindowsEnvVars {
         _ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>,
         env_vars: FxHashMap<OsString, OsString>,
     ) -> InterpResult<'tcx, Self> {
-        Ok(Self { map: env_vars })
+        interp_ok(Self { map: env_vars })
     }
 
     /// Implementation detail for [`InterpCx::get_env_var`].
     pub(crate) fn get<'tcx>(&self, name: &OsStr) -> InterpResult<'tcx, Option<OsString>> {
-        Ok(self.map.get(name).cloned())
+        interp_ok(self.map.get(name).cloned())
     }
 }
 
@@ -52,7 +52,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let buf_size = this.read_scalar(size_op)?.to_u32()?; // in characters
 
         let name = this.read_os_str_from_wide_str(name_ptr)?;
-        Ok(match this.machine.env_vars.windows().map.get(&name).cloned() {
+        interp_ok(match this.machine.env_vars.windows().map.get(&name).cloned() {
             Some(val) => {
                 Scalar::from_u32(windows_check_buffer_size(this.write_os_str_to_wide_str(
                     &val,
@@ -89,7 +89,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let envblock_ptr =
             this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::Runtime.into())?;
         // If the function succeeds, the return value is a pointer to the environment block of the current process.
-        Ok(envblock_ptr)
+        interp_ok(envblock_ptr)
     }
 
     #[allow(non_snake_case)]
@@ -100,7 +100,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let env_block_ptr = this.read_pointer(env_block_op)?;
         this.deallocate_ptr(env_block_ptr, None, MiriMemoryKind::Runtime.into())?;
         // If the function succeeds, the return value is nonzero.
-        Ok(Scalar::from_i32(1))
+        interp_ok(Scalar::from_i32(1))
     }
 
     #[allow(non_snake_case)]
@@ -128,11 +128,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         } else if this.ptr_is_null(value_ptr)? {
             // Delete environment variable `{name}` if it exists.
             this.machine.env_vars.windows_mut().map.remove(&name);
-            Ok(this.eval_windows("c", "TRUE"))
+            interp_ok(this.eval_windows("c", "TRUE"))
         } else {
             let value = this.read_os_str_from_wide_str(value_ptr)?;
             this.machine.env_vars.windows_mut().map.insert(name, value);
-            Ok(this.eval_windows("c", "TRUE"))
+            interp_ok(this.eval_windows("c", "TRUE"))
         }
     }
 
@@ -150,8 +150,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`GetCurrentDirectoryW`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
-            return Ok(Scalar::from_u32(0));
+            this.set_last_error(ErrorKind::PermissionDenied)?;
+            return interp_ok(Scalar::from_u32(0));
         }
 
         // If we cannot get the current directory, we return 0
@@ -159,13 +159,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Ok(cwd) => {
                 // This can in fact return 0. It is up to the caller to set last_error to 0
                 // beforehand and check it afterwards to exclude that case.
-                return Ok(Scalar::from_u32(windows_check_buffer_size(
+                return interp_ok(Scalar::from_u32(windows_check_buffer_size(
                     this.write_path_to_wide_str(&cwd, buf, size)?,
                 )));
             }
-            Err(e) => this.set_last_error_from_io_error(e)?,
+            Err(e) => this.set_last_error(e)?,
         }
-        Ok(Scalar::from_u32(0))
+        interp_ok(Scalar::from_u32(0))
     }
 
     #[allow(non_snake_case)]
@@ -182,16 +182,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`SetCurrentDirectoryW`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
+            this.set_last_error(ErrorKind::PermissionDenied)?;
 
-            return Ok(this.eval_windows("c", "FALSE"));
+            return interp_ok(this.eval_windows("c", "FALSE"));
         }
 
         match env::set_current_dir(path) {
-            Ok(()) => Ok(this.eval_windows("c", "TRUE")),
+            Ok(()) => interp_ok(this.eval_windows("c", "TRUE")),
             Err(e) => {
-                this.set_last_error_from_io_error(e)?;
-                Ok(this.eval_windows("c", "FALSE"))
+                this.set_last_error(e)?;
+                interp_ok(this.eval_windows("c", "FALSE"))
             }
         }
     }
@@ -201,7 +201,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         this.assert_target_os("windows", "GetCurrentProcessId");
 
-        Ok(Scalar::from_u32(this.get_pid()))
+        interp_ok(Scalar::from_u32(this.get_pid()))
     }
 
     #[allow(non_snake_case)]
@@ -227,7 +227,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         }
 
         // See <https://learn.microsoft.com/en-us/windows/win32/api/userenv/nf-userenv-getuserprofiledirectoryw> for docs.
-        Ok(match directories::UserDirs::new() {
+        interp_ok(match directories::UserDirs::new() {
             Some(dirs) => {
                 let home = dirs.home_dir();
                 let size_avail = if this.ptr_is_null(size.ptr())? {
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index f385ed4ac11..dee778876f6 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -1,17 +1,15 @@
 use std::ffi::OsStr;
-use std::io;
-use std::iter;
 use std::path::{self, Path, PathBuf};
-use std::str;
+use std::{io, iter, str};
 
 use rustc_span::Symbol;
 use rustc_target::abi::{Align, Size};
 use rustc_target::spec::abi::Abi;
 
+use self::shims::windows::handle::{Handle, PseudoHandle};
 use crate::shims::os_str::bytes_to_os_str;
 use crate::shims::windows::*;
 use crate::*;
-use self::shims::windows::handle::{Handle, PseudoHandle};
 
 pub fn is_dyn_sym(name: &str) -> bool {
     // std does dynamic detection for these symbols
@@ -23,8 +21,8 @@ pub fn is_dyn_sym(name: &str) -> bool {
 
 #[cfg(windows)]
 fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
-    // We are on Windows so we can simply lte the host do this.
-    return Ok(path::absolute(path));
+    // We are on Windows so we can simply let the host do this.
+    interp_ok(path::absolute(path))
 }
 
 #[cfg(unix)]
@@ -35,7 +33,7 @@ fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
     // If it starts with `//` (these were backslashes but are already converted)
     // then this is a magic special path, we just leave it unchanged.
     if bytes.get(0).copied() == Some(b'/') && bytes.get(1).copied() == Some(b'/') {
-        return Ok(Ok(path.into()));
+        return interp_ok(Ok(path.into()));
     };
     // Special treatment for Windows' magic filenames: they are treated as being relative to `\\.\`.
     let magic_filenames = &[
@@ -45,7 +43,7 @@ fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
     if magic_filenames.iter().any(|m| m.as_bytes() == bytes) {
         let mut result: Vec<u8> = br"//./".into();
         result.extend(bytes);
-        return Ok(Ok(bytes_to_os_str(&result)?.into()));
+        return interp_ok(Ok(bytes_to_os_str(&result)?.into()));
     }
     // Otherwise we try to do something kind of close to what Windows does, but this is probably not
     // right in all cases. We iterate over the components between `/`, and remove trailing `.`,
@@ -73,7 +71,7 @@ fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
         }
     }
     // Let the host `absolute` function do working-dir handling
-    Ok(path::absolute(bytes_to_os_str(&result)?))
+    interp_ok(path::absolute(bytes_to_os_str(&result)?))
 }
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
@@ -229,7 +227,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let filename = this.read_path_from_wide_str(filename)?;
                 let result = match win_absolute(&filename)? {
                     Err(err) => {
-                        this.set_last_error_from_io_error(err)?;
+                        this.set_last_error(err)?;
                         Scalar::from_u32(0) // return zero upon failure
                     }
                     Ok(abs_filename) => {
@@ -771,12 +769,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // This function looks and behaves excatly like miri_start_unwind.
                 let [payload] = this.check_shim(abi, Abi::C { unwind: true }, link_name, args)?;
                 this.handle_miri_start_unwind(payload)?;
-                return Ok(EmulateItemResult::NeedsUnwind);
+                return interp_ok(EmulateItemResult::NeedsUnwind);
             }
 
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
 
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs
index ec461a4cd36..69d78f58bed 100644
--- a/src/tools/miri/src/shims/windows/handle.rs
+++ b/src/tools/miri/src/shims/windows/handle.rs
@@ -1,6 +1,7 @@
-use rustc_target::abi::HasDataLayout;
 use std::mem::variant_count;
 
+use rustc_target::abi::HasDataLayout;
+
 use crate::*;
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -138,10 +139,10 @@ impl Handle {
             signed_handle as u32
         } else {
             // if a handle doesn't fit in an i32, it isn't valid.
-            return Ok(None);
+            return interp_ok(None);
         };
 
-        Ok(Self::from_packed(handle))
+        interp_ok(Self::from_packed(handle))
     }
 }
 
@@ -166,6 +167,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             _ => this.invalid_handle("CloseHandle")?,
         }
 
-        Ok(())
+        interp_ok(())
     }
 }
diff --git a/src/tools/miri/src/shims/windows/mod.rs b/src/tools/miri/src/shims/windows/mod.rs
index 537c724e526..892bd6924fc 100644
--- a/src/tools/miri/src/shims/windows/mod.rs
+++ b/src/tools/miri/src/shims/windows/mod.rs
@@ -5,9 +5,8 @@ mod handle;
 mod sync;
 mod thread;
 
-pub use self::env::WindowsEnvVars;
 // All the Windows-specific extension traits
-pub use self::env::EvalContextExt as _;
+pub use self::env::{EvalContextExt as _, WindowsEnvVars};
 pub use self::handle::EvalContextExt as _;
 pub use self::sync::EvalContextExt as _;
 pub use self::thread::EvalContextExt as _;
diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs
index 51b0129356b..6755c23039e 100644
--- a/src/tools/miri/src/shims/windows/sync.rs
+++ b/src/tools/miri/src/shims/windows/sync.rs
@@ -24,7 +24,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
         dest: &MPlaceTy<'tcx>,
     ) -> InterpResult<'tcx, bool> {
         let this = self.eval_context_mut();
-        Ok(match this.init_once_status(id) {
+        interp_ok(match this.init_once_status(id) {
             InitOnceStatus::Uninitialized => {
                 this.init_once_begin(id);
                 this.write_scalar(this.eval_windows("c", "TRUE"), pending_place)?;
@@ -70,7 +70,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         if this.init_once_try_begin(id, &pending_place, dest)? {
             // Done!
-            return Ok(());
+            return interp_ok(());
         }
 
         // We have to block, and then try again when we are woken up.
@@ -86,11 +86,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 @unblock = |this| {
                     let ret = this.init_once_try_begin(id, &pending_place, &dest)?;
                     assert!(ret, "we were woken up but init_once_try_begin still failed");
-                    Ok(())
+                    interp_ok(())
                 }
             ),
         );
-        return Ok(());
+        interp_ok(())
     }
 
     fn InitOnceComplete(
@@ -130,7 +130,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.init_once_fail(id)?;
         }
 
-        Ok(this.eval_windows("c", "TRUE"))
+        interp_ok(this.eval_windows("c", "TRUE"))
     }
 
     fn WaitOnAddress(
@@ -154,7 +154,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             let invalid_param = this.eval_windows("c", "ERROR_INVALID_PARAMETER");
             this.set_last_error(invalid_param)?;
             this.write_scalar(Scalar::from_i32(0), dest)?;
-            return Ok(());
+            return interp_ok(());
         };
         let size = Size::from_bytes(size);
 
@@ -188,7 +188,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         this.write_scalar(Scalar::from_i32(1), dest)?;
 
-        Ok(())
+        interp_ok(())
     }
 
     fn WakeByAddressSingle(&mut self, ptr_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
@@ -202,7 +202,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let addr = ptr.addr().bytes();
         this.futex_wake(addr, u32::MAX)?;
 
-        Ok(())
+        interp_ok(())
     }
     fn WakeByAddressAll(&mut self, ptr_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
@@ -215,6 +215,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let addr = ptr.addr().bytes();
         while this.futex_wake(addr, u32::MAX)? {}
 
-        Ok(())
+        interp_ok(())
     }
 }
diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs
index 9f93fc5f081..a920abea3a8 100644
--- a/src/tools/miri/src/shims/windows/thread.rs
+++ b/src/tools/miri/src/shims/windows/thread.rs
@@ -1,8 +1,8 @@
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_target::spec::abi::Abi;
 
-use crate::*;
 use self::shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle};
+use crate::*;
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 
@@ -79,6 +79,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         this.join_thread(thread)?;
 
-        Ok(0)
+        interp_ok(0)
     }
 }
diff --git a/src/tools/miri/src/shims/x86/aesni.rs b/src/tools/miri/src/shims/x86/aesni.rs
index dbbae0731e0..3a8138654fd 100644
--- a/src/tools/miri/src/shims/x86/aesni.rs
+++ b/src/tools/miri/src/shims/x86/aesni.rs
@@ -123,9 +123,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             // TODO: Implement the `llvm.x86.aesni.aeskeygenassist` when possible
             // with an external crate.
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
 
@@ -162,5 +162,5 @@ fn aes_round<'tcx>(
         this.write_scalar(Scalar::from_u128(res), &dest)?;
     }
 
-    Ok(())
+    interp_ok(())
 }
diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs
index bdc4fc94469..080e7c8ce0b 100644
--- a/src/tools/miri/src/shims/x86/avx.rs
+++ b/src/tools/miri/src/shims/x86/avx.rs
@@ -1,4 +1,4 @@
-use rustc_apfloat::{ieee::Double, ieee::Single};
+use rustc_apfloat::ieee::{Double, Single};
 use rustc_middle::mir;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf as _;
@@ -348,8 +348,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // The only thing that needs to be ensured is the correct calling convention.
                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
             }
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs
index 1dda1a10a05..331b693a3e4 100644
--- a/src/tools/miri/src/shims/x86/avx2.rs
+++ b/src/tools/miri/src/shims/x86/avx2.rs
@@ -435,8 +435,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                 shift_simd_by_simd(this, left, right, which, dest)?;
             }
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/x86/bmi.rs b/src/tools/miri/src/shims/x86/bmi.rs
index e70757f4397..59e76abf179 100644
--- a/src/tools/miri/src/shims/x86/bmi.rs
+++ b/src/tools/miri/src/shims/x86/bmi.rs
@@ -30,7 +30,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.expect_target_feature_for_intrinsic(link_name, target_feature)?;
 
         if is_64_bit && this.tcx.sess.target.arch != "x86_64" {
-            return Ok(EmulateItemResult::NotSupported);
+            return interp_ok(EmulateItemResult::NotSupported);
         }
 
         let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -93,7 +93,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
                 result
             }
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         };
 
         let result = if is_64_bit {
@@ -103,6 +103,6 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
         this.write_scalar(result, dest)?;
 
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/x86/gfni.rs b/src/tools/miri/src/shims/x86/gfni.rs
new file mode 100644
index 00000000000..c91b8c835f2
--- /dev/null
+++ b/src/tools/miri/src/shims/x86/gfni.rs
@@ -0,0 +1,196 @@
+use rustc_span::Symbol;
+use rustc_target::spec::abi::Abi;
+
+use crate::*;
+
+impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
+pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
+    fn emulate_x86_gfni_intrinsic(
+        &mut self,
+        link_name: Symbol,
+        abi: Abi,
+        args: &[OpTy<'tcx>],
+        dest: &MPlaceTy<'tcx>,
+    ) -> InterpResult<'tcx, EmulateItemResult> {
+        let this = self.eval_context_mut();
+
+        // Prefix should have already been checked.
+        let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.").unwrap();
+
+        this.expect_target_feature_for_intrinsic(link_name, "gfni")?;
+        if unprefixed_name.ends_with(".256") {
+            this.expect_target_feature_for_intrinsic(link_name, "avx")?;
+        } else if unprefixed_name.ends_with(".512") {
+            this.expect_target_feature_for_intrinsic(link_name, "avx512f")?;
+        }
+
+        match unprefixed_name {
+            // Used to implement the `_mm{, 256, 512}_gf2p8affine_epi64_epi8` functions.
+            // See `affine_transform` for details.
+            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affine_
+            "vgf2p8affineqb.128" | "vgf2p8affineqb.256" | "vgf2p8affineqb.512" => {
+                let [left, right, imm8] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                affine_transform(this, left, right, imm8, dest, /* inverse */ false)?;
+            }
+            // Used to implement the `_mm{, 256, 512}_gf2p8affineinv_epi64_epi8` functions.
+            // See `affine_transform` for details.
+            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affineinv
+            "vgf2p8affineinvqb.128" | "vgf2p8affineinvqb.256" | "vgf2p8affineinvqb.512" => {
+                let [left, right, imm8] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                affine_transform(this, left, right, imm8, dest, /* inverse */ true)?;
+            }
+            // Used to implement the `_mm{, 256, 512}_gf2p8mul_epi8` functions.
+            // Multiplies packed 8-bit integers in `left` and `right` in the finite field GF(2^8)
+            // and store the results in `dst`. The field GF(2^8) is represented in
+            // polynomial representation with the reduction polynomial x^8 + x^4 + x^3 + x + 1.
+            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8mul
+            "vgf2p8mulb.128" | "vgf2p8mulb.256" | "vgf2p8mulb.512" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.project_to_simd(left)?;
+                let (right, right_len) = this.project_to_simd(right)?;
+                let (dest, dest_len) = this.project_to_simd(dest)?;
+
+                assert_eq!(left_len, right_len);
+                assert_eq!(dest_len, right_len);
+
+                for i in 0..dest_len {
+                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u8()?;
+                    let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u8()?;
+                    let dest = this.project_index(&dest, i)?;
+                    this.write_scalar(Scalar::from_u8(gf2p8_mul(left, right)), &dest)?;
+                }
+            }
+            _ => return interp_ok(EmulateItemResult::NotSupported),
+        }
+        interp_ok(EmulateItemResult::NeedsReturn)
+    }
+}
+
+/// Calculates the affine transformation `right * left + imm8` inside the finite field GF(2^8).
+/// `right` is an 8x8 bit matrix, `left` and `imm8` are bit vectors.
+/// If `inverse` is set, then the inverse transformation with respect to the reduction polynomial
+/// x^8 + x^4 + x^3 + x + 1 is performed instead.
+fn affine_transform<'tcx>(
+    this: &mut MiriInterpCx<'tcx>,
+    left: &OpTy<'tcx>,
+    right: &OpTy<'tcx>,
+    imm8: &OpTy<'tcx>,
+    dest: &MPlaceTy<'tcx>,
+    inverse: bool,
+) -> InterpResult<'tcx, ()> {
+    let (left, left_len) = this.project_to_simd(left)?;
+    let (right, right_len) = this.project_to_simd(right)?;
+    let (dest, dest_len) = this.project_to_simd(dest)?;
+
+    assert_eq!(dest_len, right_len);
+    assert_eq!(dest_len, left_len);
+
+    let imm8 = this.read_scalar(imm8)?.to_u8()?;
+
+    // Each 8x8 bit matrix gets multiplied with eight bit vectors.
+    // Therefore, the iteration is done in chunks of eight.
+    for i in (0..dest_len).step_by(8) {
+        // Get the bit matrix.
+        let mut matrix = [0u8; 8];
+        for j in 0..8 {
+            matrix[usize::try_from(j).unwrap()] =
+                this.read_scalar(&this.project_index(&right, i.wrapping_add(j))?)?.to_u8()?;
+        }
+
+        // Multiply the matrix with the vector and perform the addition.
+        for j in 0..8 {
+            let index = i.wrapping_add(j);
+            let left = this.read_scalar(&this.project_index(&left, index)?)?.to_u8()?;
+            let left = if inverse { TABLE[usize::from(left)] } else { left };
+
+            let mut res = 0;
+
+            // Do the matrix multiplication.
+            for bit in 0u8..8 {
+                let mut b = matrix[usize::from(bit)] & left;
+
+                // Calculate the parity bit.
+                b = (b & 0b1111) ^ (b >> 4);
+                b = (b & 0b11) ^ (b >> 2);
+                b = (b & 0b1) ^ (b >> 1);
+
+                res |= b << 7u8.wrapping_sub(bit);
+            }
+
+            // Perform the addition.
+            res ^= imm8;
+
+            let dest = this.project_index(&dest, index)?;
+            this.write_scalar(Scalar::from_u8(res), &dest)?;
+        }
+    }
+
+    interp_ok(())
+}
+
+/// A lookup table for computing the inverse byte for the inverse affine transformation.
+// This is a evaluated at compile time. Trait based conversion is not available.
+/// See <https://www.corsix.org/content/galois-field-instructions-2021-cpus> for the
+/// definition of `gf_inv` which was used for the creation of this table.
+#[allow(clippy::cast_possible_truncation)]
+static TABLE: [u8; 256] = {
+    let mut array = [0; 256];
+
+    let mut i = 1;
+    while i < 256 {
+        let mut x = i as u8;
+        let mut y = gf2p8_mul(x, x);
+        x = y;
+        let mut j = 2;
+        while j < 8 {
+            x = gf2p8_mul(x, x);
+            y = gf2p8_mul(x, y);
+            j += 1;
+        }
+        array[i] = y;
+        i += 1;
+    }
+
+    array
+};
+
+/// Multiplies packed 8-bit integers in `left` and `right` in the finite field GF(2^8)
+/// and store the results in `dst`. The field GF(2^8) is represented in
+/// polynomial representation with the reduction polynomial x^8 + x^4 + x^3 + x + 1.
+/// See <https://www.corsix.org/content/galois-field-instructions-2021-cpus> for details.
+// This is a const function. Trait based conversion is not available.
+#[allow(clippy::cast_possible_truncation)]
+const fn gf2p8_mul(left: u8, right: u8) -> u8 {
+    // This implementation is based on the `gf2p8mul_byte` definition found inside the Intel intrinsics guide.
+    // See https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8mul
+    // for more information.
+
+    const POLYNOMIAL: u32 = 0x11b;
+
+    let left = left as u32;
+    let right = right as u32;
+
+    let mut result = 0u32;
+
+    let mut i = 0u32;
+    while i < 8 {
+        if left & (1 << i) != 0 {
+            result ^= right << i;
+        }
+        i = i.wrapping_add(1);
+    }
+
+    let mut i = 14u32;
+    while i >= 8 {
+        if result & (1 << i) != 0 {
+            result ^= POLYNOMIAL << i.wrapping_sub(8);
+        }
+        i = i.wrapping_sub(1);
+    }
+
+    result as u8
+}
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index 9139156fd0e..9339d301aee 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -1,6 +1,6 @@
 use rand::Rng as _;
-
-use rustc_apfloat::{Float, ieee::Single};
+use rustc_apfloat::Float;
+use rustc_apfloat::ieee::Single;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::{mir, ty};
@@ -8,13 +8,14 @@ use rustc_span::Symbol;
 use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
 
-use crate::*;
 use self::helpers::bool_to_simd_element;
+use crate::*;
 
 mod aesni;
 mod avx;
 mod avx2;
 mod bmi;
+mod gfni;
 mod sha;
 mod sse;
 mod sse2;
@@ -43,7 +44,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/subborrow-u32-subborrow-u64.html
             "addcarry.32" | "addcarry.64" | "subborrow.32" | "subborrow.64" => {
                 if unprefixed_name.ends_with("64") && this.tcx.sess.target.arch != "x86_64" {
-                    return Ok(EmulateItemResult::NotSupported);
+                    return interp_ok(EmulateItemResult::NotSupported);
                 }
 
                 let [cb_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
@@ -67,7 +68,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                 let is_u64 = unprefixed_name.ends_with("64");
                 if is_u64 && this.tcx.sess.target.arch != "x86_64" {
-                    return Ok(EmulateItemResult::NotSupported);
+                    return interp_ok(EmulateItemResult::NotSupported);
                 }
 
                 let [c_in, a, b, out] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
@@ -106,6 +107,13 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     this, link_name, abi, args, dest,
                 );
             }
+            // The GFNI extension does not get its own namespace.
+            // Check for instruction names instead.
+            name if name.starts_with("vgf2p8affine") || name.starts_with("vgf2p8mulb") => {
+                return gfni::EvalContextExt::emulate_x86_gfni_intrinsic(
+                    this, link_name, abi, args, dest,
+                );
+            }
             name if name.starts_with("sha") => {
                 return sha::EvalContextExt::emulate_x86_sha_intrinsic(
                     this, link_name, abi, args, dest,
@@ -157,9 +165,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 );
             }
 
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
 
@@ -244,7 +252,7 @@ impl FloatBinOp {
             this.expect_target_feature_for_intrinsic(intrinsic, "avx")?;
             unord = !unord;
         }
-        Ok(Self::Cmp { gt, lt, eq, unord })
+        interp_ok(Self::Cmp { gt, lt, eq, unord })
     }
 }
 
@@ -266,7 +274,7 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>(
                 Some(std::cmp::Ordering::Equal) => eq,
                 Some(std::cmp::Ordering::Greater) => gt,
             };
-            Ok(bool_to_simd_element(res, Size::from_bits(F::BITS)))
+            interp_ok(bool_to_simd_element(res, Size::from_bits(F::BITS)))
         }
         FloatBinOp::Min => {
             let left_scalar = left.to_scalar();
@@ -280,9 +288,9 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>(
                 || right.is_nan()
                 || left >= right
             {
-                Ok(right_scalar)
+                interp_ok(right_scalar)
             } else {
-                Ok(left_scalar)
+                interp_ok(left_scalar)
             }
         }
         FloatBinOp::Max => {
@@ -297,9 +305,9 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>(
                 || right.is_nan()
                 || left <= right
             {
-                Ok(right_scalar)
+                interp_ok(right_scalar)
             } else {
-                Ok(left_scalar)
+                interp_ok(left_scalar)
             }
         }
     }
@@ -332,7 +340,7 @@ fn bin_op_simd_float_first<'tcx, F: rustc_apfloat::Float>(
         this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?;
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 /// Performs `which` operation on each component of `left` and
@@ -360,7 +368,7 @@ fn bin_op_simd_float_all<'tcx, F: rustc_apfloat::Float>(
         this.write_scalar(res, &dest)?;
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 #[derive(Copy, Clone)]
@@ -391,7 +399,7 @@ fn unary_op_f32<'tcx>(
             // Apply a relative error with a magnitude on the order of 2^-12 to simulate the
             // inaccuracy of RCP.
             let res = apply_random_float_error(this, div, -12);
-            Ok(Scalar::from_f32(res))
+            interp_ok(Scalar::from_f32(res))
         }
         FloatUnaryOp::Rsqrt => {
             let op = op.to_scalar().to_u32()?;
@@ -401,7 +409,7 @@ fn unary_op_f32<'tcx>(
             // Apply a relative error with a magnitude on the order of 2^-12 to simulate the
             // inaccuracy of RSQRT.
             let res = apply_random_float_error(this, rsqrt, -12);
-            Ok(Scalar::from_f32(res))
+            interp_ok(Scalar::from_f32(res))
         }
     }
 }
@@ -442,7 +450,7 @@ fn unary_op_ss<'tcx>(
         this.copy_op(&this.project_index(&op, i)?, &this.project_index(&dest, i)?)?;
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 /// Performs `which` operation on each component of `op`, storing the
@@ -466,7 +474,7 @@ fn unary_op_ps<'tcx>(
         this.write_scalar(res, &dest)?;
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 enum ShiftOp {
@@ -532,7 +540,7 @@ fn shift_simd_by_scalar<'tcx>(
         this.write_scalar(res, &dest)?;
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 /// Shifts each element of `left` by the corresponding element of `right`.
@@ -587,7 +595,7 @@ fn shift_simd_by_simd<'tcx>(
         this.write_scalar(res, &dest)?;
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 /// Takes a 128-bit vector, transmutes it to `[u64; 2]` and extracts
@@ -633,7 +641,7 @@ fn round_first<'tcx, F: rustc_apfloat::Float>(
         this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?;
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 // Rounds all elements of `op` according to `rounding`.
@@ -659,7 +667,7 @@ fn round_all<'tcx, F: rustc_apfloat::Float>(
         )?;
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 /// Gets equivalent `rustc_apfloat::Round` from rounding mode immediate of
@@ -671,14 +679,14 @@ fn rounding_from_imm<'tcx>(rounding: i32) -> InterpResult<'tcx, rustc_apfloat::R
     match rounding & !0b1000 {
         // When the third bit is 0, the rounding mode is determined by the
         // first two bits.
-        0b000 => Ok(rustc_apfloat::Round::NearestTiesToEven),
-        0b001 => Ok(rustc_apfloat::Round::TowardNegative),
-        0b010 => Ok(rustc_apfloat::Round::TowardPositive),
-        0b011 => Ok(rustc_apfloat::Round::TowardZero),
+        0b000 => interp_ok(rustc_apfloat::Round::NearestTiesToEven),
+        0b001 => interp_ok(rustc_apfloat::Round::TowardNegative),
+        0b010 => interp_ok(rustc_apfloat::Round::TowardPositive),
+        0b011 => interp_ok(rustc_apfloat::Round::TowardZero),
         // When the third bit is 1, the rounding mode is determined by the
         // SSE status register. Since we do not support modifying it from
         // Miri (or Rust), we assume it to be at its default mode (round-to-nearest).
-        0b100..=0b111 => Ok(rustc_apfloat::Round::NearestTiesToEven),
+        0b100..=0b111 => interp_ok(rustc_apfloat::Round::NearestTiesToEven),
         rounding => panic!("invalid rounding mode 0x{rounding:02x}"),
     }
 }
@@ -717,7 +725,7 @@ fn convert_float_to_int<'tcx>(
         this.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?;
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 /// Calculates absolute value of integers in `op` and stores the result in `dest`.
@@ -747,7 +755,7 @@ fn int_abs<'tcx>(
         this.write_immediate(*res, &dest)?;
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 /// Splits `op` (which must be a SIMD vector) into 128-bit chunks.
@@ -778,7 +786,7 @@ fn split_simd_to_128bit_chunks<'tcx, P: Projectable<'tcx, Provenance>>(
         .unwrap();
     let chunked_op = op.transmute(chunked_layout, this)?;
 
-    Ok((num_chunks, items_per_chunk, chunked_op))
+    interp_ok((num_chunks, items_per_chunk, chunked_op))
 }
 
 /// Horizontally performs `which` operation on adjacent values of
@@ -830,7 +838,7 @@ fn horizontal_bin_op<'tcx>(
         }
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 /// Conditionally multiplies the packed floating-point elements in
@@ -892,7 +900,7 @@ fn conditional_dot_product<'tcx>(
         }
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 /// Calculates two booleans.
@@ -923,7 +931,7 @@ fn test_bits_masked<'tcx>(
         masked_set &= (op & mask) == mask;
     }
 
-    Ok((all_zero, masked_set))
+    interp_ok((all_zero, masked_set))
 }
 
 /// Calculates two booleans.
@@ -956,7 +964,7 @@ fn test_high_bits_masked<'tcx>(
         negated &= (!op & mask) >> high_bit_offset == 0;
     }
 
-    Ok((direct, negated))
+    interp_ok((direct, negated))
 }
 
 /// Conditionally loads from `ptr` according the high bit of each
@@ -989,7 +997,7 @@ fn mask_load<'tcx>(
         }
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 /// Conditionally stores into `ptr` according the high bit of each
@@ -1023,7 +1031,7 @@ fn mask_store<'tcx>(
         }
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 /// Compute the sum of absolute differences of quadruplets of unsigned
@@ -1082,7 +1090,7 @@ fn mpsadbw<'tcx>(
         }
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 /// Multiplies packed 16-bit signed integer values, truncates the 32-bit
@@ -1120,7 +1128,7 @@ fn pmulhrsw<'tcx>(
         this.write_scalar(Scalar::from_i16(res), &dest)?;
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 /// Perform a carry-less multiplication of two 64-bit integers, selected from `left` and `right` according to `imm8`,
@@ -1182,7 +1190,7 @@ fn pclmulqdq<'tcx>(
     let dest_high = this.project_index(&dest, 1)?;
     this.write_scalar(Scalar::from_u64(result_high), &dest_high)?;
 
-    Ok(())
+    interp_ok(())
 }
 
 /// Packs two N-bit integer vectors to a single N/2-bit integers.
@@ -1227,7 +1235,7 @@ fn pack_generic<'tcx>(
         }
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 /// Converts two 16-bit integer vectors to a single 8-bit integer
@@ -1245,7 +1253,7 @@ fn packsswb<'tcx>(
     pack_generic(this, left, right, dest, |op| {
         let op = op.to_i16()?;
         let res = i8::try_from(op).unwrap_or(if op < 0 { i8::MIN } else { i8::MAX });
-        Ok(Scalar::from_i8(res))
+        interp_ok(Scalar::from_i8(res))
     })
 }
 
@@ -1264,7 +1272,7 @@ fn packuswb<'tcx>(
     pack_generic(this, left, right, dest, |op| {
         let op = op.to_i16()?;
         let res = u8::try_from(op).unwrap_or(if op < 0 { 0 } else { u8::MAX });
-        Ok(Scalar::from_u8(res))
+        interp_ok(Scalar::from_u8(res))
     })
 }
 
@@ -1283,7 +1291,7 @@ fn packssdw<'tcx>(
     pack_generic(this, left, right, dest, |op| {
         let op = op.to_i32()?;
         let res = i16::try_from(op).unwrap_or(if op < 0 { i16::MIN } else { i16::MAX });
-        Ok(Scalar::from_i16(res))
+        interp_ok(Scalar::from_i16(res))
     })
 }
 
@@ -1302,7 +1310,7 @@ fn packusdw<'tcx>(
     pack_generic(this, left, right, dest, |op| {
         let op = op.to_i32()?;
         let res = u16::try_from(op).unwrap_or(if op < 0 { 0 } else { u16::MAX });
-        Ok(Scalar::from_u16(res))
+        interp_ok(Scalar::from_u16(res))
     })
 }
 
@@ -1334,7 +1342,7 @@ fn psign<'tcx>(
         this.write_immediate(*res, &dest)?;
     }
 
-    Ok(())
+    interp_ok(())
 }
 
 /// Calcultates either `a + b + cb_in` or `a - b - cb_in` depending on the value
@@ -1358,5 +1366,5 @@ fn carrying_add<'tcx>(
         this.binary_op(op, &sum, &ImmTy::from_uint(cb_in, a.layout))?.to_pair(this);
     let cb_out = overflow1.to_scalar().to_bool()? | overflow2.to_scalar().to_bool()?;
 
-    Ok((sum, Scalar::from_u8(cb_out.into())))
+    interp_ok((sum, Scalar::from_u8(cb_out.into())))
 }
diff --git a/src/tools/miri/src/shims/x86/sha.rs b/src/tools/miri/src/shims/x86/sha.rs
index d9cd34377e6..8553771b694 100644
--- a/src/tools/miri/src/shims/x86/sha.rs
+++ b/src/tools/miri/src/shims/x86/sha.rs
@@ -31,7 +31,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let projected = &this.project_index(reg, i.try_into().unwrap())?;
                 *dst = this.read_scalar(projected)?.to_u32()?
             }
-            Ok(res)
+            interp_ok(res)
         }
 
         fn write<'c>(
@@ -45,7 +45,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let projected = &this.project_index(dest, i.try_into().unwrap())?;
                 this.write_scalar(Scalar::from_u32(part), projected)?;
             }
-            Ok(())
+            interp_ok(())
         }
 
         match unprefixed_name {
@@ -106,9 +106,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let result = sha256msg2(a, b);
                 write(this, &dest, result)?;
             }
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
 
diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs
index 254d25bb529..013900e95d3 100644
--- a/src/tools/miri/src/shims/x86/sse.rs
+++ b/src/tools/miri/src/shims/x86/sse.rs
@@ -201,8 +201,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?;
                 }
             }
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs
index 7c23e372664..de72e63f8af 100644
--- a/src/tools/miri/src/shims/x86/sse2.rs
+++ b/src/tools/miri/src/shims/x86/sse2.rs
@@ -344,8 +344,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?;
                 }
             }
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/x86/sse3.rs b/src/tools/miri/src/shims/x86/sse3.rs
index ef5a55d6eb2..9aa4dd59950 100644
--- a/src/tools/miri/src/shims/x86/sse3.rs
+++ b/src/tools/miri/src/shims/x86/sse3.rs
@@ -47,8 +47,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                 this.mem_copy(src_ptr, dest.ptr(), dest.layout.size, /*nonoverlapping*/ true)?;
             }
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs
index 8fcdc491c0c..7bf8ddea2fe 100644
--- a/src/tools/miri/src/shims/x86/sse41.rs
+++ b/src/tools/miri/src/shims/x86/sse41.rs
@@ -172,8 +172,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                 this.write_scalar(Scalar::from_i32(res.into()), dest)?;
             }
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs
index 0b6e0d9e0d7..f31cd406349 100644
--- a/src/tools/miri/src/shims/x86/sse42.rs
+++ b/src/tools/miri/src/shims/x86/sse42.rs
@@ -115,7 +115,7 @@ fn compare_strings<'tcx>(
                     (false, true) => i32::from(ch.to_i8()?),
                     (false, false) => i32::from(ch.to_u8()?),
                 };
-                Ok(result)
+                interp_ok(result)
             };
 
             for i in 0..len2 {
@@ -183,7 +183,7 @@ fn compare_strings<'tcx>(
         _ => (),
     }
 
-    Ok(result)
+    interp_ok(result)
 }
 
 /// Obtain the arguments of the intrinsic based on its name.
@@ -235,7 +235,7 @@ fn deconstruct_args<'tcx>(
         let str1 = str1.transmute(array_layout, this)?;
         let str2 = str2.transmute(array_layout, this)?;
 
-        Ok((str1, str2, Some((len1, len2)), imm))
+        interp_ok((str1, str2, Some((len1, len2)), imm))
     } else {
         let [str1, str2, imm] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
         let imm = this.read_scalar(imm)?.to_u8()?;
@@ -244,7 +244,7 @@ fn deconstruct_args<'tcx>(
         let str1 = str1.transmute(array_layout, this)?;
         let str2 = str2.transmute(array_layout, this)?;
 
-        Ok((str1, str2, None, imm))
+        interp_ok((str1, str2, None, imm))
     }
 }
 
@@ -266,7 +266,7 @@ fn implicit_len<'tcx>(
             break;
         }
     }
-    Ok(result)
+    interp_ok(result)
 }
 
 #[inline]
@@ -433,7 +433,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 };
 
                 if bit_size == 64 && this.tcx.sess.target.arch != "x86_64" {
-                    return Ok(EmulateItemResult::NotSupported);
+                    return interp_ok(EmulateItemResult::NotSupported);
                 }
 
                 let [left, right] =
@@ -493,8 +493,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                 this.write_scalar(result, dest)?;
             }
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs
index 096b0fb9e4b..76a2451dea4 100644
--- a/src/tools/miri/src/shims/x86/ssse3.rs
+++ b/src/tools/miri/src/shims/x86/ssse3.rs
@@ -133,8 +133,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                 psign(this, left, right, dest)?;
             }
-            _ => return Ok(EmulateItemResult::NotSupported),
+            _ => return interp_ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsReturn)
+        interp_ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/test-cargo-miri/src/main.rs b/src/tools/miri/test-cargo-miri/src/main.rs
index d171ec1c0d1..efe95bf3aba 100644
--- a/src/tools/miri/test-cargo-miri/src/main.rs
+++ b/src/tools/miri/test-cargo-miri/src/main.rs
@@ -1,9 +1,10 @@
-use byteorder::{BigEndian, ByteOrder};
 use std::env;
 #[cfg(unix)]
 use std::io::{self, BufRead};
 use std::path::PathBuf;
 
+use byteorder::{BigEndian, ByteOrder};
+
 fn main() {
     // Check env var set by `build.rs`.
     assert_eq!(env!("MIRITESTVAR"), "testval");
diff --git a/src/tools/miri/test-cargo-miri/subcrate/test.rs b/src/tools/miri/test-cargo-miri/subcrate/test.rs
index b60cf20339b..e663643f20b 100644
--- a/src/tools/miri/test-cargo-miri/subcrate/test.rs
+++ b/src/tools/miri/test-cargo-miri/subcrate/test.rs
@@ -1,5 +1,4 @@
 use std::env;
-
 use std::path::PathBuf;
 
 use byteorder::{ByteOrder, LittleEndian};
diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock
index 9a4431eb704..64bfc84ef20 100644
--- a/src/tools/miri/test_dependencies/Cargo.lock
+++ b/src/tools/miri/test_dependencies/Cargo.lock
@@ -52,9 +52,12 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
 
 [[package]]
 name = "cc"
-version = "1.1.7"
+version = "1.1.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc"
+checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
+dependencies = [
+ "shlex",
+]
 
 [[package]]
 name = "cfg-if"
@@ -262,6 +265,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
 name = "signal-hook-registry"
 version = "1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/miri/tests/avr.json b/src/tools/miri/tests/avr.json
deleted file mode 100644
index 1e00b0f57ef..00000000000
--- a/src/tools/miri/tests/avr.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
-  "arch": "avr",
-  "cpu": "atmega328p",
-  "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8",
-  "env": "",
-  "executables": true,
-  "linker": "avr-gcc",
-  "linker-flavor": "gcc",
-  "linker-is-gnu": true,
-  "llvm-target": "avr-unknown-unknown",
-  "os": "unknown",
-  "position-independent-executables": false,
-  "exe-suffix": ".elf",
-  "eh-frame-header": false,
-  "pre-link-args": {
-    "gcc": ["-mmcu=atmega328p"]
-  },
-  "late-link-args": {
-    "gcc": ["-lgcc"]
-  },
-  "target-c-int-width": "16",
-  "target-endian": "little",
-  "target-pointer-width": "16",
-  "vendor": "unknown"
-}
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs
index 6a49625d75d..b2a398e0a19 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs
@@ -2,8 +2,7 @@
 
 // Joining the same thread from multiple threads is undefined behavior.
 
-use std::thread;
-use std::{mem, ptr};
+use std::{mem, ptr, thread};
 
 extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void {
     // Yield the thread several times so that other threads can join it.
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.rs
index a79abe65328..f2df8bdca12 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.rs
@@ -1,12 +1,12 @@
 //@ignore-target: windows # No pthreads on Windows
 //
-// Check that if we pass NULL attribute, then we get the default mutex type.
+// Check that if we pass NULL attribute, then reentrant locking is UB.
 
 fn main() {
     unsafe {
         let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
         assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null() as *const _), 0);
         assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
-        libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: Undefined Behavior: trying to acquire already locked default mutex
+        libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: already locked by the current thread
     }
 }
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.stderr
index a57d10753d9..9455e704376 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.stderr
@@ -1,13 +1,13 @@
-error: Undefined Behavior: trying to acquire already locked default mutex
-  --> tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs:LL:CC
+error: Undefined Behavior: trying to acquire default mutex already locked by the current thread
+  --> tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.rs:LL:CC
    |
 LL |         libc::pthread_mutex_lock(&mut mutex as *mut _);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire already locked default mutex
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire default mutex already locked by the current thread
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
-   = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs:LL:CC
+   = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.rs
index d9293f938b6..d2d0ffff07a 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.rs
@@ -1,6 +1,11 @@
 //@ignore-target: windows # No pthreads on Windows
 //
-// Check that if we do not set the mutex type, it is the default.
+// Check that if we do not set the mutex type, it is UB to do reentrant locking. glibc apparently
+// actually exploits this, see
+// <https://github.molgen.mpg.de/git-mirror/glibc/blob/master/nptl/pthread_mutexattr_settype.c#L31>:
+// one must actively call pthread_mutexattr_settype to disable lock elision. This means a call to
+// pthread_mutexattr_settype(PTHREAD_MUTEX_NORMAL) makes a difference even if
+// PTHREAD_MUTEX_NORMAL == PTHREAD_MUTEX_DEFAULT!
 
 fn main() {
     unsafe {
@@ -9,6 +14,6 @@ fn main() {
         let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
         assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0);
         assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
-        libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: Undefined Behavior: trying to acquire already locked default mutex
+        libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: already locked by the current thread
     }
 }
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.stderr
index e9961ed413d..a9ffbde1b65 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.stderr
@@ -1,13 +1,13 @@
-error: Undefined Behavior: trying to acquire already locked default mutex
-  --> tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs:LL:CC
+error: Undefined Behavior: trying to acquire default mutex already locked by the current thread
+  --> tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.rs:LL:CC
    |
 LL |         libc::pthread_mutex_lock(&mut mutex as *mut _);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire already locked default mutex
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire default mutex already locked by the current thread
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
-   = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs:LL:CC
+   = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.rs
index b38582482b8..9a88639edf7 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.rs
@@ -10,6 +10,8 @@ fn main() {
         let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
         assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0);
         assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
+        // A "normal" mutex properly tries to acquire the lock even if its is already held
+        // by the current thread -- and then we deadlock.
         libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: deadlock: the evaluated program deadlocked
     }
 }
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.stderr
index 4337475963e..f20b26297e2 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.stderr
@@ -1,11 +1,11 @@
 error: deadlock: the evaluated program deadlocked
-  --> tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs:LL:CC
+  --> tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.rs:LL:CC
    |
 LL |         libc::pthread_mutex_lock(&mut mutex as *mut _);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program deadlocked
    |
    = note: BACKTRACE:
-   = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs:LL:CC
+   = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.rs
new file mode 100644
index 00000000000..bd8aef787e6
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.rs
@@ -0,0 +1,12 @@
+//@ignore-target: windows # No pthreads on Windows
+//
+// Check that if we use PTHREAD_MUTEX_INITIALIZER, then reentrant locking is UB.
+// glibc apparently actually exploits this so we better catch it!
+
+fn main() {
+    unsafe {
+        let mut mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER;
+        assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
+        libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: already locked by the current thread
+    }
+}
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.stderr
new file mode 100644
index 00000000000..984bb07b728
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: trying to acquire default mutex already locked by the current thread
+  --> tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.rs:LL:CC
+   |
+LL |         libc::pthread_mutex_lock(&mut mutex as *mut _);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire default mutex already locked by the current thread
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail-dep/libc/affinity.rs b/src/tools/miri/tests/fail-dep/libc/affinity.rs
index d7d5c59e1bc..09f096e46f1 100644
--- a/src/tools/miri/tests/fail-dep/libc/affinity.rs
+++ b/src/tools/miri/tests/fail-dep/libc/affinity.rs
@@ -3,10 +3,10 @@
 //@compile-flags: -Zmiri-disable-isolation -Zmiri-num-cpus=4
 
 fn main() {
-    use libc::{cpu_set_t, sched_setaffinity};
-
     use std::mem::size_of;
 
+    use libc::{cpu_set_t, sched_setaffinity};
+
     // If pid is zero, then the calling thread is used.
     const PID: i32 = 0;
 
diff --git a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs
index c7d8bacd379..3a832bb0ce0 100644
--- a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs
+++ b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs
@@ -1,8 +1,7 @@
 //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0
 //@ignore-target: windows # No libc env support on Windows
 
-use std::env;
-use std::thread;
+use std::{env, thread};
 
 fn main() {
     let t = thread::spawn(|| unsafe {
diff --git a/src/tools/miri/tests/fail/coroutine-pinned-moved.rs b/src/tools/miri/tests/fail/coroutine-pinned-moved.rs
index 46ec58810a6..abed638e443 100644
--- a/src/tools/miri/tests/fail/coroutine-pinned-moved.rs
+++ b/src/tools/miri/tests/fail/coroutine-pinned-moved.rs
@@ -1,10 +1,8 @@
 //@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
 #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
 
-use std::{
-    ops::{Coroutine, CoroutineState},
-    pin::Pin,
-};
+use std::ops::{Coroutine, CoroutineState};
+use std::pin::Pin;
 
 fn firstn() -> impl Coroutine<Yield = u64, Return = ()> {
     #[coroutine]
diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs
index 8bceba9380a..c67ce65eb34 100644
--- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs
+++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs
@@ -3,8 +3,7 @@
 // Avoid accidental synchronization via address reuse inside `thread::spawn`.
 //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
 
-use std::sync::atomic::AtomicUsize;
-use std::sync::atomic::Ordering;
+use std::sync::atomic::{AtomicUsize, Ordering};
 use std::thread::spawn;
 
 #[derive(Copy, Clone)]
diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs
index 1a2746a26f4..5e328740e85 100644
--- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs
+++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs
@@ -3,8 +3,7 @@
 // Avoid accidental synchronization via address reuse inside `thread::spawn`.
 //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
 
-use std::sync::atomic::AtomicUsize;
-use std::sync::atomic::Ordering;
+use std::sync::atomic::{AtomicUsize, Ordering};
 use std::thread::spawn;
 
 #[derive(Copy, Clone)]
diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs
index b494bd3a003..fdc0f9e20f0 100644
--- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs
+++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs
@@ -3,8 +3,7 @@
 // Avoid accidental synchronization via address reuse inside `thread::spawn`.
 //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
 
-use std::sync::atomic::AtomicUsize;
-use std::sync::atomic::Ordering;
+use std::sync::atomic::{AtomicUsize, Ordering};
 use std::thread::spawn;
 
 #[derive(Copy, Clone)]
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read.rs
deleted file mode 100644
index 828b47f0a65..00000000000
--- a/src/tools/miri/tests/fail/data_race/mixed_size_read.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
-
-use std::sync::atomic::{AtomicU8, AtomicU16, Ordering};
-use std::thread;
-
-fn convert(a: &AtomicU16) -> &[AtomicU8; 2] {
-    unsafe { std::mem::transmute(a) }
-}
-
-// We can't allow mixed-size accesses; they are not possible in C++ and even
-// Intel says you shouldn't do it.
-fn main() {
-    let a = AtomicU16::new(0);
-    let a16 = &a;
-    let a8 = convert(a16);
-
-    thread::scope(|s| {
-        s.spawn(|| {
-            a16.load(Ordering::SeqCst);
-        });
-        s.spawn(|| {
-            a8[0].load(Ordering::SeqCst);
-            //~^ ERROR: Race condition detected between (1) 2-byte atomic load on thread `unnamed-1` and (2) 1-byte atomic load on thread `unnamed-2`
-        });
-    });
-}
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr
new file mode 100644
index 00000000000..b829627c00a
--- /dev/null
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr
@@ -0,0 +1,22 @@
+error: Undefined Behavior: Race condition detected between (1) multiple differently-sized atomic loads, including one load on thread `unnamed-ID` and (2) 2-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here
+  --> tests/fail/data_race/mixed_size_read_read_write.rs:LL:CC
+   |
+LL |                 a16.store(0, Ordering::SeqCst);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) multiple differently-sized atomic loads, including one load on thread `unnamed-ID` and (2) 2-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here
+   |
+help: and (1) occurred earlier here
+  --> tests/fail/data_race/mixed_size_read_read_write.rs:LL:CC
+   |
+LL |             a16.load(Ordering::SeqCst);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: overlapping unsynchronized atomic accesses must use the same access size
+   = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
+   = note: inside closure at tests/fail/data_race/mixed_size_read_read_write.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr
new file mode 100644
index 00000000000..6bc38b14cb2
--- /dev/null
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr
@@ -0,0 +1,22 @@
+error: Undefined Behavior: Race condition detected between (1) multiple differently-sized atomic loads, including one load on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here
+  --> tests/fail/data_race/mixed_size_read_read_write.rs:LL:CC
+   |
+LL |                 a8[0].store(0, Ordering::SeqCst);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) multiple differently-sized atomic loads, including one load on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here
+   |
+help: and (1) occurred earlier here
+  --> tests/fail/data_race/mixed_size_read_read_write.rs:LL:CC
+   |
+LL |             a16.load(Ordering::SeqCst);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: overlapping unsynchronized atomic accesses must use the same access size
+   = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
+   = note: inside closure at tests/fail/data_race/mixed_size_read_read_write.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs
new file mode 100644
index 00000000000..e76654806bb
--- /dev/null
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs
@@ -0,0 +1,39 @@
+//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation
+// Avoid accidental synchronization via address reuse inside `thread::spawn`.
+//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+// Two variants: the atomic store matches the size of the first or second atomic load.
+//@revisions: match_first_load match_second_load
+
+use std::sync::atomic::{AtomicU8, AtomicU16, Ordering};
+use std::thread;
+
+fn convert(a: &AtomicU16) -> &[AtomicU8; 2] {
+    unsafe { std::mem::transmute(a) }
+}
+
+// We can't allow mixed-size accesses; they are not possible in C++ and even
+// Intel says you shouldn't do it.
+fn main() {
+    let a = AtomicU16::new(0);
+    let a16 = &a;
+    let a8 = convert(a16);
+
+    thread::scope(|s| {
+        s.spawn(|| {
+            a16.load(Ordering::SeqCst);
+        });
+        s.spawn(|| {
+            a8[0].load(Ordering::SeqCst);
+        });
+        s.spawn(|| {
+            thread::yield_now(); // make sure this happens last
+            if cfg!(match_first_load) {
+                a16.store(0, Ordering::SeqCst);
+                //~[match_first_load]^ ERROR: Race condition detected between (1) multiple differently-sized atomic loads, including one load on thread `unnamed-1` and (2) 2-byte atomic store on thread `unnamed-3`
+            } else {
+                a8[0].store(0, Ordering::SeqCst);
+                //~[match_second_load]^ ERROR: Race condition detected between (1) multiple differently-sized atomic loads, including one load on thread `unnamed-1` and (2) 1-byte atomic store on thread `unnamed-3`
+            }
+        });
+    });
+}
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr
new file mode 100644
index 00000000000..6f8dbd38ca8
--- /dev/null
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr
@@ -0,0 +1,22 @@
+error: Undefined Behavior: Race condition detected between (1) 1-byte atomic load on thread `unnamed-ID` and (2) 2-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here
+  --> tests/fail/data_race/mixed_size_read_write.rs:LL:CC
+   |
+LL |             a16.store(1, Ordering::SeqCst);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 1-byte atomic load on thread `unnamed-ID` and (2) 2-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here
+   |
+help: and (1) occurred earlier here
+  --> tests/fail/data_race/mixed_size_read_write.rs:LL:CC
+   |
+LL |             a8[0].load(Ordering::SeqCst);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: overlapping unsynchronized atomic accesses must use the same access size
+   = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
+   = note: inside closure at tests/fail/data_race/mixed_size_read_write.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs
new file mode 100644
index 00000000000..53016bab780
--- /dev/null
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs
@@ -0,0 +1,39 @@
+//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation
+// Avoid accidental synchronization via address reuse inside `thread::spawn`.
+//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+// Two revisions, depending on which access goes first.
+//@revisions: read_write write_read
+
+use std::sync::atomic::{AtomicU8, AtomicU16, Ordering};
+use std::thread;
+
+fn convert(a: &AtomicU16) -> &[AtomicU8; 2] {
+    unsafe { std::mem::transmute(a) }
+}
+
+// We can't allow mixed-size accesses; they are not possible in C++ and even
+// Intel says you shouldn't do it.
+fn main() {
+    let a = AtomicU16::new(0);
+    let a16 = &a;
+    let a8 = convert(a16);
+
+    thread::scope(|s| {
+        s.spawn(|| {
+            if cfg!(read_write) {
+                // Let the other one go first.
+                thread::yield_now();
+            }
+            a16.store(1, Ordering::SeqCst);
+            //~[read_write]^ ERROR: Race condition detected between (1) 1-byte atomic load on thread `unnamed-2` and (2) 2-byte atomic store on thread `unnamed-1`
+        });
+        s.spawn(|| {
+            if cfg!(write_read) {
+                // Let the other one go first.
+                thread::yield_now();
+            }
+            a8[0].load(Ordering::SeqCst);
+            //~[write_read]^ ERROR: Race condition detected between (1) 2-byte atomic store on thread `unnamed-1` and (2) 1-byte atomic load on thread `unnamed-2`
+        });
+    });
+}
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr
index 31a798a89b1..990d2058bca 100644
--- a/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr
@@ -1,20 +1,20 @@
-error: Undefined Behavior: Race condition detected between (1) 2-byte atomic load on thread `unnamed-ID` and (2) 1-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here
-  --> tests/fail/data_race/mixed_size_read.rs:LL:CC
+error: Undefined Behavior: Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here
+  --> tests/fail/data_race/mixed_size_read_write.rs:LL:CC
    |
 LL |             a8[0].load(Ordering::SeqCst);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte atomic load on thread `unnamed-ID` and (2) 1-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here
    |
 help: and (1) occurred earlier here
-  --> tests/fail/data_race/mixed_size_read.rs:LL:CC
+  --> tests/fail/data_race/mixed_size_read_write.rs:LL:CC
    |
-LL |             a16.load(Ordering::SeqCst);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |             a16.store(1, Ordering::SeqCst);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: overlapping unsynchronized atomic accesses must use the same access size
    = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
-   = note: inside closure at tests/fail/data_race/mixed_size_read.rs:LL:CC
+   = note: inside closure at tests/fail/data_race/mixed_size_read_write.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr
new file mode 100644
index 00000000000..a353910dcc9
--- /dev/null
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr
@@ -0,0 +1,22 @@
+error: Undefined Behavior: Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here
+  --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC
+   |
+LL |             a8[idx].store(1, Ordering::SeqCst);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here
+   |
+help: and (1) occurred earlier here
+  --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC
+   |
+LL |             a16.store(1, Ordering::SeqCst);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: overlapping unsynchronized atomic accesses must use the same access size
+   = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
+   = note: inside closure at tests/fail/data_race/mixed_size_write_write.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs
index 89afda2fff5..545e354a037 100644
--- a/src/tools/miri/tests/fail/data_race/mixed_size_write.rs
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs
@@ -1,6 +1,7 @@
 //@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation
 // Avoid accidental synchronization via address reuse inside `thread::spawn`.
 //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@revisions: fst snd
 
 use std::sync::atomic::{AtomicU8, AtomicU16, Ordering};
 use std::thread;
@@ -21,7 +22,8 @@ fn main() {
             a16.store(1, Ordering::SeqCst);
         });
         s.spawn(|| {
-            a8[0].store(1, Ordering::SeqCst);
+            let idx = if cfg!(fst) { 0 } else { 1 };
+            a8[idx].store(1, Ordering::SeqCst);
             //~^ ERROR: Race condition detected between (1) 2-byte atomic store on thread `unnamed-1` and (2) 1-byte atomic store on thread `unnamed-2`
         });
     });
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr
new file mode 100644
index 00000000000..3b9c0491502
--- /dev/null
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr
@@ -0,0 +1,22 @@
+error: Undefined Behavior: Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC+0x1. (2) just happened here
+  --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC
+   |
+LL |             a8[idx].store(1, Ordering::SeqCst);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC+0x1. (2) just happened here
+   |
+help: and (1) occurred earlier here
+  --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC
+   |
+LL |             a16.store(1, Ordering::SeqCst);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: overlapping unsynchronized atomic accesses must use the same access size
+   = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
+   = note: inside closure at tests/fail/data_race/mixed_size_write_write.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.stderr
index c30b48c1f32..1f22413bc5f 100644
--- a/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.stderr
@@ -1,11 +1,11 @@
 error: Undefined Behavior: Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here
-  --> tests/fail/data_race/mixed_size_write.rs:LL:CC
+  --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC
    |
 LL |             a8[0].store(1, Ordering::SeqCst);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here
    |
 help: and (1) occurred earlier here
-  --> tests/fail/data_race/mixed_size_write.rs:LL:CC
+  --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC
    |
 LL |             a16.store(1, Ordering::SeqCst);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -14,7 +14,7 @@ LL |             a16.store(1, Ordering::SeqCst);
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
-   = note: inside closure at tests/fail/data_race/mixed_size_write.rs:LL:CC
+   = note: inside closure at tests/fail/data_race/mixed_size_write_write.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/fail/data_race/read_read_race1.rs b/src/tools/miri/tests/fail/data_race/read_read_race1.rs
deleted file mode 100644
index 02aa4e4b716..00000000000
--- a/src/tools/miri/tests/fail/data_race/read_read_race1.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-//@compile-flags: -Zmiri-preemption-rate=0.0
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
-
-use std::sync::atomic::{AtomicU16, Ordering};
-use std::thread;
-
-// Make sure races between atomic and non-atomic reads are detected.
-// This seems harmless but C++ does not allow them, so we can't allow them for now either.
-// This test coverse the case where the non-atomic access come first.
-fn main() {
-    let a = AtomicU16::new(0);
-
-    thread::scope(|s| {
-        s.spawn(|| {
-            let ptr = &a as *const AtomicU16 as *mut u16;
-            unsafe { ptr.read() };
-        });
-        s.spawn(|| {
-            thread::yield_now();
-
-            // We also put a non-atomic access here, but that should *not* be reported.
-            let ptr = &a as *const AtomicU16 as *mut u16;
-            unsafe { ptr.read() };
-            // Then do the atomic access.
-            a.load(Ordering::SeqCst);
-            //~^ ERROR: Data race detected between (1) non-atomic read on thread `unnamed-1` and (2) atomic load on thread `unnamed-2`
-        });
-    });
-}
diff --git a/src/tools/miri/tests/fail/data_race/read_read_race1.stderr b/src/tools/miri/tests/fail/data_race/read_read_race1.stderr
deleted file mode 100644
index e97c4a4fdcb..00000000000
--- a/src/tools/miri/tests/fail/data_race/read_read_race1.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here
-  --> tests/fail/data_race/read_read_race1.rs:LL:CC
-   |
-LL |             a.load(Ordering::SeqCst);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here
-   |
-help: and (1) occurred earlier here
-  --> tests/fail/data_race/read_read_race1.rs:LL:CC
-   |
-LL |             unsafe { ptr.read() };
-   |                      ^^^^^^^^^^
-   = help: overlapping atomic and non-atomic accesses must be synchronized, even if both are read-only
-   = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
-   = note: inside closure at tests/fail/data_race/read_read_race1.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/data_race/read_read_race2.rs b/src/tools/miri/tests/fail/data_race/read_read_race2.rs
deleted file mode 100644
index 3b94c9143f3..00000000000
--- a/src/tools/miri/tests/fail/data_race/read_read_race2.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-//@compile-flags: -Zmiri-preemption-rate=0.0
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
-
-use std::sync::atomic::{AtomicU16, Ordering};
-use std::thread;
-
-// Make sure races between atomic and non-atomic reads are detected.
-// This seems harmless but C++ does not allow them, so we can't allow them for now either.
-// This test coverse the case where the atomic access come first.
-fn main() {
-    let a = AtomicU16::new(0);
-
-    thread::scope(|s| {
-        s.spawn(|| {
-            // We also put a non-atomic access here, but that should *not* be reported.
-            let ptr = &a as *const AtomicU16 as *mut u16;
-            unsafe { ptr.read() };
-            // Then do the atomic access.
-            a.load(Ordering::SeqCst);
-        });
-        s.spawn(|| {
-            thread::yield_now();
-
-            let ptr = &a as *const AtomicU16 as *mut u16;
-            unsafe { ptr.read() };
-            //~^ ERROR: Data race detected between (1) atomic load on thread `unnamed-1` and (2) non-atomic read on thread `unnamed-2`
-        });
-    });
-}
diff --git a/src/tools/miri/tests/fail/data_race/read_read_race2.stderr b/src/tools/miri/tests/fail/data_race/read_read_race2.stderr
deleted file mode 100644
index d64032db7b3..00000000000
--- a/src/tools/miri/tests/fail/data_race/read_read_race2.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error: Undefined Behavior: Data race detected between (1) atomic load on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here
-  --> tests/fail/data_race/read_read_race2.rs:LL:CC
-   |
-LL |             unsafe { ptr.read() };
-   |                      ^^^^^^^^^^ Data race detected between (1) atomic load on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here
-   |
-help: and (1) occurred earlier here
-  --> tests/fail/data_race/read_read_race2.rs:LL:CC
-   |
-LL |             a.load(Ordering::SeqCst);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: overlapping atomic and non-atomic accesses must be synchronized, even if both are read-only
-   = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
-   = note: inside closure at tests/fail/data_race/read_read_race2.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/panic/abort_unwind.rs b/src/tools/miri/tests/fail/panic/abort_unwind.rs
new file mode 100644
index 00000000000..e313d9c11de
--- /dev/null
+++ b/src/tools/miri/tests/fail/panic/abort_unwind.rs
@@ -0,0 +1,11 @@
+//@error-in-other-file: the program aborted execution
+//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();"
+//@normalize-stderr-test: "\| +\^+" -> "| ^"
+//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
+//@normalize-stderr-test: "\n +at [^\n]+" -> ""
+
+#![feature(abort_unwind)]
+
+fn main() {
+    std::panic::abort_unwind(|| panic!("PANIC!!!"));
+}
diff --git a/src/tools/miri/tests/fail/panic/abort_unwind.stderr b/src/tools/miri/tests/fail/panic/abort_unwind.stderr
new file mode 100644
index 00000000000..e9c5413693e
--- /dev/null
+++ b/src/tools/miri/tests/fail/panic/abort_unwind.stderr
@@ -0,0 +1,33 @@
+thread 'main' panicked at tests/fail/panic/abort_unwind.rs:LL:CC:
+PANIC!!!
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
+thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC:
+panic in a function that cannot unwind
+stack backtrace:
+thread caused non-unwinding panic. aborting.
+error: abnormal termination: the program aborted execution
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
+   |
+LL |     ABORT();
+   | ^ the program aborted execution
+   |
+   = note: BACKTRACE:
+   = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
+   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
+   = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC
+   = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC
+   = note: inside `std::panic::abort_unwind::<{closure@tests/fail/panic/abort_unwind.rs:LL:CC}, ()>` at RUSTLIB/core/src/panic.rs:LL:CC
+note: inside `main`
+  --> tests/fail/panic/abort_unwind.rs:LL:CC
+   |
+LL |     std::panic::abort_unwind(|| panic!("PANIC!!!"));
+   | ^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr
index b157e9f0b21..b416f0eb689 100644
--- a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr
+++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr
@@ -15,9 +15,9 @@ LL |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
    = note: inside `std::panicking::r#try::<i32, &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at RUSTLIB/std/src/panic.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC
-   = note: inside `std::panicking::r#try::do_call::<{closure@std::rt::lang_start_internal::{closure#2}}, isize>` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `std::panicking::r#try::<isize, {closure@std::rt::lang_start_internal::{closure#2}}>` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#2}}, isize>` at RUSTLIB/std/src/panic.rs:LL:CC
+   = note: inside `std::panicking::r#try::do_call::<{closure@std::rt::lang_start_internal::{closure#1}}, isize>` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::r#try::<isize, {closure@std::rt::lang_start_internal::{closure#1}}>` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#1}}, isize>` at RUSTLIB/std/src/panic.rs:LL:CC
    = note: inside `std::rt::lang_start_internal` at RUSTLIB/std/src/rt.rs:LL:CC
    = note: inside `std::rt::lang_start::<()>` at RUSTLIB/std/src/rt.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.rs b/src/tools/miri/tests/fail/tree_borrows/children-can-alias.rs
index 036267dc11e..d3f272dfbf8 100644
--- a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.rs
+++ b/src/tools/miri/tests/fail/tree_borrows/children-can-alias.rs
@@ -8,8 +8,7 @@
 
 #![feature(ptr_internals)]
 
-use core::ptr::Unique;
-use core::ptr::addr_of_mut;
+use core::ptr::{Unique, addr_of_mut};
 
 fn main() {
     let mut data = 0u8;
diff --git a/src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.rs b/src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.rs
new file mode 100644
index 00000000000..5fb81296494
--- /dev/null
+++ b/src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.rs
@@ -0,0 +1,32 @@
+//! Ensure that a box with a custom allocator detects when the pointer is dangling.
+#![feature(allocator_api)]
+// This should not need the aliasing model.
+//@compile-flags: -Zmiri-disable-stacked-borrows
+use std::alloc::Layout;
+use std::ptr::NonNull;
+
+#[allow(unused)]
+struct MyAlloc(usize, usize); // make sure `Box<T, MyAlloc>` is an `Aggregate`
+
+unsafe impl std::alloc::Allocator for MyAlloc {
+    fn allocate(&self, _layout: Layout) -> Result<NonNull<[u8]>, std::alloc::AllocError> {
+        unimplemented!()
+    }
+
+    unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {
+        unimplemented!()
+    }
+}
+
+#[repr(C)]
+struct MyBox<T> {
+    ptr: NonNull<T>,
+    alloc: MyAlloc,
+}
+
+fn main() {
+    let b = MyBox { ptr: NonNull::<i32>::dangling(), alloc: MyAlloc(0, 0) };
+    let _b: Box<i32, MyAlloc> = unsafe {
+        std::mem::transmute(b) //~ERROR: dangling box
+    };
+}
diff --git a/src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.stderr b/src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.stderr
new file mode 100644
index 00000000000..76d7e66cfc5
--- /dev/null
+++ b/src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: constructing invalid value: encountered a dangling box (0x4[noalloc] has no provenance)
+  --> tests/fail/validity/box-custom-alloc-dangling-ptr.rs:LL:CC
+   |
+LL |         std::mem::transmute(b)
+   |         ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (0x4[noalloc] has no provenance)
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/validity/box-custom-alloc-dangling-ptr.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.rs b/src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.rs
new file mode 100644
index 00000000000..101a550593f
--- /dev/null
+++ b/src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.rs
@@ -0,0 +1,37 @@
+//! Ensure that a box with a custom allocator detects when the allocator itself is invalid.
+#![feature(allocator_api)]
+// This should not need the aliasing model.
+//@compile-flags: -Zmiri-disable-stacked-borrows
+use std::alloc::Layout;
+use std::mem::MaybeUninit;
+use std::ptr::NonNull;
+
+// make sure `Box<T, MyAlloc>` is an `Aggregate`
+#[allow(unused)]
+struct MyAlloc {
+    my_alloc_field1: usize,
+    my_alloc_field2: usize,
+}
+
+unsafe impl std::alloc::Allocator for MyAlloc {
+    fn allocate(&self, _layout: Layout) -> Result<NonNull<[u8]>, std::alloc::AllocError> {
+        unimplemented!()
+    }
+
+    unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {
+        unimplemented!()
+    }
+}
+
+#[repr(C)]
+struct MyBox<T> {
+    ptr: NonNull<T>,
+    alloc: MaybeUninit<MyAlloc>,
+}
+
+fn main() {
+    let b = MyBox { ptr: NonNull::from(&42), alloc: MaybeUninit::uninit() };
+    let _b: Box<i32, MyAlloc> = unsafe {
+        std::mem::transmute(b) //~ERROR: uninitialized memory
+    };
+}
diff --git a/src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.stderr b/src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.stderr
new file mode 100644
index 00000000000..e151f80dde3
--- /dev/null
+++ b/src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: constructing invalid value at .1.my_alloc_field1: encountered uninitialized memory, but expected an integer
+  --> tests/fail/validity/box-custom-alloc-invalid-alloc.rs:LL:CC
+   |
+LL |         std::mem::transmute(b)
+   |         ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .1.my_alloc_field1: encountered uninitialized memory, but expected an integer
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/validity/box-custom-alloc-invalid-alloc.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs
index 1478abedee0..566ddac2cc7 100644
--- a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs
+++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs
@@ -5,7 +5,9 @@ trait Trait {
 
 impl<T: Copy> Trait for T {
     type Assoc = T;
-    fn foo(&self) -> T { *self }
+    fn foo(&self) -> T {
+        *self
+    }
 }
 
 fn main() {
diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs
deleted file mode 100644
index 1193dddc577..00000000000
--- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-// We want to control preemption here.
-// Avoid accidental synchronization via address reuse.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-cross-thread-rate=0
-
-#![feature(core_intrinsics)]
-
-use std::ptr;
-use std::sync::atomic::AtomicU32;
-use std::sync::atomic::Ordering::*;
-use std::thread::spawn;
-
-fn static_atomic_u32(val: u32) -> &'static AtomicU32 {
-    let ret = Box::leak(Box::new(AtomicU32::new(val)));
-    ret
-}
-
-fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] {
-    unsafe { std::mem::transmute::<*const u32, *const [u16; 2]>(dword) }
-}
-
-// Wine's SRWLock implementation does this, which is definitely undefined in C++ memory model
-// https://github.com/wine-mirror/wine/blob/303f8042f9db508adaca02ef21f8de4992cb9c03/dlls/ntdll/sync.c#L543-L566
-// It probably works just fine on x86, but Intel does document this as "don't do it!"
-pub fn main() {
-    let x = static_atomic_u32(0);
-    let j1 = spawn(move || {
-        x.store(1, Relaxed);
-    });
-
-    let j2 = spawn(move || {
-        let x_ptr = x as *const AtomicU32 as *const u32;
-        let x_split = split_u32_ptr(x_ptr);
-        unsafe {
-            let hi = ptr::addr_of!((*x_split)[0]);
-            std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: (1) 4-byte atomic store on thread `unnamed-1` and (2) 2-byte atomic load
-        }
-    });
-
-    j1.join().unwrap();
-    j2.join().unwrap();
-}
diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs
deleted file mode 100644
index 0a0e372f1f3..00000000000
--- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-// We want to control preemption here.
-// Avoid accidental synchronization via address reuse.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-cross-thread-rate=0
-
-use std::sync::atomic::Ordering::*;
-use std::sync::atomic::{AtomicU16, AtomicU32};
-use std::thread::spawn;
-
-fn static_atomic(val: u32) -> &'static AtomicU32 {
-    let ret = Box::leak(Box::new(AtomicU32::new(val)));
-    ret
-}
-
-fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] {
-    unsafe { std::mem::transmute::<*const u32, *const [u16; 2]>(dword) }
-}
-
-// Racing mixed size reads may cause two loads to read-from
-// the same store but observe different values, which doesn't make
-// sense under the formal model so we forbid this.
-pub fn main() {
-    let x = static_atomic(0);
-
-    let j1 = spawn(move || {
-        x.load(Relaxed);
-    });
-
-    let j2 = spawn(move || {
-        let x_ptr = x as *const AtomicU32 as *const u32;
-        let x_split = split_u32_ptr(x_ptr);
-        unsafe {
-            let hi = x_split as *const u16 as *const AtomicU16;
-            (*hi).load(Relaxed); //~ ERROR: (1) 4-byte atomic load on thread `unnamed-1` and (2) 2-byte atomic load
-        }
-    });
-
-    j1.join().unwrap();
-    j2.join().unwrap();
-}
diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr
deleted file mode 100644
index 9e6a6e80418..00000000000
--- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error: Undefined Behavior: Race condition detected between (1) 4-byte atomic load on thread `unnamed-ID` and (2) 2-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here
-  --> tests/fail/weak_memory/racing_mixed_size_read.rs:LL:CC
-   |
-LL |             (*hi).load(Relaxed);
-   |             ^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 4-byte atomic load on thread `unnamed-ID` and (2) 2-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here
-   |
-help: and (1) occurred earlier here
-  --> tests/fail/weak_memory/racing_mixed_size_read.rs:LL:CC
-   |
-LL |         x.load(Relaxed);
-   |         ^^^^^^^^^^^^^^^
-   = help: overlapping unsynchronized atomic accesses must use the same access size
-   = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
-   = note: inside closure at tests/fail/weak_memory/racing_mixed_size_read.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs
index 255a93226a9..20e642a0a29 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs
@@ -6,8 +6,7 @@
 
 use std::mem::MaybeUninit;
 use std::ptr::{self, addr_of};
-use std::sync::atomic::AtomicI32;
-use std::sync::atomic::Ordering;
+use std::sync::atomic::{AtomicI32, Ordering};
 use std::thread;
 use std::time::{Duration, Instant};
 
diff --git a/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs b/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs
index 2dc09709b8e..b5738600040 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs
@@ -8,8 +8,7 @@
 // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
 #![allow(static_mut_refs)]
 
-use std::mem;
-use std::ptr;
+use std::{mem, ptr};
 
 pub type Key = libc::pthread_key_t;
 
diff --git a/src/tools/miri/tests/pass-dep/getrandom.rs b/src/tools/miri/tests/pass-dep/getrandom.rs
index 53de3af7635..a5bc5ec7079 100644
--- a/src/tools/miri/tests/pass-dep/getrandom.rs
+++ b/src/tools/miri/tests/pass-dep/getrandom.rs
@@ -6,6 +6,11 @@
 /// Test direct calls of getrandom 0.1 and 0.2.
 fn main() {
     let mut data = vec![0; 16];
+
+    // Old Solaris had a different return type for `getrandom`, and old versions of the getrandom crate
+    // used that signature, which Miri is not happy about.
+    #[cfg(not(target_os = "solaris"))]
     getrandom_01::getrandom(&mut data).unwrap();
+
     getrandom_02::getrandom(&mut data).unwrap();
 }
diff --git a/src/tools/miri/tests/pass-dep/libc/gettid.rs b/src/tools/miri/tests/pass-dep/libc/gettid.rs
index ca352e0109a..51f1a5ed708 100644
--- a/src/tools/miri/tests/pass-dep/libc/gettid.rs
+++ b/src/tools/miri/tests/pass-dep/libc/gettid.rs
@@ -2,9 +2,10 @@
 //@revisions: with_isolation without_isolation
 //@[without_isolation] compile-flags: -Zmiri-disable-isolation
 
-use libc::{getpid, gettid};
 use std::thread;
 
+use libc::{getpid, gettid};
+
 fn main() {
     thread::spawn(|| {
         // Test that in isolation mode a deterministic value will be returned.
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs
index ff152eaea5c..8aa8c7dcb8e 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs
@@ -5,9 +5,10 @@
 #![feature(pointer_is_aligned_to)]
 #![feature(strict_provenance)]
 
-use libc::{cpu_set_t, sched_getaffinity, sched_setaffinity};
 use std::mem::{size_of, size_of_val};
 
+use libc::{cpu_set_t, sched_getaffinity, sched_setaffinity};
+
 // If pid is zero, then the calling thread is used.
 const PID: i32 = 0;
 
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs
index eb38529ae57..d7675a40163 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs
@@ -1,5 +1,5 @@
 //@only-target: linux
-// test_epoll_block_then_unblock depends on a deterministic schedule.
+// test_epoll_block_then_unblock and test_epoll_race depend on a deterministic schedule.
 //@compile-flags: -Zmiri-preemption-rate=0
 
 use std::convert::TryInto;
@@ -12,6 +12,7 @@ fn main() {
     test_epoll_block_without_notification();
     test_epoll_block_then_unblock();
     test_notification_after_timeout();
+    test_epoll_race();
 }
 
 // Using `as` cast since `EPOLLET` wraps around
@@ -137,3 +138,41 @@ fn test_notification_after_timeout() {
     let expected_value = fds[0] as u64;
     check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 10);
 }
+
+// This test shows a data_race before epoll had vector clocks added.
+fn test_epoll_race() {
+    // Create an epoll instance.
+    let epfd = unsafe { libc::epoll_create1(0) };
+    assert_ne!(epfd, -1);
+
+    // Create an eventfd instance.
+    let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC;
+    let fd = unsafe { libc::eventfd(0, flags) };
+
+    // Register eventfd with the epoll instance.
+    let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd as u64 };
+    let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) };
+    assert_eq!(res, 0);
+
+    static mut VAL: u8 = 0;
+    let thread1 = thread::spawn(move || {
+        // Write to the static mut variable.
+        unsafe { VAL = 1 };
+        // Write to the eventfd instance.
+        let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes();
+        let res = unsafe { libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) };
+        // read returns number of bytes that have been read, which is always 8.
+        assert_eq!(res, 8);
+    });
+    thread::yield_now();
+    // epoll_wait for the event to happen.
+    let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap();
+    let expected_value = u64::try_from(fd).unwrap();
+    check_epoll_wait::<8>(epfd, &[(expected_event, expected_value)], -1);
+    // Read from the static mut variable.
+    #[allow(static_mut_refs)]
+    unsafe {
+        assert_eq!(VAL, 1)
+    };
+    thread1.join().unwrap();
+}
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs
index be11f65a1e0..99d6d2b38f8 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-flock.rs
@@ -1,7 +1,9 @@
 //@ignore-target: windows # File handling is not implemented yet
 //@compile-flags: -Zmiri-disable-isolation
 
-use std::{fs::File, io::Error, os::fd::AsRawFd};
+use std::fs::File;
+use std::io::Error;
+use std::os::fd::AsRawFd;
 
 #[path = "../../utils/mod.rs"]
 mod utils;
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
index 17e6e507c27..f85abe2cc43 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
@@ -230,8 +230,7 @@ fn test_posix_mkstemp() {
 
 /// Test allocating variant of `realpath`.
 fn test_posix_realpath_alloc() {
-    use std::os::unix::ffi::OsStrExt;
-    use std::os::unix::ffi::OsStringExt;
+    use std::os::unix::ffi::{OsStrExt, OsStringExt};
 
     let buf;
     let path = utils::tmp().join("miri_test_libc_posix_realpath_alloc");
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-random.rs b/src/tools/miri/tests/pass-dep/libc/libc-random.rs
index e951603639c..8f4398cbd8f 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-random.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-random.rs
@@ -6,6 +6,8 @@ fn main() {
     test_getentropy();
     #[cfg(not(target_os = "macos"))]
     test_getrandom();
+    #[cfg(any(target_os = "freebsd", target_os = "illumos", target_os = "solaris"))]
+    test_arc4random_buf();
 }
 
 fn test_getentropy() {
@@ -61,3 +63,14 @@ fn test_getrandom() {
         );
     }
 }
+
+#[cfg(any(target_os = "freebsd", target_os = "illumos", target_os = "solaris"))]
+fn test_arc4random_buf() {
+    // FIXME: Use declaration from libc once <https://github.com/rust-lang/libc/pull/3944> lands.
+    extern "C" {
+        fn arc4random_buf(buf: *mut libc::c_void, size: libc::size_t);
+    }
+    let mut buf = [0u8; 5];
+    unsafe { arc4random_buf(buf.as_mut_ptr() as _, buf.len()) };
+    assert!(buf != [0u8; 5]);
+}
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-time.rs b/src/tools/miri/tests/pass-dep/libc/libc-time.rs
index c2c87586492..84dbd8ad768 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-time.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-time.rs
@@ -15,7 +15,7 @@ fn test_clocks() {
     assert_eq!(is_error, 0);
     let is_error = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) };
     assert_eq!(is_error, 0);
-    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
+    #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "android"))]
     {
         let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) };
         assert_eq!(is_error, 0);
@@ -63,9 +63,19 @@ fn test_localtime_r() {
         tm_wday: 0,
         tm_yday: 0,
         tm_isdst: 0,
-        #[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))]
+        #[cfg(any(
+            target_os = "linux",
+            target_os = "macos",
+            target_os = "freebsd",
+            target_os = "android"
+        ))]
         tm_gmtoff: 0,
-        #[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))]
+        #[cfg(any(
+            target_os = "linux",
+            target_os = "macos",
+            target_os = "freebsd",
+            target_os = "android"
+        ))]
         tm_zone: std::ptr::null_mut::<libc::c_char>(),
     };
     let res = unsafe { libc::localtime_r(custom_time_ptr, &mut tm) };
@@ -79,9 +89,19 @@ fn test_localtime_r() {
     assert_eq!(tm.tm_wday, 0);
     assert_eq!(tm.tm_yday, 97);
     assert_eq!(tm.tm_isdst, -1);
-    #[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))]
+    #[cfg(any(
+        target_os = "linux",
+        target_os = "macos",
+        target_os = "freebsd",
+        target_os = "android"
+    ))]
     assert_eq!(tm.tm_gmtoff, 0);
-    #[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))]
+    #[cfg(any(
+        target_os = "linux",
+        target_os = "macos",
+        target_os = "freebsd",
+        target_os = "android"
+    ))]
     unsafe {
         assert_eq!(std::ffi::CStr::from_ptr(tm.tm_zone).to_str().unwrap(), "+00")
     };
diff --git a/src/tools/miri/tests/pass-dep/tokio/file-io.rs b/src/tools/miri/tests/pass-dep/tokio/file-io.rs
index 14c27285a6a..6e88b907f5d 100644
--- a/src/tools/miri/tests/pass-dep/tokio/file-io.rs
+++ b/src/tools/miri/tests/pass-dep/tokio/file-io.rs
@@ -2,6 +2,7 @@
 //@only-target: linux # We only support tokio on Linux
 
 use std::fs::remove_file;
+
 use tokio::fs::{File, OpenOptions};
 use tokio::io::{self, AsyncReadExt, AsyncWriteExt};
 
diff --git a/src/tools/miri/tests/pass/async-niche-aliasing.rs b/src/tools/miri/tests/pass/async-niche-aliasing.rs
index ab82c929a94..fe4ddd9d800 100644
--- a/src/tools/miri/tests/pass/async-niche-aliasing.rs
+++ b/src/tools/miri/tests/pass/async-niche-aliasing.rs
@@ -1,13 +1,11 @@
 //@revisions: stack tree
 //@[tree]compile-flags: -Zmiri-tree-borrows
 
-use std::{
-    future::Future,
-    mem::MaybeUninit,
-    pin::Pin,
-    sync::Arc,
-    task::{Context, Poll, Wake},
-};
+use std::future::Future;
+use std::mem::MaybeUninit;
+use std::pin::Pin;
+use std::sync::Arc;
+use std::task::{Context, Poll, Wake};
 
 struct ThingAdder<'a> {
     // Using `MaybeUninit` to ensure there are no niches here.
diff --git a/src/tools/miri/tests/pass/atomic-compare-exchange-weak-never-fail.rs b/src/tools/miri/tests/pass/atomic-compare-exchange-weak-never-fail.rs
index 8d3d71869f4..0a236377a9c 100644
--- a/src/tools/miri/tests/pass/atomic-compare-exchange-weak-never-fail.rs
+++ b/src/tools/miri/tests/pass/atomic-compare-exchange-weak-never-fail.rs
@@ -1,5 +1,6 @@
 //@compile-flags: -Zmiri-compare-exchange-weak-failure-rate=0.0
-use std::sync::atomic::{AtomicBool, Ordering::*};
+use std::sync::atomic::AtomicBool;
+use std::sync::atomic::Ordering::*;
 
 // Ensure that compare_exchange_weak never fails.
 fn main() {
diff --git a/src/tools/miri/tests/pass/atomic.rs b/src/tools/miri/tests/pass/atomic.rs
index 781cc9bd309..f84fe825d01 100644
--- a/src/tools/miri/tests/pass/atomic.rs
+++ b/src/tools/miri/tests/pass/atomic.rs
@@ -6,9 +6,8 @@
 // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
 #![allow(static_mut_refs)]
 
-use std::sync::atomic::{
-    AtomicBool, AtomicIsize, AtomicPtr, AtomicU64, Ordering::*, compiler_fence, fence,
-};
+use std::sync::atomic::Ordering::*;
+use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicU64, compiler_fence, fence};
 
 fn main() {
     atomic_bool();
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr
index b87063431ad..9849a1aa74e 100644
--- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr
+++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr
@@ -10,7 +10,7 @@ RUSTLIB/core/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once)
 RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call)
 RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try)
 RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind)
-RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#2})
+RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#1})
 RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call)
 RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try)
 RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind)
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr
index 2c729c49ee0..48d9649c920 100644
--- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr
+++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr
@@ -10,7 +10,7 @@ RUSTLIB/core/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once)
 RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call)
 RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try)
 RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind)
-RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#2})
+RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#1})
 RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call)
 RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try)
 RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind)
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr
index d9414aa6518..667ee04e624 100644
--- a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr
+++ b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr
@@ -14,7 +14,7 @@
  at RUSTLIB/std/src/panicking.rs:LL:CC
    7: std::panic::catch_unwind
  at RUSTLIB/std/src/panic.rs:LL:CC
-   8: std::rt::lang_start_internal::{closure#2}
+   8: std::rt::lang_start_internal::{closure#1}
  at RUSTLIB/std/src/rt.rs:LL:CC
    9: std::panicking::r#try::do_call
  at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr
index d6d69ee837e..b3a3a9d654a 100644
--- a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr
+++ b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr
@@ -22,7 +22,7 @@
  at RUSTLIB/std/src/panicking.rs:LL:CC
   11: std::panic::catch_unwind
  at RUSTLIB/std/src/panic.rs:LL:CC
-  12: std::rt::lang_start_internal::{closure#2}
+  12: std::rt::lang_start_internal::{closure#1}
  at RUSTLIB/std/src/rt.rs:LL:CC
   13: std::panicking::r#try::do_call
  at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs b/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs
index a1371242f60..0a61db960c1 100644
--- a/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs
+++ b/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs
@@ -7,13 +7,11 @@
 #![feature(allocator_api)]
 #![feature(strict_provenance)]
 
-use std::{
-    alloc::{AllocError, Allocator, Layout},
-    cell::{Cell, UnsafeCell},
-    mem,
-    ptr::{self, NonNull, addr_of},
-    thread::{self, ThreadId},
-};
+use std::alloc::{AllocError, Allocator, Layout};
+use std::cell::{Cell, UnsafeCell};
+use std::mem;
+use std::ptr::{self, NonNull, addr_of};
+use std::thread::{self, ThreadId};
 
 const BIN_SIZE: usize = 8;
 
diff --git a/src/tools/miri/tests/pass/box-custom-alloc.rs b/src/tools/miri/tests/pass/box-custom-alloc.rs
index 8d6da0733fe..71ce019187c 100644
--- a/src/tools/miri/tests/pass/box-custom-alloc.rs
+++ b/src/tools/miri/tests/pass/box-custom-alloc.rs
@@ -3,8 +3,7 @@
 #![allow(incomplete_features)] // for trait upcasting
 #![feature(allocator_api, trait_upcasting)]
 
-use std::alloc::Layout;
-use std::alloc::{AllocError, Allocator};
+use std::alloc::{AllocError, Allocator, Layout};
 use std::cell::Cell;
 use std::mem::MaybeUninit;
 use std::ptr::{self, NonNull};
diff --git a/src/tools/miri/tests/pass/concurrency/address_reuse_happens_before.rs b/src/tools/miri/tests/pass/concurrency/address_reuse_happens_before.rs
index cfc1ef7ae45..255f4061abc 100644
--- a/src/tools/miri/tests/pass/concurrency/address_reuse_happens_before.rs
+++ b/src/tools/miri/tests/pass/concurrency/address_reuse_happens_before.rs
@@ -5,7 +5,8 @@
 #![feature(sync_unsafe_cell)]
 
 use std::cell::SyncUnsafeCell;
-use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering::Relaxed;
 use std::thread;
 
 static ADDR: AtomicUsize = AtomicUsize::new(0);
diff --git a/src/tools/miri/tests/pass/concurrency/data_race.rs b/src/tools/miri/tests/pass/concurrency/data_race.rs
index 34380dfa504..d16de0ae8e2 100644
--- a/src/tools/miri/tests/pass/concurrency/data_race.rs
+++ b/src/tools/miri/tests/pass/concurrency/data_race.rs
@@ -1,7 +1,7 @@
 //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
 
 use std::sync::atomic::*;
-use std::thread::spawn;
+use std::thread::{self, spawn};
 
 #[derive(Copy, Clone)]
 struct EvilSend<T>(pub T);
@@ -143,10 +143,84 @@ fn test_local_variable_lazy_write() {
     assert_eq!(val, 127);
 }
 
+// This test coverse the case where the non-atomic access come first.
+fn test_read_read_race1() {
+    let a = AtomicU16::new(0);
+
+    thread::scope(|s| {
+        s.spawn(|| {
+            let ptr = &a as *const AtomicU16 as *mut u16;
+            unsafe { ptr.read() };
+        });
+        s.spawn(|| {
+            thread::yield_now();
+
+            a.load(Ordering::SeqCst);
+        });
+    });
+}
+
+// This test coverse the case where the atomic access come first.
+fn test_read_read_race2() {
+    let a = AtomicU16::new(0);
+
+    thread::scope(|s| {
+        s.spawn(|| {
+            a.load(Ordering::SeqCst);
+        });
+        s.spawn(|| {
+            thread::yield_now();
+
+            let ptr = &a as *const AtomicU16 as *mut u16;
+            unsafe { ptr.read() };
+        });
+    });
+}
+
+fn mixed_size_read_read() {
+    fn convert(a: &AtomicU16) -> &[AtomicU8; 2] {
+        unsafe { std::mem::transmute(a) }
+    }
+
+    let a = AtomicU16::new(0);
+    let a16 = &a;
+    let a8 = convert(a16);
+
+    // Just two different-sized atomic reads without any writes are fine.
+    thread::scope(|s| {
+        s.spawn(|| {
+            a16.load(Ordering::SeqCst);
+        });
+        s.spawn(|| {
+            a8[0].load(Ordering::SeqCst);
+        });
+    });
+}
+
+fn failing_rmw_is_read() {
+    let a = AtomicUsize::new(0);
+    thread::scope(|s| {
+        s.spawn(|| unsafe {
+            // Non-atomic read.
+            let _val = *(&a as *const AtomicUsize).cast::<usize>();
+        });
+
+        s.spawn(|| {
+            // RMW that will fail.
+            // This is not considered a write, so there is no data race here.
+            a.compare_exchange(1, 2, Ordering::SeqCst, Ordering::SeqCst).unwrap_err();
+        });
+    });
+}
+
 pub fn main() {
     test_fence_sync();
     test_multiple_reads();
     test_rmw_no_block();
     test_simple_release();
     test_local_variable_lazy_write();
+    test_read_read_race1();
+    test_read_read_race2();
+    mixed_size_read_read();
+    failing_rmw_is_read();
 }
diff --git a/src/tools/miri/tests/pass/concurrency/sync_singlethread.rs b/src/tools/miri/tests/pass/concurrency/sync_singlethread.rs
index 5663e1c1426..e52dbd3186e 100644
--- a/src/tools/miri/tests/pass/concurrency/sync_singlethread.rs
+++ b/src/tools/miri/tests/pass/concurrency/sync_singlethread.rs
@@ -1,6 +1,5 @@
 use std::hint;
-use std::sync::atomic;
-use std::sync::{Mutex, TryLockError};
+use std::sync::{Mutex, TryLockError, atomic};
 
 fn main() {
     test_mutex_stdlib();
diff --git a/src/tools/miri/tests/pass/coroutine.rs b/src/tools/miri/tests/pass/coroutine.rs
index 7822c136d91..9ec9b1fc5bc 100644
--- a/src/tools/miri/tests/pass/coroutine.rs
+++ b/src/tools/miri/tests/pass/coroutine.rs
@@ -4,10 +4,8 @@
 
 use std::fmt::Debug;
 use std::mem::ManuallyDrop;
-use std::ops::{
-    Coroutine,
-    CoroutineState::{self, *},
-};
+use std::ops::Coroutine;
+use std::ops::CoroutineState::{self, *};
 use std::pin::Pin;
 use std::ptr;
 use std::sync::atomic::{AtomicUsize, Ordering};
diff --git a/src/tools/miri/tests/pass/dyn-arbitrary-self.rs b/src/tools/miri/tests/pass/dyn-arbitrary-self.rs
index dc2b9e4491b..d993e5ad68c 100644
--- a/src/tools/miri/tests/pass/dyn-arbitrary-self.rs
+++ b/src/tools/miri/tests/pass/dyn-arbitrary-self.rs
@@ -21,7 +21,9 @@ fn pin_box_dyn() {
 }
 
 fn stdlib_pointers() {
-    use std::{pin::Pin, rc::Rc, sync::Arc};
+    use std::pin::Pin;
+    use std::rc::Rc;
+    use std::sync::Arc;
 
     trait Trait {
         fn by_rc(self: Rc<Self>) -> i64;
@@ -60,10 +62,8 @@ fn stdlib_pointers() {
 }
 
 fn pointers_and_wrappers() {
-    use std::{
-        marker::Unsize,
-        ops::{CoerceUnsized, Deref, DispatchFromDyn},
-    };
+    use std::marker::Unsize;
+    use std::ops::{CoerceUnsized, Deref, DispatchFromDyn};
 
     struct Ptr<T: ?Sized>(Box<T>);
 
diff --git a/src/tools/miri/tests/pass/function_calls/abi_compat.rs b/src/tools/miri/tests/pass/function_calls/abi_compat.rs
index 0cfcd532ff4..b5feac8c677 100644
--- a/src/tools/miri/tests/pass/function_calls/abi_compat.rs
+++ b/src/tools/miri/tests/pass/function_calls/abi_compat.rs
@@ -1,7 +1,5 @@
-use std::mem;
-use std::num;
-use std::ptr;
 use std::rc::Rc;
+use std::{mem, num, ptr};
 
 #[derive(Copy, Clone, Default)]
 struct Zst;
diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
index cd606a5282a..f560669dd63 100644
--- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
+++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
@@ -11,7 +11,8 @@
 #![allow(incomplete_features, internal_features)]
 use std::intrinsics::simd as intrinsics;
 use std::ptr;
-use std::simd::{StdFloat, prelude::*};
+use std::simd::StdFloat;
+use std::simd::prelude::*;
 
 extern "rust-intrinsic" {
     #[rustc_nounwind]
diff --git a/src/tools/miri/tests/pass/issues/issue-miri-3541-dyn-vtable-trait-normalization.rs b/src/tools/miri/tests/pass/issues/issue-miri-3541-dyn-vtable-trait-normalization.rs
index c46031de2d8..123fe6ed642 100644
--- a/src/tools/miri/tests/pass/issues/issue-miri-3541-dyn-vtable-trait-normalization.rs
+++ b/src/tools/miri/tests/pass/issues/issue-miri-3541-dyn-vtable-trait-normalization.rs
@@ -2,7 +2,8 @@
 // This test is the result of minimizing the `emplacable` crate to reproduce
 // <https://github.com/rust-lang/miri/issues/3541>.
 
-use std::{ops::FnMut, ptr::Pointee};
+use std::ops::FnMut;
+use std::ptr::Pointee;
 
 pub type EmplacerFn<'a, T> = dyn for<'b> FnMut(<T as Pointee>::Metadata) + 'a;
 
diff --git a/src/tools/miri/tests/pass/leak-in-static.rs b/src/tools/miri/tests/pass/leak-in-static.rs
index 95233944088..6f08b64ada4 100644
--- a/src/tools/miri/tests/pass/leak-in-static.rs
+++ b/src/tools/miri/tests/pass/leak-in-static.rs
@@ -1,7 +1,5 @@
-use std::{
-    ptr,
-    sync::atomic::{AtomicPtr, Ordering},
-};
+use std::ptr;
+use std::sync::atomic::{AtomicPtr, Ordering};
 
 static mut LEAKER: Option<Box<Vec<i32>>> = None;
 
diff --git a/src/tools/miri/tests/pass/ptr_int_casts.rs b/src/tools/miri/tests/pass/ptr_int_casts.rs
index 684e8f6ec7b..4e274f62981 100644
--- a/src/tools/miri/tests/pass/ptr_int_casts.rs
+++ b/src/tools/miri/tests/pass/ptr_int_casts.rs
@@ -2,8 +2,7 @@
 // Tree Borrows doesn't support int2ptr casts, but let's make sure we don't immediately crash either.
 //@[tree]compile-flags: -Zmiri-tree-borrows
 //@[stack]compile-flags: -Zmiri-permissive-provenance
-use std::mem;
-use std::ptr;
+use std::{mem, ptr};
 
 fn eq_ref<T>(x: &T, y: &T) -> bool {
     x as *const _ == y as *const _
diff --git a/src/tools/miri/tests/pass/shims/env/var.rs b/src/tools/miri/tests/pass/shims/env/var.rs
index a576c1fc8bb..655b29674e3 100644
--- a/src/tools/miri/tests/pass/shims/env/var.rs
+++ b/src/tools/miri/tests/pass/shims/env/var.rs
@@ -1,6 +1,5 @@
 //@compile-flags: -Zmiri-preemption-rate=0
-use std::env;
-use std::thread;
+use std::{env, thread};
 
 fn main() {
     // Test that miri environment is isolated when communication is disabled.
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index 62424ca26b1..81151f4ac47 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -4,7 +4,7 @@
 #![feature(io_error_more)]
 #![feature(io_error_uncategorized)]
 
-use std::collections::HashMap;
+use std::collections::BTreeMap;
 use std::ffi::OsString;
 use std::fs::{
     File, OpenOptions, canonicalize, create_dir, read_dir, remove_dir, remove_dir_all, remove_file,
@@ -262,7 +262,7 @@ fn test_directory() {
     create_dir(&dir_1).unwrap();
     // Test that read_dir metadata calls succeed
     assert_eq!(
-        HashMap::from([
+        BTreeMap::from([
             (OsString::from("test_file_1"), true),
             (OsString::from("test_file_2"), true),
             (OsString::from("test_dir_1"), false)
@@ -273,7 +273,7 @@ fn test_directory() {
                 let e = e.unwrap();
                 (e.file_name(), e.metadata().unwrap().is_file())
             })
-            .collect::<HashMap<_, _>>()
+            .collect::<BTreeMap<_, _>>()
     );
     // Deleting the directory should fail, since it is not empty.
     assert_eq!(ErrorKind::DirectoryNotEmpty, remove_dir(&dir_path).unwrap_err().kind());
diff --git a/src/tools/miri/tests/pass/shims/random.rs b/src/tools/miri/tests/pass/shims/random.rs
new file mode 100644
index 00000000000..ae75ebdcd3f
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/random.rs
@@ -0,0 +1,5 @@
+#![feature(random)]
+
+fn main() {
+    let _x: i32 = std::random::random();
+}
diff --git a/src/tools/miri/tests/pass/shims/windows-threadname.rs b/src/tools/miri/tests/pass/shims/windows-threadname.rs
index 29c3fa5d5f3..f1c05fa3790 100644
--- a/src/tools/miri/tests/pass/shims/windows-threadname.rs
+++ b/src/tools/miri/tests/pass/shims/windows-threadname.rs
@@ -1,9 +1,8 @@
 //@only-target: windows # this directly tests windows-only functions
 
+use core::ffi::c_void;
 use std::ffi::OsStr;
 use std::os::windows::ffi::OsStrExt;
-
-use core::ffi::c_void;
 type HANDLE = *mut c_void;
 type PWSTR = *mut u16;
 type PCWSTR = *const u16;
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs
new file mode 100644
index 00000000000..a629e2acfe9
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs
@@ -0,0 +1,518 @@
+// We're testing x86 target specific features
+//@only-target: x86_64 i686
+//@compile-flags: -C target-feature=+gfni,+avx512f
+
+// The constants in the tests below are just bit patterns. They should not
+// be interpreted as integers; signedness does not make sense for them, but
+// __mXXXi happens to be defined in terms of signed integers.
+#![allow(overflowing_literals)]
+#![feature(avx512_target_feature)]
+#![feature(stdarch_x86_avx512)]
+
+#[cfg(target_arch = "x86")]
+use std::arch::x86::*;
+#[cfg(target_arch = "x86_64")]
+use std::arch::x86_64::*;
+use std::hint::black_box;
+use std::mem::{size_of, transmute};
+
+const IDENTITY_BYTE: i32 = 0;
+const CONSTANT_BYTE: i32 = 0x63;
+
+fn main() {
+    // Mostly copied from library/stdarch/crates/core_arch/src/x86/gfni.rs
+
+    assert!(is_x86_feature_detected!("avx512f"));
+    assert!(is_x86_feature_detected!("gfni"));
+
+    unsafe {
+        let byte_mul_test_data = generate_byte_mul_test_data();
+        let affine_mul_test_data_identity = generate_affine_mul_test_data(IDENTITY_BYTE as u8);
+        let affine_mul_test_data_constant = generate_affine_mul_test_data(CONSTANT_BYTE as u8);
+        let inv_tests_data = generate_inv_tests_data();
+
+        test_mm512_gf2p8mul_epi8(&byte_mul_test_data);
+        test_mm256_gf2p8mul_epi8(&byte_mul_test_data);
+        test_mm_gf2p8mul_epi8(&byte_mul_test_data);
+        test_mm512_gf2p8affine_epi64_epi8(&byte_mul_test_data, &affine_mul_test_data_identity);
+        test_mm256_gf2p8affine_epi64_epi8(&byte_mul_test_data, &affine_mul_test_data_identity);
+        test_mm_gf2p8affine_epi64_epi8(&byte_mul_test_data, &affine_mul_test_data_identity);
+        test_mm512_gf2p8affineinv_epi64_epi8(&inv_tests_data, &affine_mul_test_data_constant);
+        test_mm256_gf2p8affineinv_epi64_epi8(&inv_tests_data, &affine_mul_test_data_constant);
+        test_mm_gf2p8affineinv_epi64_epi8(&inv_tests_data, &affine_mul_test_data_constant);
+    }
+}
+
+#[target_feature(enable = "gfni,avx512f")]
+unsafe fn test_mm512_gf2p8mul_epi8(
+    byte_mul_test_data: &([u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES]),
+) {
+    let (left, right, expected) = byte_mul_test_data;
+
+    for i in 0..NUM_TEST_WORDS_512 {
+        let left = load_m512i_word(left, i);
+        let right = load_m512i_word(right, i);
+        let expected = load_m512i_word(expected, i);
+        let result = _mm512_gf2p8mul_epi8(left, right);
+        assert_eq_m512i(result, expected);
+    }
+}
+
+#[target_feature(enable = "gfni,avx")]
+unsafe fn test_mm256_gf2p8mul_epi8(
+    byte_mul_test_data: &([u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES]),
+) {
+    let (left, right, expected) = byte_mul_test_data;
+
+    for i in 0..NUM_TEST_WORDS_256 {
+        let left = load_m256i_word(left, i);
+        let right = load_m256i_word(right, i);
+        let expected = load_m256i_word(expected, i);
+        let result = _mm256_gf2p8mul_epi8(left, right);
+        assert_eq_m256i(result, expected);
+    }
+}
+
+#[target_feature(enable = "gfni")]
+unsafe fn test_mm_gf2p8mul_epi8(
+    byte_mul_test_data: &([u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES]),
+) {
+    let (left, right, expected) = byte_mul_test_data;
+
+    for i in 0..NUM_TEST_WORDS_128 {
+        let left = load_m128i_word(left, i);
+        let right = load_m128i_word(right, i);
+        let expected = load_m128i_word(expected, i);
+        let result = _mm_gf2p8mul_epi8(left, right);
+        assert_eq_m128i(result, expected);
+    }
+}
+
+#[target_feature(enable = "gfni,avx512f")]
+unsafe fn test_mm512_gf2p8affine_epi64_epi8(
+    byte_mul_test_data: &([u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES]),
+    affine_mul_test_data_identity: &(
+        [u64; NUM_TEST_WORDS_64],
+        [u8; NUM_TEST_ENTRIES],
+        [u8; NUM_TEST_ENTRIES],
+    ),
+) {
+    let identity: i64 = 0x01_02_04_08_10_20_40_80;
+    let constant: i64 = 0;
+    let identity = _mm512_set1_epi64(identity);
+    let constant = _mm512_set1_epi64(constant);
+    let constant_reference = _mm512_set1_epi8(CONSTANT_BYTE as i8);
+
+    let (bytes, more_bytes, _) = byte_mul_test_data;
+    let (matrices, vectors, references) = affine_mul_test_data_identity;
+
+    for i in 0..NUM_TEST_WORDS_512 {
+        let data = load_m512i_word(bytes, i);
+        let result = _mm512_gf2p8affine_epi64_epi8::<IDENTITY_BYTE>(data, identity);
+        assert_eq_m512i(result, data);
+        let result = _mm512_gf2p8affine_epi64_epi8::<CONSTANT_BYTE>(data, constant);
+        assert_eq_m512i(result, constant_reference);
+        let data = load_m512i_word(more_bytes, i);
+        let result = _mm512_gf2p8affine_epi64_epi8::<IDENTITY_BYTE>(data, identity);
+        assert_eq_m512i(result, data);
+        let result = _mm512_gf2p8affine_epi64_epi8::<CONSTANT_BYTE>(data, constant);
+        assert_eq_m512i(result, constant_reference);
+
+        let matrix = load_m512i_word(matrices, i);
+        let vector = load_m512i_word(vectors, i);
+        let reference = load_m512i_word(references, i);
+
+        let result = _mm512_gf2p8affine_epi64_epi8::<IDENTITY_BYTE>(vector, matrix);
+        assert_eq_m512i(result, reference);
+    }
+}
+
+#[target_feature(enable = "gfni,avx")]
+unsafe fn test_mm256_gf2p8affine_epi64_epi8(
+    byte_mul_test_data: &([u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES]),
+    affine_mul_test_data_identity: &(
+        [u64; NUM_TEST_WORDS_64],
+        [u8; NUM_TEST_ENTRIES],
+        [u8; NUM_TEST_ENTRIES],
+    ),
+) {
+    let identity: i64 = 0x01_02_04_08_10_20_40_80;
+    let constant: i64 = 0;
+    let identity = _mm256_set1_epi64x(identity);
+    let constant = _mm256_set1_epi64x(constant);
+    let constant_reference = _mm256_set1_epi8(CONSTANT_BYTE as i8);
+
+    let (bytes, more_bytes, _) = byte_mul_test_data;
+    let (matrices, vectors, references) = affine_mul_test_data_identity;
+
+    for i in 0..NUM_TEST_WORDS_256 {
+        let data = load_m256i_word(bytes, i);
+        let result = _mm256_gf2p8affine_epi64_epi8::<IDENTITY_BYTE>(data, identity);
+        assert_eq_m256i(result, data);
+        let result = _mm256_gf2p8affine_epi64_epi8::<CONSTANT_BYTE>(data, constant);
+        assert_eq_m256i(result, constant_reference);
+        let data = load_m256i_word(more_bytes, i);
+        let result = _mm256_gf2p8affine_epi64_epi8::<IDENTITY_BYTE>(data, identity);
+        assert_eq_m256i(result, data);
+        let result = _mm256_gf2p8affine_epi64_epi8::<CONSTANT_BYTE>(data, constant);
+        assert_eq_m256i(result, constant_reference);
+
+        let matrix = load_m256i_word(matrices, i);
+        let vector = load_m256i_word(vectors, i);
+        let reference = load_m256i_word(references, i);
+
+        let result = _mm256_gf2p8affine_epi64_epi8::<IDENTITY_BYTE>(vector, matrix);
+        assert_eq_m256i(result, reference);
+    }
+}
+
+#[target_feature(enable = "gfni")]
+unsafe fn test_mm_gf2p8affine_epi64_epi8(
+    byte_mul_test_data: &([u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES]),
+    affine_mul_test_data_identity: &(
+        [u64; NUM_TEST_WORDS_64],
+        [u8; NUM_TEST_ENTRIES],
+        [u8; NUM_TEST_ENTRIES],
+    ),
+) {
+    let identity: i64 = 0x01_02_04_08_10_20_40_80;
+    let constant: i64 = 0;
+    let identity = _mm_set1_epi64x(identity);
+    let constant = _mm_set1_epi64x(constant);
+    let constant_reference = _mm_set1_epi8(CONSTANT_BYTE as i8);
+
+    let (bytes, more_bytes, _) = byte_mul_test_data;
+    let (matrices, vectors, references) = affine_mul_test_data_identity;
+
+    for i in 0..NUM_TEST_WORDS_128 {
+        let data = load_m128i_word(bytes, i);
+        let result = _mm_gf2p8affine_epi64_epi8::<IDENTITY_BYTE>(data, identity);
+        assert_eq_m128i(result, data);
+        let result = _mm_gf2p8affine_epi64_epi8::<CONSTANT_BYTE>(data, constant);
+        assert_eq_m128i(result, constant_reference);
+        let data = load_m128i_word(more_bytes, i);
+        let result = _mm_gf2p8affine_epi64_epi8::<IDENTITY_BYTE>(data, identity);
+        assert_eq_m128i(result, data);
+        let result = _mm_gf2p8affine_epi64_epi8::<CONSTANT_BYTE>(data, constant);
+        assert_eq_m128i(result, constant_reference);
+
+        let matrix = load_m128i_word(matrices, i);
+        let vector = load_m128i_word(vectors, i);
+        let reference = load_m128i_word(references, i);
+
+        let result = _mm_gf2p8affine_epi64_epi8::<IDENTITY_BYTE>(vector, matrix);
+        assert_eq_m128i(result, reference);
+    }
+}
+
+#[target_feature(enable = "gfni,avx512f")]
+unsafe fn test_mm512_gf2p8affineinv_epi64_epi8(
+    inv_tests_data: &([u8; NUM_BYTES], [u8; NUM_BYTES]),
+    affine_mul_test_data_constant: &(
+        [u64; NUM_TEST_WORDS_64],
+        [u8; NUM_TEST_ENTRIES],
+        [u8; NUM_TEST_ENTRIES],
+    ),
+) {
+    let identity: i64 = 0x01_02_04_08_10_20_40_80;
+    let identity = _mm512_set1_epi64(identity);
+
+    // validate inversion
+    let (inputs, results) = inv_tests_data;
+
+    for i in 0..NUM_BYTES_WORDS_512 {
+        let input = load_m512i_word(inputs, i);
+        let reference = load_m512i_word(results, i);
+        let result = _mm512_gf2p8affineinv_epi64_epi8::<IDENTITY_BYTE>(input, identity);
+        let remultiplied = _mm512_gf2p8mul_epi8(result, input);
+        assert_eq_m512i(remultiplied, reference);
+    }
+
+    // validate subsequent affine operation
+    let (matrices, vectors, _affine_expected) = affine_mul_test_data_constant;
+
+    for i in 0..NUM_TEST_WORDS_512 {
+        let vector = load_m512i_word(vectors, i);
+        let matrix = load_m512i_word(matrices, i);
+
+        let inv_vec = _mm512_gf2p8affineinv_epi64_epi8::<IDENTITY_BYTE>(vector, identity);
+        let reference = _mm512_gf2p8affine_epi64_epi8::<CONSTANT_BYTE>(inv_vec, matrix);
+        let result = _mm512_gf2p8affineinv_epi64_epi8::<CONSTANT_BYTE>(vector, matrix);
+        assert_eq_m512i(result, reference);
+    }
+
+    // validate everything by virtue of checking against the AES SBox
+    const AES_S_BOX_MATRIX: i64 = 0xF1_E3_C7_8F_1F_3E_7C_F8;
+    let sbox_matrix = _mm512_set1_epi64(AES_S_BOX_MATRIX);
+
+    for i in 0..NUM_BYTES_WORDS_512 {
+        let reference = load_m512i_word(&AES_S_BOX, i);
+        let input = load_m512i_word(inputs, i);
+        let result = _mm512_gf2p8affineinv_epi64_epi8::<CONSTANT_BYTE>(input, sbox_matrix);
+        assert_eq_m512i(result, reference);
+    }
+}
+
+#[target_feature(enable = "gfni,avx")]
+unsafe fn test_mm256_gf2p8affineinv_epi64_epi8(
+    inv_tests_data: &([u8; NUM_BYTES], [u8; NUM_BYTES]),
+    affine_mul_test_data_constant: &(
+        [u64; NUM_TEST_WORDS_64],
+        [u8; NUM_TEST_ENTRIES],
+        [u8; NUM_TEST_ENTRIES],
+    ),
+) {
+    let identity: i64 = 0x01_02_04_08_10_20_40_80;
+    let identity = _mm256_set1_epi64x(identity);
+
+    // validate inversion
+    let (inputs, results) = inv_tests_data;
+
+    for i in 0..NUM_BYTES_WORDS_256 {
+        let input = load_m256i_word(inputs, i);
+        let reference = load_m256i_word(results, i);
+        let result = _mm256_gf2p8affineinv_epi64_epi8::<IDENTITY_BYTE>(input, identity);
+        let remultiplied = _mm256_gf2p8mul_epi8(result, input);
+        assert_eq_m256i(remultiplied, reference);
+    }
+
+    // validate subsequent affine operation
+    let (matrices, vectors, _affine_expected) = affine_mul_test_data_constant;
+
+    for i in 0..NUM_TEST_WORDS_256 {
+        let vector = load_m256i_word(vectors, i);
+        let matrix = load_m256i_word(matrices, i);
+
+        let inv_vec = _mm256_gf2p8affineinv_epi64_epi8::<IDENTITY_BYTE>(vector, identity);
+        let reference = _mm256_gf2p8affine_epi64_epi8::<CONSTANT_BYTE>(inv_vec, matrix);
+        let result = _mm256_gf2p8affineinv_epi64_epi8::<CONSTANT_BYTE>(vector, matrix);
+        assert_eq_m256i(result, reference);
+    }
+
+    // validate everything by virtue of checking against the AES SBox
+    const AES_S_BOX_MATRIX: i64 = 0xF1_E3_C7_8F_1F_3E_7C_F8;
+    let sbox_matrix = _mm256_set1_epi64x(AES_S_BOX_MATRIX);
+
+    for i in 0..NUM_BYTES_WORDS_256 {
+        let reference = load_m256i_word(&AES_S_BOX, i);
+        let input = load_m256i_word(inputs, i);
+        let result = _mm256_gf2p8affineinv_epi64_epi8::<CONSTANT_BYTE>(input, sbox_matrix);
+        assert_eq_m256i(result, reference);
+    }
+}
+
+#[target_feature(enable = "gfni")]
+unsafe fn test_mm_gf2p8affineinv_epi64_epi8(
+    inv_tests_data: &([u8; NUM_BYTES], [u8; NUM_BYTES]),
+    affine_mul_test_data_constant: &(
+        [u64; NUM_TEST_WORDS_64],
+        [u8; NUM_TEST_ENTRIES],
+        [u8; NUM_TEST_ENTRIES],
+    ),
+) {
+    let identity: i64 = 0x01_02_04_08_10_20_40_80;
+    let identity = _mm_set1_epi64x(identity);
+
+    // validate inversion
+    let (inputs, results) = inv_tests_data;
+
+    for i in 0..NUM_BYTES_WORDS_128 {
+        let input = load_m128i_word(inputs, i);
+        let reference = load_m128i_word(results, i);
+        let result = _mm_gf2p8affineinv_epi64_epi8::<IDENTITY_BYTE>(input, identity);
+        let remultiplied = _mm_gf2p8mul_epi8(result, input);
+        assert_eq_m128i(remultiplied, reference);
+    }
+
+    // validate subsequent affine operation
+    let (matrices, vectors, _affine_expected) = affine_mul_test_data_constant;
+
+    for i in 0..NUM_TEST_WORDS_128 {
+        let vector = load_m128i_word(vectors, i);
+        let matrix = load_m128i_word(matrices, i);
+
+        let inv_vec = _mm_gf2p8affineinv_epi64_epi8::<IDENTITY_BYTE>(vector, identity);
+        let reference = _mm_gf2p8affine_epi64_epi8::<CONSTANT_BYTE>(inv_vec, matrix);
+        let result = _mm_gf2p8affineinv_epi64_epi8::<CONSTANT_BYTE>(vector, matrix);
+        assert_eq_m128i(result, reference);
+    }
+
+    // validate everything by virtue of checking against the AES SBox
+    const AES_S_BOX_MATRIX: i64 = 0xF1_E3_C7_8F_1F_3E_7C_F8;
+    let sbox_matrix = _mm_set1_epi64x(AES_S_BOX_MATRIX);
+
+    for i in 0..NUM_BYTES_WORDS_128 {
+        let reference = load_m128i_word(&AES_S_BOX, i);
+        let input = load_m128i_word(inputs, i);
+        let result = _mm_gf2p8affineinv_epi64_epi8::<CONSTANT_BYTE>(input, sbox_matrix);
+        assert_eq_m128i(result, reference);
+    }
+}
+
+/* Various utilities for processing SIMD values. */
+
+#[target_feature(enable = "sse2")]
+unsafe fn load_m128i_word<T>(data: &[T], word_index: usize) -> __m128i {
+    let byte_offset = word_index * 16 / size_of::<T>();
+    let pointer = data.as_ptr().add(byte_offset) as *const __m128i;
+    _mm_loadu_si128(black_box(pointer))
+}
+
+#[target_feature(enable = "avx")]
+unsafe fn load_m256i_word<T>(data: &[T], word_index: usize) -> __m256i {
+    let byte_offset = word_index * 32 / size_of::<T>();
+    let pointer = data.as_ptr().add(byte_offset) as *const __m256i;
+    _mm256_loadu_si256(black_box(pointer))
+}
+
+#[target_feature(enable = "avx512f")]
+unsafe fn load_m512i_word<T>(data: &[T], word_index: usize) -> __m512i {
+    let byte_offset = word_index * 64 / size_of::<T>();
+    let pointer = data.as_ptr().add(byte_offset) as *const i32;
+    _mm512_loadu_si512(black_box(pointer))
+}
+
+#[track_caller]
+#[target_feature(enable = "sse2")]
+unsafe fn assert_eq_m128i(a: __m128i, b: __m128i) {
+    assert_eq!(transmute::<_, [u64; 2]>(a), transmute::<_, [u64; 2]>(b))
+}
+
+#[track_caller]
+#[target_feature(enable = "avx")]
+unsafe fn assert_eq_m256i(a: __m256i, b: __m256i) {
+    assert_eq!(transmute::<_, [u64; 4]>(a), transmute::<_, [u64; 4]>(b))
+}
+
+#[track_caller]
+#[target_feature(enable = "avx512f")]
+unsafe fn assert_eq_m512i(a: __m512i, b: __m512i) {
+    assert_eq!(transmute::<_, [u64; 8]>(a), transmute::<_, [u64; 8]>(b))
+}
+
+/* Software implementation of the hardware intrinsics. */
+
+fn mulbyte(left: u8, right: u8) -> u8 {
+    // this implementation follows the description in
+    // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm512_gf2p8mul_epi8
+    const REDUCTION_POLYNOMIAL: u16 = 0x11b;
+    let left: u16 = left.into();
+    let right: u16 = right.into();
+    let mut carryless_product: u16 = 0;
+
+    // Carryless multiplication
+    for i in 0..8 {
+        if ((left >> i) & 0x01) != 0 {
+            carryless_product ^= right << i;
+        }
+    }
+
+    // reduction, adding in "0" where appropriate to clear out high bits
+    // note that REDUCTION_POLYNOMIAL is zero in this context
+    for i in (8..=14).rev() {
+        if ((carryless_product >> i) & 0x01) != 0 {
+            carryless_product ^= REDUCTION_POLYNOMIAL << (i - 8);
+        }
+    }
+
+    carryless_product as u8
+}
+
+/// Calculates the bitwise XOR of all bits inside a byte.
+fn parity(input: u8) -> u8 {
+    let mut accumulator = 0;
+    for i in 0..8 {
+        accumulator ^= (input >> i) & 0x01;
+    }
+    accumulator
+}
+
+/// Calculates `matrix * x + b` inside the finite field GF(2).
+fn mat_vec_multiply_affine(matrix: u64, x: u8, b: u8) -> u8 {
+    // this implementation follows the description in
+    // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_gf2p8affine_epi64_epi8
+    let mut accumulator = 0;
+
+    for bit in 0..8 {
+        accumulator |= parity(x & matrix.to_le_bytes()[bit]) << (7 - bit);
+    }
+
+    accumulator ^ b
+}
+
+/* Test data generation. */
+
+const NUM_TEST_WORDS_512: usize = 4;
+const NUM_TEST_WORDS_256: usize = NUM_TEST_WORDS_512 * 2;
+const NUM_TEST_WORDS_128: usize = NUM_TEST_WORDS_256 * 2;
+const NUM_TEST_ENTRIES: usize = NUM_TEST_WORDS_512 * 64;
+const NUM_TEST_WORDS_64: usize = NUM_TEST_WORDS_128 * 2;
+const NUM_BYTES: usize = 256;
+const NUM_BYTES_WORDS_128: usize = NUM_BYTES / 16;
+const NUM_BYTES_WORDS_256: usize = NUM_BYTES_WORDS_128 / 2;
+const NUM_BYTES_WORDS_512: usize = NUM_BYTES_WORDS_256 / 2;
+
+fn generate_affine_mul_test_data(
+    immediate: u8,
+) -> ([u64; NUM_TEST_WORDS_64], [u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES]) {
+    let mut left: [u64; NUM_TEST_WORDS_64] = [0; NUM_TEST_WORDS_64];
+    let mut right: [u8; NUM_TEST_ENTRIES] = [0; NUM_TEST_ENTRIES];
+    let mut result: [u8; NUM_TEST_ENTRIES] = [0; NUM_TEST_ENTRIES];
+
+    for i in 0..NUM_TEST_WORDS_64 {
+        left[i] = (i as u64) * 103 * 101;
+        for j in 0..8 {
+            let j64 = j as u64;
+            right[i * 8 + j] = ((left[i] + j64) % 256) as u8;
+            result[i * 8 + j] = mat_vec_multiply_affine(left[i], right[i * 8 + j], immediate);
+        }
+    }
+
+    (left, right, result)
+}
+
+fn generate_inv_tests_data() -> ([u8; NUM_BYTES], [u8; NUM_BYTES]) {
+    let mut input: [u8; NUM_BYTES] = [0; NUM_BYTES];
+    let mut result: [u8; NUM_BYTES] = [0; NUM_BYTES];
+
+    for i in 0..NUM_BYTES {
+        input[i] = (i % 256) as u8;
+        result[i] = if i == 0 { 0 } else { 1 };
+    }
+
+    (input, result)
+}
+
+const AES_S_BOX: [u8; NUM_BYTES] = [
+    0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+    0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+    0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+    0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+    0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+    0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+    0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+    0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+    0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+    0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+    0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+    0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+    0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+    0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+    0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+    0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
+];
+
+fn generate_byte_mul_test_data()
+-> ([u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES]) {
+    let mut left: [u8; NUM_TEST_ENTRIES] = [0; NUM_TEST_ENTRIES];
+    let mut right: [u8; NUM_TEST_ENTRIES] = [0; NUM_TEST_ENTRIES];
+    let mut result: [u8; NUM_TEST_ENTRIES] = [0; NUM_TEST_ENTRIES];
+
+    for i in 0..NUM_TEST_ENTRIES {
+        left[i] = (i % 256) as u8;
+        right[i] = left[i].wrapping_mul(101);
+        result[i] = mulbyte(left[i], right[i]);
+    }
+
+    (left, right, result)
+}
diff --git a/src/tools/miri/tests/pass/slices.rs b/src/tools/miri/tests/pass/slices.rs
index 459d04d6761..39e1d1cb97f 100644
--- a/src/tools/miri/tests/pass/slices.rs
+++ b/src/tools/miri/tests/pass/slices.rs
@@ -6,8 +6,7 @@
 #![feature(layout_for_ptr)]
 #![feature(strict_provenance)]
 
-use std::ptr;
-use std::slice;
+use std::{ptr, slice};
 
 fn slice_of_zst() {
     fn foo<T>(v: &[T]) -> Option<&[T]> {
diff --git a/src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs b/src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs
index 259fc72d392..72e360fe19a 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs
+++ b/src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs
@@ -2,10 +2,8 @@
 // this fails when Stacked Borrows is strictly applied even to `!Unpin` types.
 #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
 
-use std::{
-    ops::{Coroutine, CoroutineState},
-    pin::Pin,
-};
+use std::ops::{Coroutine, CoroutineState};
+use std::pin::Pin;
 
 fn firstn() -> impl Coroutine<Yield = u64, Return = ()> {
     #[coroutine]
diff --git a/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs b/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs
index 9c9db4d1b3b..1478b21d6c1 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs
+++ b/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs
@@ -3,10 +3,8 @@
 //@compile-flags: -Zmiri-permissive-provenance -Zmiri-provenance-gc=0
 
 #![feature(strict_provenance)]
-use std::{
-    alloc::{self, Layout},
-    mem::ManuallyDrop,
-};
+use std::alloc::{self, Layout};
+use std::mem::ManuallyDrop;
 
 extern "Rust" {
     fn miri_get_alloc_id(ptr: *const u8) -> u64;
diff --git a/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs b/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs
index c741e4de6d5..b9d5ca06ed0 100644
--- a/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs
+++ b/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs
@@ -3,8 +3,7 @@
 //@[uniq]compile-flags: -Zmiri-unique-is-unique
 #![feature(allocator_api)]
 
-use std::mem;
-use std::ptr;
+use std::{mem, ptr};
 
 fn main() {
     aliasing_read_only_mutable_refs();
diff --git a/src/tools/miri/tests/pass/underscore_pattern.rs b/src/tools/miri/tests/pass/underscore_pattern.rs
index f0afe558954..f59bb9f5c82 100644
--- a/src/tools/miri/tests/pass/underscore_pattern.rs
+++ b/src/tools/miri/tests/pass/underscore_pattern.rs
@@ -1,5 +1,7 @@
 // Various tests ensuring that underscore patterns really just construct the place, but don't check its contents.
 #![feature(strict_provenance)]
+#![feature(never_type)]
+
 use std::ptr;
 
 fn main() {
@@ -9,6 +11,7 @@ fn main() {
     invalid_let();
     dangling_let_type_annotation();
     invalid_let_type_annotation();
+    never();
 }
 
 fn dangling_match() {
@@ -34,6 +37,13 @@ fn invalid_match() {
             _ => {}
         }
     }
+
+    unsafe {
+        let x: Uninit<!> = Uninit { uninit: () };
+        match x.value {
+            _ => {}
+        }
+    }
 }
 
 fn dangling_let() {
@@ -41,6 +51,11 @@ fn dangling_let() {
         let ptr = ptr::without_provenance::<bool>(0x40);
         let _ = *ptr;
     }
+
+    unsafe {
+        let ptr = ptr::without_provenance::<!>(0x40);
+        let _ = *ptr;
+    }
 }
 
 fn invalid_let() {
@@ -49,6 +64,12 @@ fn invalid_let() {
         let ptr = ptr::addr_of!(val).cast::<bool>();
         let _ = *ptr;
     }
+
+    unsafe {
+        let val = 3u8;
+        let ptr = ptr::addr_of!(val).cast::<!>();
+        let _ = *ptr;
+    }
 }
 
 // Adding a type annotation used to change how MIR is generated, make sure we cover both cases.
@@ -57,6 +78,11 @@ fn dangling_let_type_annotation() {
         let ptr = ptr::without_provenance::<bool>(0x40);
         let _: bool = *ptr;
     }
+
+    unsafe {
+        let ptr = ptr::without_provenance::<!>(0x40);
+        let _: ! = *ptr;
+    }
 }
 
 fn invalid_let_type_annotation() {
@@ -65,7 +91,28 @@ fn invalid_let_type_annotation() {
         let ptr = ptr::addr_of!(val).cast::<bool>();
         let _: bool = *ptr;
     }
+
+    unsafe {
+        let val = 3u8;
+        let ptr = ptr::addr_of!(val).cast::<!>();
+        let _: ! = *ptr;
+    }
 }
 
-// FIXME: we should also test `!`, not just `bool` -- but that s currently buggy:
-// https://github.com/rust-lang/rust/issues/117288
+// Regression test from <https://github.com/rust-lang/rust/issues/117288>.
+fn never() {
+    unsafe {
+        let x = 3u8;
+        let x: *const ! = &x as *const u8 as *const _;
+        let _: ! = *x;
+    }
+
+    // Without a type annotation, make sure we don't implicitly coerce `!` to `()`
+    // when we do the noop `*x` (as that would require a `!` *value*, creating
+    // which is UB).
+    unsafe {
+        let x = 3u8;
+        let x: *const ! = &x as *const u8 as *const _;
+        let _ = *x;
+    }
+}
diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs
index 2430140eea1..9553a37c9a8 100644
--- a/src/tools/miri/tests/ui.rs
+++ b/src/tools/miri/tests/ui.rs
@@ -1,8 +1,9 @@
+use std::env;
 use std::ffi::OsString;
 use std::num::NonZero;
 use std::path::{Path, PathBuf};
+use std::process::Command;
 use std::sync::OnceLock;
-use std::{env, process::Command};
 
 use colored::*;
 use regex::bytes::Regex;
diff --git a/src/tools/miri/tests/x86_64-unknown-kernel.json b/src/tools/miri/tests/x86_64-unknown-kernel.json
new file mode 100644
index 00000000000..8135b618d0d
--- /dev/null
+++ b/src/tools/miri/tests/x86_64-unknown-kernel.json
@@ -0,0 +1,24 @@
+{
+  "llvm-target": "x86_64-unknown-none",
+  "target-endian": "little",
+  "target-pointer-width": "64",
+  "target-c-int-width": "32",
+  "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
+  "arch": "x86_64",
+  "os": "none",
+  "env": "",
+  "vendor": "unknown",
+  "linker": "rust-lld",
+  "linker-flavor": "gnu-lld",
+  "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float",
+  "dynamic-linking": false,
+  "executables": true,
+  "relocation-model": "static",
+  "code-model": "kernel",
+  "disable-redzone": true,
+  "frame-pointer": "always",
+  "exe-suffix": "",
+  "has-rpath": false,
+  "no-default-libraries": true,
+  "position-independent-executables": false
+}
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index e5f0aabbf7c..060deb18344 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -102,9 +102,9 @@ checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
 
 [[package]]
 name = "autocfg"
-version = "1.3.0"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
 
 [[package]]
 name = "bincode"
@@ -161,9 +161,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "cc"
-version = "1.1.21"
+version = "1.1.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0"
+checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
 dependencies = [
  "shlex",
 ]
@@ -376,9 +376,9 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
 
 [[package]]
 name = "flate2"
-version = "1.0.33"
+version = "1.0.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253"
+checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0"
 dependencies = [
  "crc32fast",
  "miniz_oxide",
@@ -572,9 +572,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
 [[package]]
 name = "libc"
-version = "0.2.158"
+version = "0.2.159"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
+checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
 
 [[package]]
 name = "libdbus-sys"
@@ -949,9 +949,9 @@ dependencies = [
 
 [[package]]
 name = "pkg-config"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
 
 [[package]]
 name = "polib"
@@ -1082,9 +1082,9 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.4"
+version = "0.5.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853"
+checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b"
 dependencies = [
  "bitflags 2.6.0",
 ]
@@ -1205,9 +1205,9 @@ dependencies = [
 
 [[package]]
 name = "serde_spanned"
-version = "0.6.7"
+version = "0.6.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
+checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
 dependencies = [
  "serde",
 ]
@@ -1275,9 +1275,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "syn"
-version = "2.0.77"
+version = "2.0.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
+checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1306,9 +1306,9 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.12.0"
+version = "3.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
+checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
 dependencies = [
  "cfg-if",
  "fastrand",
@@ -1346,18 +1346,18 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
 
 [[package]]
 name = "thiserror"
-version = "1.0.63"
+version = "1.0.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
+checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.63"
+version = "1.0.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
+checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1411,9 +1411,9 @@ dependencies = [
 
 [[package]]
 name = "toml_edit"
-version = "0.22.21"
+version = "0.22.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
 dependencies = [
  "indexmap",
  "serde",
@@ -1766,9 +1766,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "winnow"
-version = "0.6.18"
+version = "0.6.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
+checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
 dependencies = [
  "memchr",
 ]
diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js
index 8f6626f6296..c5874b4ee02 100644
--- a/src/tools/rustdoc-gui/tester.js
+++ b/src/tools/rustdoc-gui/tester.js
@@ -19,7 +19,6 @@ function showHelp() {
     console.log("  --debug                    : show extra information about script run");
     console.log("  --show-text                : render font in pages");
     console.log("  --no-headless              : disable headless mode");
-    console.log("  --no-sandbox               : disable sandbox mode");
     console.log("  --help                     : show this message then quit");
     console.log("  --tests-folder [PATH]      : location of the .GOML tests folder");
     console.log("  --jobs [NUMBER]            : number of threads to run tests on");
@@ -40,7 +39,6 @@ function parseOptions(args) {
         "no_headless": false,
         "jobs": -1,
         "executable_path": null,
-        "no_sandbox": false,
     };
     const correspondences = {
         "--doc-folder": "doc_folder",
@@ -49,7 +47,6 @@ function parseOptions(args) {
         "--show-text": "show_text",
         "--no-headless": "no_headless",
         "--executable-path": "executable_path",
-        "--no-sandbox": "no_sandbox",
     };
 
     for (let i = 0; i < args.length; ++i) {
@@ -80,9 +77,6 @@ function parseOptions(args) {
         } else if (arg === "--help") {
             showHelp();
             process.exit(0);
-        } else if (arg === "--no-sandbox") {
-            console.log("`--no-sandbox` is being used. Be very careful!");
-            opts[correspondences[arg]] = true;
         } else if (correspondences[arg]) {
             opts[correspondences[arg]] = true;
         } else {
@@ -203,6 +197,7 @@ async function main(argv) {
         const args = [
             "--variable", "DOC_PATH", opts["doc_folder"].split("\\").join("/"),
             "--enable-fail-on-js-error", "--allow-file-access-from-files",
+            "--no-sandbox",
         ];
         if (opts["debug"]) {
             debug = true;
@@ -211,9 +206,6 @@ async function main(argv) {
         if (opts["show_text"]) {
             args.push("--show-text");
         }
-        if (opts["no_sandbox"]) {
-            args.push("--no-sandbox");
-        }
         if (opts["no_headless"]) {
             args.push("--no-headless");
             headless = false;
@@ -262,19 +254,6 @@ async function main(argv) {
         console.log(`Running ${files.length} rustdoc-gui ...`);
     }
 
-    // We catch this "event" to display a nicer message in case of unexpected exit (because of a
-    // missing `--no-sandbox`).
-    const exitHandling = () => {
-        if (!opts["no_sandbox"]) {
-            console.log("");
-            console.log(
-                "`browser-ui-test` crashed unexpectedly. Please try again with adding `--test-args \
---no-sandbox` at the end. For example: `x.py test tests/rustdoc-gui --test-args --no-sandbox`");
-            console.log("");
-        }
-    };
-    process.on("exit", exitHandling);
-
     const originalFilesLen = files.length;
     const results = createEmptyResults();
     const status_bar = char_printer(files.length);
@@ -299,9 +278,6 @@ async function main(argv) {
     Array.prototype.push.apply(results.failed, new_results.failed);
     Array.prototype.push.apply(results.errored, new_results.errored);
 
-    // We don't need this listener anymore.
-    process.removeListener("exit", exitHandling);
-
     if (debug) {
         results.successful.sort(by_filename);
         results.successful.forEach(r => {
diff --git a/src/tools/rustfmt/src/parse/macros/asm.rs b/src/tools/rustfmt/src/parse/macros/asm.rs
index 5ee083da539..58c8d21bd7a 100644
--- a/src/tools/rustfmt/src/parse/macros/asm.rs
+++ b/src/tools/rustfmt/src/parse/macros/asm.rs
@@ -7,5 +7,5 @@ use crate::rewrite::RewriteContext;
 pub(crate) fn parse_asm(context: &RewriteContext<'_>, mac: &ast::MacCall) -> Option<AsmArgs> {
     let ts = mac.args.tokens.clone();
     let mut parser = super::build_parser(context, ts);
-    parse_asm_args(&mut parser, mac.span(), false).ok()
+    parse_asm_args(&mut parser, mac.span(), ast::AsmMacro::Asm).ok()
 }
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index 9f27a05939e..54ad56ed3f3 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -46,7 +46,7 @@ impl SilentOnIgnoredFilesEmitter {
 }
 
 impl Translate for SilentOnIgnoredFilesEmitter {
-    fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
+    fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> {
         self.emitter.fluent_bundle()
     }
 
@@ -56,7 +56,7 @@ impl Translate for SilentOnIgnoredFilesEmitter {
 }
 
 impl Emitter for SilentOnIgnoredFilesEmitter {
-    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
+    fn source_map(&self) -> Option<&SourceMap> {
         None
     }
 
@@ -344,7 +344,7 @@ mod tests {
         }
 
         impl Translate for TestEmitter {
-            fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
+            fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> {
                 None
             }
 
@@ -354,7 +354,7 @@ mod tests {
         }
 
         impl Emitter for TestEmitter {
-            fn source_map(&self) -> Option<&Lrc<SourceMap>> {
+            fn source_map(&self) -> Option<&SourceMap> {
                 None
             }
 
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 49d5b71ff2d..1ffad06457f 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -88,7 +88,10 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>,
 const EXCEPTIONS: ExceptionList = &[
     // tidy-alphabetical-start
     ("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc
+    ("arrayref", "BSD-2-Clause"),                            // rustc
+    ("blake3", "CC0-1.0 OR Apache-2.0 OR Apache-2.0 WITH LLVM-exception"),  // rustc
     ("colored", "MPL-2.0"),                                  // rustfmt
+    ("constant_time_eq", "CC0-1.0 OR MIT-0 OR Apache-2.0"),  // rustc
     ("dissimilar", "Apache-2.0"),                            // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps)
     ("fluent-langneg", "Apache-2.0"),                        // rustc (fluent translations)
     ("instant", "BSD-3-Clause"),                             // rustc_driver/tracing-subscriber/parking_lot
@@ -249,14 +252,17 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "annotate-snippets",
     "anstyle",
     "ar_archive_writer",
+    "arrayref",
     "arrayvec",
     "autocfg",
     "bitflags",
+    "blake3",
     "block-buffer",
     "byteorder", // via ruzstd in object in thorin-dwp
     "cc",
     "cfg-if",
     "cfg_aliases",
+    "constant_time_eq",
     "cpufeatures",
     "crc32fast",
     "crossbeam-channel",
diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml
index 91ff19ad9fc..49f4e59650e 100644
--- a/src/tools/wasm-component-ld/Cargo.toml
+++ b/src/tools/wasm-component-ld/Cargo.toml
@@ -10,4 +10,4 @@ name = "wasm-component-ld"
 path = "src/main.rs"
 
 [dependencies]
-wasm-component-ld = "0.5.4"
+wasm-component-ld = "0.5.9"
diff --git a/tests/assembly/aarch64-naked-fn-no-bti-prolog.rs b/tests/assembly/aarch64-naked-fn-no-bti-prolog.rs
index 8ee6f6792e9..46e627eaa00 100644
--- a/tests/assembly/aarch64-naked-fn-no-bti-prolog.rs
+++ b/tests/assembly/aarch64-naked-fn-no-bti-prolog.rs
@@ -5,7 +5,7 @@
 
 #![crate_type = "lib"]
 #![feature(naked_functions)]
-use std::arch::asm;
+use std::arch::naked_asm;
 
 // The problem at hand: Rust has adopted a fairly strict meaning for "naked functions",
 // meaning "no prologue whatsoever, no, really, not one instruction."
@@ -17,5 +17,5 @@ use std::arch::asm;
 pub unsafe extern "C" fn _hlt() -> ! {
     // CHECK-NOT: hint #34
     // CHECK: hlt #0x1
-    asm!("hlt #1", options(noreturn))
+    naked_asm!("hlt #1")
 }
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index 7d1d05e2d55..f26d06a0ecb 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -375,6 +375,15 @@
 //@ revisions: riscv32_wrs_vxworks
 //@ [riscv32_wrs_vxworks] compile-flags: --target riscv32-wrs-vxworks
 //@ [riscv32_wrs_vxworks] needs-llvm-components: riscv
+//@ revisions: riscv32e_unknown_none_elf
+//@ [riscv32e_unknown_none_elf] compile-flags: --target riscv32e-unknown-none-elf
+//@ [riscv32e_unknown_none_elf] needs-llvm-components: riscv
+//@ revisions: riscv32em_unknown_none_elf
+//@ [riscv32em_unknown_none_elf] compile-flags: --target riscv32em-unknown-none-elf
+//@ [riscv32em_unknown_none_elf] needs-llvm-components: riscv
+//@ revisions: riscv32emc_unknown_none_elf
+//@ [riscv32emc_unknown_none_elf] compile-flags: --target riscv32emc-unknown-none-elf
+//@ [riscv32emc_unknown_none_elf] needs-llvm-components: riscv
 //@ revisions: riscv32gc_unknown_linux_gnu
 //@ [riscv32gc_unknown_linux_gnu] compile-flags: --target riscv32gc-unknown-linux-gnu
 //@ [riscv32gc_unknown_linux_gnu] needs-llvm-components: riscv
@@ -594,6 +603,9 @@
 //@ revisions: x86_64_unknown_redox
 //@ [x86_64_unknown_redox] compile-flags: --target x86_64-unknown-redox
 //@ [x86_64_unknown_redox] needs-llvm-components: x86
+//@ revisions: x86_64_unknown_trusty
+//@ [x86_64_unknown_trusty] compile-flags: --target x86_64-unknown-trusty
+//@ [x86_64_unknown_trusty] needs-llvm-components: x86
 //@ revisions: x86_64_wrs_vxworks
 //@ [x86_64_wrs_vxworks] compile-flags: --target x86_64-wrs-vxworks
 //@ [x86_64_wrs_vxworks] needs-llvm-components: x86
diff --git a/tests/assembly/x86_64-naked-fn-no-cet-prolog.rs b/tests/assembly/x86_64-naked-fn-no-cet-prolog.rs
index a5683874182..54e1d93c68b 100644
--- a/tests/assembly/x86_64-naked-fn-no-cet-prolog.rs
+++ b/tests/assembly/x86_64-naked-fn-no-cet-prolog.rs
@@ -5,7 +5,7 @@
 
 #![crate_type = "lib"]
 #![feature(naked_functions)]
-use std::arch::asm;
+use std::arch::naked_asm;
 
 // The problem at hand: Rust has adopted a fairly strict meaning for "naked functions",
 // meaning "no prologue whatsoever, no, really, not one instruction."
@@ -17,7 +17,7 @@ use std::arch::asm;
 pub unsafe extern "sysv64" fn will_halt() -> ! {
     // CHECK-NOT: endbr{{32|64}}
     // CHECK: hlt
-    asm!("hlt", options(noreturn))
+    naked_asm!("hlt")
 }
 
 // what about aarch64?
diff --git a/tests/codegen/asm-s390x-clobbers.rs b/tests/codegen/asm-s390x-clobbers.rs
new file mode 100644
index 00000000000..45f72206bdf
--- /dev/null
+++ b/tests/codegen/asm-s390x-clobbers.rs
@@ -0,0 +1,50 @@
+//@ revisions: s390x
+//@[s390x] compile-flags: --target s390x-unknown-linux-gnu
+//@[s390x] needs-llvm-components: systemz
+
+#![crate_type = "rlib"]
+#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+    () => {};
+}
+
+// CHECK-LABEL: @cc_clobber
+// CHECK: call void asm sideeffect "", "~{cc}"()
+#[no_mangle]
+pub unsafe fn cc_clobber() {
+    asm!("", options(nostack, nomem));
+}
+
+// CHECK-LABEL: @no_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn no_clobber() {
+    asm!("", options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @a2_clobber
+// CHECK: call void asm sideeffect "", "~{a2}"()
+#[no_mangle]
+pub unsafe fn a2_clobber() {
+    asm!("", out("a2") _, options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @v0_clobber
+// CHECK: call void asm sideeffect "", "~{v0}"()
+#[no_mangle]
+pub unsafe fn v0_clobber() {
+    asm!("", out("v0") _, options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @clobber_abi
+// CHECK: asm sideeffect "", "={r0},={r1},={r2},={r3},={r4},={r5},={r14},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31},~{a2},~{a3},~{a4},~{a5},~{a6},~{a7},~{a8},~{a9},~{a10},~{a11},~{a12},~{a13},~{a14},~{a15}"()
+#[no_mangle]
+pub unsafe fn clobber_abi() {
+    asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs b/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs
new file mode 100644
index 00000000000..9cf4f210e52
--- /dev/null
+++ b/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs
@@ -0,0 +1,13 @@
+//@ compile-flags: -O
+//@ ignore-debug
+#![crate_type = "lib"]
+
+use std::collections::binary_heap::PeekMut;
+
+// CHECK-LABEL: @peek_mut_pop
+#[no_mangle]
+pub fn peek_mut_pop(peek_mut: PeekMut<u32>) -> u32 {
+    // CHECK-NOT: panic
+    // CHECK-NOT: unwrap_failed
+    PeekMut::pop(peek_mut)
+}
diff --git a/tests/codegen/cffi/c-variadic-naked.rs b/tests/codegen/cffi/c-variadic-naked.rs
index 807873ea368..24b69c5f59e 100644
--- a/tests/codegen/cffi/c-variadic-naked.rs
+++ b/tests/codegen/cffi/c-variadic-naked.rs
@@ -12,8 +12,7 @@
 pub unsafe extern "C" fn c_variadic(_: usize, _: ...) {
     // CHECK-NOT: va_start
     // CHECK-NOT: alloca
-    core::arch::asm! {
+    core::arch::naked_asm! {
         "ret",
-        options(noreturn),
     }
 }
diff --git a/tests/codegen/default-hidden-visibility.rs b/tests/codegen/default-visibility.rs
index 2bea8f62a40..884d386ec20 100644
--- a/tests/codegen/default-hidden-visibility.rs
+++ b/tests/codegen/default-visibility.rs
@@ -1,11 +1,12 @@
-// Verifies that `Session::default_hidden_visibility` is affected when using the related cmdline
-// flag.  This is a regression test for https://github.com/rust-lang/compiler-team/issues/656.  See
+// Verifies that `Session::default_visibility` is affected when using the related cmdline
+// flag.  This is a regression test for https://github.com/rust-lang/compiler-team/issues/782.  See
 // also https://github.com/rust-lang/rust/issues/73295 and
 // https://github.com/rust-lang/rust/issues/37530.
 
-//@ revisions:DEFAULT YES NO
-//@[YES] compile-flags: -Zdefault-hidden-visibility=yes
-//@[NO]  compile-flags: -Zdefault-hidden-visibility=no
+//@ revisions:DEFAULT HIDDEN PROTECTED INTERPOSABLE
+//@[HIDDEN] compile-flags: -Zdefault-visibility=hidden
+//@[PROTECTED] compile-flags: -Zdefault-visibility=protected
+//@[INTERPOSABLE] compile-flags: -Zdefault-visibility=interposable
 
 // The test scenario is specifically about visibility of symbols exported out of dynamically linked
 // libraries.
@@ -26,6 +27,7 @@ pub static tested_symbol: [u8; 6] = *b"foobar";
 //
 //@     only-x86_64-unknown-linux-gnu
 
-// DEFAULT: @{{.*}}default_hidden_visibility{{.*}}tested_symbol{{.*}} = constant
-// YES:     @{{.*}}default_hidden_visibility{{.*}}tested_symbol{{.*}} = hidden constant
-// NO:      @{{.*}}default_hidden_visibility{{.*}}tested_symbol{{.*}} = constant
+// HIDDEN:       @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = hidden constant
+// PROTECTED:    @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = protected constant
+// INTERPOSABLE: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant
+// DEFAULT:      @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant
diff --git a/tests/codegen/issues/issue-123712-str-to-lower-autovectorization.rs b/tests/codegen/issues/issue-123712-str-to-lower-autovectorization.rs
new file mode 100644
index 00000000000..11ee10e8cc3
--- /dev/null
+++ b/tests/codegen/issues/issue-123712-str-to-lower-autovectorization.rs
@@ -0,0 +1,23 @@
+//@ only-x86_64
+//@ compile-flags: -C opt-level=3
+#![crate_type = "lib"]
+#![no_std]
+#![feature(str_internals)]
+
+extern crate alloc;
+
+/// Ensure that the ascii-prefix loop for `str::to_lowercase` and `str::to_uppercase` uses vector
+/// instructions.
+///
+/// The llvm ir should be the same for all targets that support some form of simd. Only targets
+/// without any simd instructions would see scalarized ir.
+/// Unfortunately, there is no `only-simd` directive to only run this test on only such platforms,
+/// and using test revisions would still require the core libraries for all platforms.
+// CHECK-LABEL: @lower_while_ascii
+// CHECK: [[A:%[0-9]]] = load <16 x i8>
+// CHECK-NEXT: [[B:%[0-9]]] = icmp slt <16 x i8> [[A]], zeroinitializer
+// CHECK-NEXT: [[C:%[0-9]]] = bitcast <16 x i1> [[B]] to i16
+#[no_mangle]
+pub fn lower_while_ascii(s: &str) -> (alloc::string::String, &str) {
+    alloc::str::convert_while_ascii(s, u8::to_ascii_lowercase)
+}
diff --git a/tests/codegen/naked-asan.rs b/tests/codegen/naked-asan.rs
index ac36018eed3..bcaa60baeff 100644
--- a/tests/codegen/naked-asan.rs
+++ b/tests/codegen/naked-asan.rs
@@ -14,7 +14,7 @@
 #[no_mangle]
 pub extern "x86-interrupt" fn page_fault_handler(_: u64, _: u64) {
     unsafe {
-        core::arch::asm!("ud2", options(noreturn));
+        core::arch::naked_asm!("ud2");
     }
 }
 
diff --git a/tests/codegen/naked-fn/aligned.rs b/tests/codegen/naked-fn/aligned.rs
index d5faac44836..3bbd67981e5 100644
--- a/tests/codegen/naked-fn/aligned.rs
+++ b/tests/codegen/naked-fn/aligned.rs
@@ -4,7 +4,7 @@
 
 #![crate_type = "lib"]
 #![feature(naked_functions, fn_align)]
-use std::arch::asm;
+use std::arch::naked_asm;
 
 // CHECK: Function Attrs: naked
 // CHECK-NEXT: define{{.*}}void @naked_empty()
@@ -16,5 +16,5 @@ pub unsafe extern "C" fn naked_empty() {
     // CHECK-NEXT: start:
     // CHECK-NEXT: call void asm
     // CHECK-NEXT: unreachable
-    asm!("ret", options(noreturn));
+    naked_asm!("ret");
 }
diff --git a/tests/codegen/naked-fn/naked-functions.rs b/tests/codegen/naked-fn/naked-functions.rs
index 307745a921c..3f7447af599 100644
--- a/tests/codegen/naked-fn/naked-functions.rs
+++ b/tests/codegen/naked-fn/naked-functions.rs
@@ -4,7 +4,7 @@
 
 #![crate_type = "lib"]
 #![feature(naked_functions)]
-use std::arch::asm;
+use std::arch::naked_asm;
 
 // CHECK: Function Attrs: naked
 // CHECK-NEXT: define{{.*}}void @naked_empty()
@@ -14,7 +14,7 @@ pub unsafe extern "C" fn naked_empty() {
     // CHECK-NEXT: {{.+}}:
     // CHECK-NEXT: call void asm
     // CHECK-NEXT: unreachable
-    asm!("ret", options(noreturn));
+    naked_asm!("ret");
 }
 
 // CHECK: Function Attrs: naked
@@ -25,5 +25,5 @@ pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize
     // CHECK-NEXT: {{.+}}:
     // CHECK-NEXT: call void asm
     // CHECK-NEXT: unreachable
-    asm!("lea rax, [rdi + rsi]", "ret", options(noreturn));
+    naked_asm!("lea rax, [rdi + rsi]", "ret");
 }
diff --git a/tests/codegen/naked-fn/naked-nocoverage.rs b/tests/codegen/naked-fn/naked-nocoverage.rs
index d73c5b7fd26..f63661bcd3a 100644
--- a/tests/codegen/naked-fn/naked-nocoverage.rs
+++ b/tests/codegen/naked-fn/naked-nocoverage.rs
@@ -6,7 +6,7 @@
 //@ compile-flags: -Cinstrument-coverage
 #![crate_type = "lib"]
 #![feature(naked_functions)]
-use std::arch::asm;
+use std::arch::naked_asm;
 
 #[naked]
 #[no_mangle]
@@ -15,5 +15,5 @@ pub unsafe extern "C" fn f() {
     // CHECK-NEXT:  start:
     // CHECK-NEXT:    call void asm
     // CHECK-NEXT:    unreachable
-    asm!("", options(noreturn));
+    naked_asm!("");
 }
diff --git a/tests/codegen/naked-fn/naked-noinline.rs b/tests/codegen/naked-fn/naked-noinline.rs
index c1e8f368249..6ea36d96783 100644
--- a/tests/codegen/naked-fn/naked-noinline.rs
+++ b/tests/codegen/naked-fn/naked-noinline.rs
@@ -5,7 +5,7 @@
 #![crate_type = "lib"]
 #![feature(naked_functions)]
 
-use std::arch::asm;
+use std::arch::naked_asm;
 
 #[naked]
 #[no_mangle]
@@ -15,7 +15,7 @@ pub unsafe extern "C" fn f() {
     // CHECK:       define {{(dso_local )?}}void @f() unnamed_addr [[ATTR:#[0-9]+]]
     // CHECK-NEXT:  start:
     // CHECK-NEXT:    call void asm
-    asm!("", options(noreturn));
+    naked_asm!("");
 }
 
 #[no_mangle]
diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map
index eb5f94d1080..fb4a137d4c8 100644
--- a/tests/coverage/closure_macro.cov-map
+++ b/tests/coverage/closure_macro.cov-map
@@ -23,19 +23,19 @@ Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
 Function name: closure_macro::main::{closure#0}
-Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 00, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 00, 00, 17, 00, 1e, 07, 02, 09, 00, 0a]
+Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 0d, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 0d, 00, 17, 00, 1e, 07, 02, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 3
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add)
-- expression 2 operands: lhs = Counter(2), rhs = Zero
+- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
 Number of file 0 mappings: 5
 - Code(Counter(0)) at (prev + 16, 28) to (start + 3, 33)
 - Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39)
 - Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22)
     = (c0 - c1)
-- Code(Zero) at (prev + 0, 23) to (start + 0, 30)
+- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 30)
 - Code(Expression(1, Add)) at (prev + 2, 9) to (start + 0, 10)
-    = (c1 + (c2 + Zero))
+    = (c1 + (c2 + c3))
 
diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map
index 4d0597f58bf..091e87909f9 100644
--- a/tests/coverage/closure_macro_async.cov-map
+++ b/tests/coverage/closure_macro_async.cov-map
@@ -31,19 +31,19 @@ Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
 Function name: closure_macro_async::test::{closure#0}::{closure#0}
-Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 00, 05, 01, 15, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 00, 00, 17, 00, 1e, 07, 02, 09, 00, 0a]
+Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 0d, 05, 01, 15, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 0d, 00, 17, 00, 1e, 07, 02, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 3
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add)
-- expression 2 operands: lhs = Counter(2), rhs = Zero
+- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
 Number of file 0 mappings: 5
 - Code(Counter(0)) at (prev + 21, 28) to (start + 3, 33)
 - Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39)
 - Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22)
     = (c0 - c1)
-- Code(Zero) at (prev + 0, 23) to (start + 0, 30)
+- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 30)
 - Code(Expression(1, Add)) at (prev + 2, 9) to (start + 0, 10)
-    = (c1 + (c2 + Zero))
+    = (c1 + (c2 + c3))
 
diff --git a/tests/crashes/119716-2.rs b/tests/crashes/119716-2.rs
deleted file mode 100644
index 47bffb5c1de..00000000000
--- a/tests/crashes/119716-2.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-//@ known-bug: #119716
-#![feature(non_lifetime_binders)]
-trait Trait<T> {}
-fn f() -> impl for<T> Trait<impl Trait<T>> {}
diff --git a/tests/crashes/119716.rs b/tests/crashes/119716.rs
deleted file mode 100644
index d7cba0f51c4..00000000000
--- a/tests/crashes/119716.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-//@ known-bug: #119716
-#![feature(non_lifetime_binders)]
-trait v0<v1> {}
-fn kind  :(v3main impl for<v4> v0<'_, v2 = impl v0<v4> + '_>) {}
diff --git a/tests/crashes/121422.rs b/tests/crashes/121422.rs
deleted file mode 100644
index 5d7ef6e8ce9..00000000000
--- a/tests/crashes/121422.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ known-bug: #121422
-#![feature(non_lifetime_binders)]
-
-trait Trait<T: ?Sized> {}
-
-fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> {
-    16
-}
diff --git a/tests/crashes/124375.rs b/tests/crashes/124375.rs
index 7165655178d..1d877caeb8b 100644
--- a/tests/crashes/124375.rs
+++ b/tests/crashes/124375.rs
@@ -3,9 +3,9 @@
 //@ only-x86_64
 #![crate_type = "lib"]
 #![feature(naked_functions)]
-use std::arch::asm;
+use std::arch::naked_asm;
 
 #[naked]
 pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
-    asm!("lea rax, [rdi + rsi]", "ret", options(noreturn));
+    naked_asm!("lea rax, [rdi + rsi]", "ret");
 }
diff --git a/tests/crashes/125843.rs b/tests/crashes/125843.rs
deleted file mode 100644
index 8b9a3913c7e..00000000000
--- a/tests/crashes/125843.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-//@ known-bug: rust-lang/rust#125843
-#![feature(non_lifetime_binders)]
-trait v0<> {}
-fn kind  :(v3main impl for<v4> v0<'_, v2 = impl v0<v4> + '_>) {}
diff --git a/tests/crashes/125881.rs b/tests/crashes/125881.rs
deleted file mode 100644
index a38f1891b61..00000000000
--- a/tests/crashes/125881.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ known-bug: rust-lang/rust#125881
-#![crate_type = "lib"]
-#![feature(transmutability)]
-#![feature(unboxed_closures,effects)]
-
-const fn test() -> impl std::mem::TransmuteFrom() {
-    || {}
-}
diff --git a/tests/crashes/126377.rs b/tests/crashes/126377.rs
deleted file mode 100644
index f6727bcc0a4..00000000000
--- a/tests/crashes/126377.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-//@ known-bug: rust-lang/rust#126377
-
-#![feature(effects)]
-#![feature(generic_const_exprs)]
-
-mod assert {
-    use std::mem::{Assume, TransmuteFrom};
-
-    pub fn is_transmutable<
-        Src,
-        Dst,
-        const ASSUME_ALIGNMENT: bool,
-        const ASSUME_LIFETIMES: bool,
-        const ASSUME_SAFETY: bool,
-        const ASSUME_VALIDITY: bool,
-    >()
-    where
-        Dst: TransmuteFrom<
-            Src,
-            {  }
-        >,
-    {}
-}
-
-const fn from_options() -> Assume {
-    #[repr(C)] struct Src;
-    #[repr(C)] struct Dst;
-    assert::is_transmutable::<Src, Dst, {0u8}, false, false, false>();
-}
diff --git a/tests/crashes/127880.rs b/tests/crashes/127880.rs
deleted file mode 100644
index 6c625eac691..00000000000
--- a/tests/crashes/127880.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-//@ known-bug: #127880
-//@ compile-flags: -Cinstrument-coverage
-
-#[coverage]
-fn main() {}
diff --git a/tests/crashes/128327.rs b/tests/crashes/128327.rs
deleted file mode 100644
index a63f758c317..00000000000
--- a/tests/crashes/128327.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-//@ known-bug: rust-lang/rust#128327
-
-use std::ops::Deref;
-struct Apple((Apple, <&'static [f64] as Deref>::Target(Banana ? Citron)));
-fn main(){}
diff --git a/tests/crashes/129099.rs b/tests/crashes/129099.rs
deleted file mode 100644
index 9aaab756b5b..00000000000
--- a/tests/crashes/129099.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//@ known-bug: rust-lang/rust#129099
-
-#![feature(type_alias_impl_trait)]
-
-fn dyn_hoops<T: Sized>() -> dyn for<'a> Iterator<Item = impl Captures<'a>> {
-    loop {}
-}
-
-pub fn main() {
-    type Opaque = impl Sized;
-    fn define() -> Opaque {
-        let x: Opaque = dyn_hoops::<()>(0);
-        x
-    }
-}
diff --git a/tests/crashes/130413.rs b/tests/crashes/130413.rs
deleted file mode 100644
index 08435ac6450..00000000000
--- a/tests/crashes/130413.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//@ known-bug: #130413
-
-#![feature(transmutability)]
-trait Aaa {
-    type Y;
-}
-
-trait Bbb {
-    type B: std::mem::TransmuteFrom<()>;
-}
-
-impl<T> Bbb for T
-where
-    T: Aaa,
-{
-    type B = T::Y;
-}
diff --git a/tests/crashes/130521.rs b/tests/crashes/130521.rs
new file mode 100644
index 00000000000..2d30b658024
--- /dev/null
+++ b/tests/crashes/130521.rs
@@ -0,0 +1,13 @@
+//@ known-bug: #130521
+
+#![feature(object_safe_for_dispatch)]
+struct Vtable(dyn Cap);
+
+trait Cap<'a> {}
+
+union Transmute {
+    t: u64,
+    u: &'static Vtable,
+}
+
+const G: &Copy = unsafe { Transmute { t: 1 }.u };
diff --git a/tests/crashes/130524.rs b/tests/crashes/130524.rs
new file mode 100644
index 00000000000..14d2269de59
--- /dev/null
+++ b/tests/crashes/130524.rs
@@ -0,0 +1,22 @@
+//@ known-bug: #130524
+
+trait Transform {
+    type Output<'a>;
+}
+
+trait Propagate<Input> {}
+
+fn new_node<T: Transform>(_c: Vec<Box<dyn for<'a> Propagate<<T as Transform>::Output<'a>>>>) -> T {
+    todo!()
+}
+
+impl<Input, T> Propagate<Input> for T {}
+struct Noop;
+
+impl Transform for Noop {
+    type Output<'a> = ();
+}
+
+fn main() {
+    let _node: Noop = new_node(vec![Box::new(Noop)]);
+}
diff --git a/tests/crashes/130627.rs b/tests/crashes/130627.rs
new file mode 100644
index 00000000000..59d3606592b
--- /dev/null
+++ b/tests/crashes/130627.rs
@@ -0,0 +1,20 @@
+//@ known-bug: #130627
+
+#![feature(trait_alias)]
+
+trait Test {}
+
+#[diagnostic::on_unimplemented(
+    message="message",
+    label="label",
+    note="note"
+)]
+trait Alias = Test;
+
+// Use trait alias as bound on type parameter.
+fn foo<T: Alias>(v: &T) {
+}
+
+pub fn main() {
+    foo(&1);
+}
diff --git a/tests/crashes/130687.rs b/tests/crashes/130687.rs
new file mode 100644
index 00000000000..361be0905df
--- /dev/null
+++ b/tests/crashes/130687.rs
@@ -0,0 +1,4 @@
+//@ known-bug: #130687
+//@ only-x86_64
+pub struct Data([u8; usize::MAX >> 16]);
+const _: &'static Data = &Data([0; usize::MAX >> 16]);
diff --git a/tests/crashes/130779.rs b/tests/crashes/130779.rs
new file mode 100644
index 00000000000..f0fd81fff44
--- /dev/null
+++ b/tests/crashes/130779.rs
@@ -0,0 +1,11 @@
+//@ known-bug: #130779
+#![feature(never_patterns)]
+
+enum E { A }
+
+fn main() {
+    match E::A {
+        ! |
+        if true => {}
+    }
+}
diff --git a/tests/crashes/130921.rs b/tests/crashes/130921.rs
new file mode 100644
index 00000000000..b7cb1303937
--- /dev/null
+++ b/tests/crashes/130921.rs
@@ -0,0 +1,10 @@
+//@ known-bug: #130921
+//@ compile-flags: -Zvalidate-mir -Copt-level=0 --crate-type lib
+
+pub fn hello() -> [impl Sized; 2] {
+    if false {
+        let x = hello();
+        let _: &[i32] = &x;
+    }
+    todo!()
+}
diff --git a/tests/crashes/130970.rs b/tests/crashes/130970.rs
new file mode 100644
index 00000000000..e1f59c155a5
--- /dev/null
+++ b/tests/crashes/130970.rs
@@ -0,0 +1,9 @@
+//@ known-bug: #130970
+//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir
+
+fn main() {
+    extern "C" {
+        static symbol: [usize];
+    }
+    println!("{}", symbol[0]);
+}
diff --git a/tests/incremental/hashes/function_interfaces.rs b/tests/incremental/hashes/function_interfaces.rs
index ab4d578458d..016a1813bab 100644
--- a/tests/incremental/hashes/function_interfaces.rs
+++ b/tests/incremental/hashes/function_interfaces.rs
@@ -318,9 +318,9 @@ pub fn change_return_impl_trait() -> impl Clone {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg = "cfail2")]
+#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes")]
 #[rustc_clean(cfg = "cfail3")]
-#[rustc_clean(cfg = "cfail5", except = "typeck")]
+#[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes, typeck")]
 #[rustc_clean(cfg = "cfail6")]
 pub fn change_return_impl_trait() -> impl  Copy {
     0u32
diff --git a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff
new file mode 100644
index 00000000000..047441e6099
--- /dev/null
+++ b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff
@@ -0,0 +1,46 @@
+- // MIR for `bitwise_not` before JumpThreading
++ // MIR for `bitwise_not` after JumpThreading
+  
+  fn bitwise_not() -> i32 {
+      let mut _0: i32;
+      let mut _1: i32;
+      let mut _2: bool;
+      let mut _3: i32;
+      let mut _4: i32;
+      scope 1 {
+          debug a => _1;
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = const 0_i32;
+          _1 = const 1_i32;
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = copy _1;
+          _3 = Not(move _4);
+          StorageDead(_4);
+          _2 = Eq(move _3, const 0_i32);
+          switchInt(move _2) -> [0: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          StorageDead(_3);
+          _0 = const 1_i32;
+          goto -> bb3;
+      }
+  
+      bb2: {
+          StorageDead(_3);
+          _0 = const 0_i32;
+          goto -> bb3;
+      }
+  
+      bb3: {
+          StorageDead(_2);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff
new file mode 100644
index 00000000000..047441e6099
--- /dev/null
+++ b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff
@@ -0,0 +1,46 @@
+- // MIR for `bitwise_not` before JumpThreading
++ // MIR for `bitwise_not` after JumpThreading
+  
+  fn bitwise_not() -> i32 {
+      let mut _0: i32;
+      let mut _1: i32;
+      let mut _2: bool;
+      let mut _3: i32;
+      let mut _4: i32;
+      scope 1 {
+          debug a => _1;
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = const 0_i32;
+          _1 = const 1_i32;
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = copy _1;
+          _3 = Not(move _4);
+          StorageDead(_4);
+          _2 = Eq(move _3, const 0_i32);
+          switchInt(move _2) -> [0: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          StorageDead(_3);
+          _0 = const 1_i32;
+          goto -> bb3;
+      }
+  
+      bb2: {
+          StorageDead(_3);
+          _0 = const 0_i32;
+          goto -> bb3;
+      }
+  
+      bb3: {
+          StorageDead(_2);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs
index 9487a4e7e5f..743ee8e728b 100644
--- a/tests/mir-opt/jump_threading.rs
+++ b/tests/mir-opt/jump_threading.rs
@@ -2,7 +2,6 @@
 //@ compile-flags: -Zmir-enable-passes=+Inline
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
-#![feature(control_flow_enum)]
 #![feature(try_trait_v2)]
 #![feature(custom_mir, core_intrinsics, rustc_attrs)]
 
@@ -531,6 +530,16 @@ fn floats() -> u32 {
     if x == 0.0 { 0 } else { 1 }
 }
 
+pub fn bitwise_not() -> i32 {
+    // CHECK-LABEL: fn bitwise_not(
+    // CHECK: switchInt(
+
+    // Test for #131195, which was optimizing `!a == b` into `a != b`.
+    let mut a: i32 = 0;
+    a = 1;
+    if !a == 0 { 1 } else { 0 }
+}
+
 fn main() {
     // CHECK-LABEL: fn main(
     too_complex(Ok(0));
@@ -562,3 +571,4 @@ fn main() {
 // EMIT_MIR jump_threading.assume.JumpThreading.diff
 // EMIT_MIR jump_threading.aggregate_copy.JumpThreading.diff
 // EMIT_MIR jump_threading.floats.JumpThreading.diff
+// EMIT_MIR jump_threading.bitwise_not.JumpThreading.diff
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 0ad7f5910a0..4d964b0afb7 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,66 +5,61 @@ 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 _6: usize;
-        scope 2 (inlined Vec::<u8>::as_ptr) {
+        scope 2 (inlined Vec::<u8>::as_slice) {
             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: &alloc::raw_vec::RawVecInner;
-                scope 4 (inlined alloc::raw_vec::RawVecInner::ptr::<u8>) {
-                    debug self => _3;
-                    scope 5 (inlined alloc::raw_vec::RawVecInner::non_null::<u8>) {
+            let mut _6: usize;
+            scope 3 (inlined Vec::<u8>::as_ptr) {
+                debug self => _1;
+                let mut _2: &alloc::raw_vec::RawVec<u8>;
+                scope 4 (inlined alloc::raw_vec::RawVec::<u8>::ptr) {
+                    debug self => _2;
+                    let mut _3: &alloc::raw_vec::RawVecInner;
+                    scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::<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) {
+                        scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::<u8>) {
+                            debug self => _3;
+                            let mut _4: std::ptr::NonNull<u8>;
+                            scope 7 (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 8 (inlined NonNull::<u8>::cast::<u8>) {
                                     debug self => _4;
-                                    let mut _5: *const u8;
+                                    scope 9 (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>) => _4;
-                            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>) => _4;
-                                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>) => _4;
-                                    debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
-                                }
+                            scope 10 (inlined Unique::<u8>::as_non_null_ptr) {
+                                debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4;
+                                debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
                             }
                         }
+                        scope 11 (inlined NonNull::<u8>::as_ptr) {
+                            debug self => _4;
+                        }
                     }
-                    scope 12 (inlined NonNull::<u8>::as_ptr) {
-                        debug self => _4;
-                    }
-                }
-            }
-        }
-        scope 13 (inlined std::slice::from_raw_parts::<'_, u8>) {
-            debug data => _5;
-            debug len => _6;
-            let _7: *const [u8];
-            scope 14 (inlined core::ub_checks::check_language_ub) {
-                scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
                 }
             }
-            scope 16 (inlined std::mem::size_of::<u8>) {
-            }
-            scope 17 (inlined align_of::<u8>) {
-            }
-            scope 18 (inlined slice_from_raw_parts::<u8>) {
+            scope 12 (inlined std::slice::from_raw_parts::<'_, u8>) {
                 debug data => _5;
                 debug len => _6;
-                scope 19 (inlined std::ptr::from_raw_parts::<[u8], u8>) {
-                    debug data_pointer => _5;
-                    debug metadata => _6;
+                let _7: *const [u8];
+                scope 13 (inlined core::ub_checks::check_language_ub) {
+                    scope 14 (inlined core::ub_checks::check_language_ub::runtime) {
+                    }
+                }
+                scope 15 (inlined std::mem::size_of::<u8>) {
+                }
+                scope 16 (inlined align_of::<u8>) {
+                }
+                scope 17 (inlined slice_from_raw_parts::<u8>) {
+                    debug data => _5;
+                    debug len => _6;
+                    scope 18 (inlined std::ptr::from_raw_parts::<[u8], u8>) {
+                        debug data_pointer => _5;
+                        debug metadata => _6;
+                    }
                 }
             }
         }
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 0ad7f5910a0..4d964b0afb7 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,66 +5,61 @@ 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 _6: usize;
-        scope 2 (inlined Vec::<u8>::as_ptr) {
+        scope 2 (inlined Vec::<u8>::as_slice) {
             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: &alloc::raw_vec::RawVecInner;
-                scope 4 (inlined alloc::raw_vec::RawVecInner::ptr::<u8>) {
-                    debug self => _3;
-                    scope 5 (inlined alloc::raw_vec::RawVecInner::non_null::<u8>) {
+            let mut _6: usize;
+            scope 3 (inlined Vec::<u8>::as_ptr) {
+                debug self => _1;
+                let mut _2: &alloc::raw_vec::RawVec<u8>;
+                scope 4 (inlined alloc::raw_vec::RawVec::<u8>::ptr) {
+                    debug self => _2;
+                    let mut _3: &alloc::raw_vec::RawVecInner;
+                    scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::<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) {
+                        scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::<u8>) {
+                            debug self => _3;
+                            let mut _4: std::ptr::NonNull<u8>;
+                            scope 7 (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 8 (inlined NonNull::<u8>::cast::<u8>) {
                                     debug self => _4;
-                                    let mut _5: *const u8;
+                                    scope 9 (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>) => _4;
-                            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>) => _4;
-                                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>) => _4;
-                                    debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
-                                }
+                            scope 10 (inlined Unique::<u8>::as_non_null_ptr) {
+                                debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _4;
+                                debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
                             }
                         }
+                        scope 11 (inlined NonNull::<u8>::as_ptr) {
+                            debug self => _4;
+                        }
                     }
-                    scope 12 (inlined NonNull::<u8>::as_ptr) {
-                        debug self => _4;
-                    }
-                }
-            }
-        }
-        scope 13 (inlined std::slice::from_raw_parts::<'_, u8>) {
-            debug data => _5;
-            debug len => _6;
-            let _7: *const [u8];
-            scope 14 (inlined core::ub_checks::check_language_ub) {
-                scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
                 }
             }
-            scope 16 (inlined std::mem::size_of::<u8>) {
-            }
-            scope 17 (inlined align_of::<u8>) {
-            }
-            scope 18 (inlined slice_from_raw_parts::<u8>) {
+            scope 12 (inlined std::slice::from_raw_parts::<'_, u8>) {
                 debug data => _5;
                 debug len => _6;
-                scope 19 (inlined std::ptr::from_raw_parts::<[u8], u8>) {
-                    debug data_pointer => _5;
-                    debug metadata => _6;
+                let _7: *const [u8];
+                scope 13 (inlined core::ub_checks::check_language_ub) {
+                    scope 14 (inlined core::ub_checks::check_language_ub::runtime) {
+                    }
+                }
+                scope 15 (inlined std::mem::size_of::<u8>) {
+                }
+                scope 16 (inlined align_of::<u8>) {
+                }
+                scope 17 (inlined slice_from_raw_parts::<u8>) {
+                    debug data => _5;
+                    debug len => _6;
+                    scope 18 (inlined std::ptr::from_raw_parts::<[u8], u8>) {
+                        debug data_pointer => _5;
+                        debug metadata => _6;
+                    }
                 }
             }
         }
diff --git a/tests/mir-opt/separate_const_switch.rs b/tests/mir-opt/separate_const_switch.rs
index 5e8371b3e49..05835942980 100644
--- a/tests/mir-opt/separate_const_switch.rs
+++ b/tests/mir-opt/separate_const_switch.rs
@@ -1,5 +1,4 @@
 // skip-filecheck
-#![feature(control_flow_enum)]
 #![feature(try_trait_v2)]
 
 //@ compile-flags: -Zunsound-mir-opts
diff --git a/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir
index 240f409817d..02e1f4be15e 100644
--- a/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir
+++ b/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir
@@ -3,9 +3,8 @@
 fn process_never(_1: *const !) -> () {
     debug input => _1;
     let mut _0: ();
-    let _2: &!;
     scope 1 {
-        debug _input => _2;
+        debug _input => const ();
     }
 
     bb0: {
diff --git a/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir
index 51514ba5e5d..64711755f73 100644
--- a/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir
+++ b/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir
@@ -4,7 +4,7 @@ fn process_void(_1: *const Void) -> () {
     debug input => _1;
     let mut _0: ();
     scope 1 {
-        debug _input => _1;
+        debug _input => const ZeroSized: Void;
     }
 
     bb0: {
diff --git a/tests/mir-opt/uninhabited_enum.rs b/tests/mir-opt/uninhabited_enum.rs
index 859535852cf..90b5353f291 100644
--- a/tests/mir-opt/uninhabited_enum.rs
+++ b/tests/mir-opt/uninhabited_enum.rs
@@ -1,18 +1,19 @@
 // skip-filecheck
 #![feature(never_type)]
 
+#[derive(Copy, Clone)]
 pub enum Void {}
 
 // EMIT_MIR uninhabited_enum.process_never.SimplifyLocals-final.after.mir
 #[no_mangle]
 pub fn process_never(input: *const !) {
-    let _input = unsafe { &*input };
+    let _input = unsafe { *input };
 }
 
 // EMIT_MIR uninhabited_enum.process_void.SimplifyLocals-final.after.mir
 #[no_mangle]
 pub fn process_void(input: *const Void) {
-    let _input = unsafe { &*input };
+    let _input = unsafe { *input };
     // In the future, this should end with `unreachable`, but we currently only do
     // unreachability analysis for `!`.
 }
diff --git a/tests/mir-opt/uninhabited_not_read.main.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_not_read.main.SimplifyLocals-final.after.mir
new file mode 100644
index 00000000000..6bf4be652be
--- /dev/null
+++ b/tests/mir-opt/uninhabited_not_read.main.SimplifyLocals-final.after.mir
@@ -0,0 +1,49 @@
+// MIR for `main` after SimplifyLocals-final
+
+fn main() -> () {
+    let mut _0: ();
+    let _1: u8;
+    let mut _2: *const !;
+    let mut _3: *const u8;
+    let _4: u8;
+    let mut _5: *const !;
+    let mut _6: *const u8;
+    scope 1 {
+        debug x => _1;
+        scope 2 {
+            debug x => _2;
+            scope 3 {
+            }
+        }
+    }
+    scope 4 {
+        debug x => _4;
+        scope 5 {
+            debug x => _5;
+            scope 6 {
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_1);
+        _1 = const 3_u8;
+        StorageLive(_2);
+        StorageLive(_3);
+        _3 = &raw const _1;
+        _2 = move _3 as *const ! (PtrToPtr);
+        StorageDead(_3);
+        StorageDead(_2);
+        StorageDead(_1);
+        StorageLive(_4);
+        _4 = const 3_u8;
+        StorageLive(_5);
+        StorageLive(_6);
+        _6 = &raw const _4;
+        _5 = move _6 as *const ! (PtrToPtr);
+        StorageDead(_6);
+        StorageDead(_5);
+        StorageDead(_4);
+        return;
+    }
+}
diff --git a/tests/mir-opt/uninhabited_not_read.rs b/tests/mir-opt/uninhabited_not_read.rs
new file mode 100644
index 00000000000..15769cdd75b
--- /dev/null
+++ b/tests/mir-opt/uninhabited_not_read.rs
@@ -0,0 +1,26 @@
+// skip-filecheck
+
+//@ edition: 2021
+// In ed 2021 and below, we don't fallback `!` to `()`.
+// This would introduce a `! -> ()` coercion which would
+// be UB if we didn't disallow this explicitly.
+
+#![feature(never_type)]
+
+// EMIT_MIR uninhabited_not_read.main.SimplifyLocals-final.after.mir
+fn main() {
+    // With a type annotation
+    unsafe {
+        let x = 3u8;
+        let x: *const ! = &x as *const u8 as *const _;
+        let _: ! = *x;
+    }
+
+    // Without a type annotation, make sure we don't implicitly coerce `!` to `()`
+    // when we do the noop `*x`.
+    unsafe {
+        let x = 3u8;
+        let x: *const ! = &x as *const u8 as *const _;
+        let _ = *x;
+    }
+}
diff --git a/tests/run-make/apple-sdk-version/foo.rs b/tests/run-make/apple-sdk-version/foo.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/tests/run-make/apple-sdk-version/foo.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/tests/run-make/apple-sdk-version/rmake.rs b/tests/run-make/apple-sdk-version/rmake.rs
new file mode 100644
index 00000000000..6463ec00403
--- /dev/null
+++ b/tests/run-make/apple-sdk-version/rmake.rs
@@ -0,0 +1,95 @@
+//! Test codegen when setting SDK version on Apple platforms.
+//!
+//! This is important since its a compatibility hazard. The linker will
+//! generate load commands differently based on what minimum OS it can assume.
+//!
+//! See https://github.com/rust-lang/rust/issues/129432.
+
+//@ only-apple
+
+use run_make_support::{apple_os, cmd, run_in_tmpdir, rustc, target};
+
+/// Run vtool to check the `sdk` field in LC_BUILD_VERSION.
+///
+/// On lower deployment targets, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS and similar
+/// are used instead of LC_BUILD_VERSION, but both name the relevant variable `sdk`.
+#[track_caller]
+fn has_sdk_version(file: &str, version: &str) {
+    cmd("vtool")
+        .arg("-show-build")
+        .arg(file)
+        .run()
+        .assert_stdout_contains(format!("sdk {version}"));
+}
+
+fn main() {
+    // Fetch rustc's inferred deployment target.
+    let current_deployment_target =
+        rustc().target(target()).print("deployment-target").run().stdout_utf8();
+    let current_deployment_target =
+        current_deployment_target.strip_prefix("deployment_target=").unwrap().trim();
+
+    // Fetch current SDK version via. xcrun.
+    //
+    // Assumes a standard Xcode distribution, where e.g. the macOS SDK's Mac Catalyst
+    // and the iPhone Simulator version is the same as for the iPhone SDK.
+    let sdk_name = match apple_os() {
+        "macos" => "macosx",
+        "ios" => "iphoneos",
+        "watchos" => "watchos",
+        "tvos" => "appletvos",
+        "visionos" => "xros",
+        _ => unreachable!(),
+    };
+    let current_sdk_version =
+        cmd("xcrun").arg("--show-sdk-version").arg("--sdk").arg(sdk_name).run().stdout_utf8();
+    let current_sdk_version = current_sdk_version.trim();
+
+    // Check the SDK version in the object file produced by the codegen backend.
+    rustc().target(target()).crate_type("lib").emit("obj").input("foo.rs").output("foo.o").run();
+    // Set to 0, which means not set or "n/a".
+    has_sdk_version("foo.o", "n/a");
+
+    // Check the SDK version in the .rmeta file, as set in `create_object_file`.
+    //
+    // This is just to ensure that we don't set some odd version in `create_object_file`,
+    // if the rmeta file is packed in a different way in the future, this can safely be removed.
+    rustc().target(target()).crate_type("rlib").input("foo.rs").output("libfoo.rlib").run();
+    // Extra .rmeta file (which is encoded as an object file).
+    cmd("ar").arg("-x").arg("libfoo.rlib").arg("lib.rmeta").run();
+    has_sdk_version("lib.rmeta", "n/a");
+
+    // Test that version makes it to the linker.
+    for (crate_type, file_ext) in [("bin", ""), ("dylib", ".dylib")] {
+        // Non-simulator watchOS targets don't support dynamic linking,
+        // for simplicity we disable the test on all watchOS targets.
+        if crate_type == "dylib" && apple_os() == "watchos" {
+            continue;
+        }
+
+        // Test with clang
+        let file_name = format!("foo_cc{file_ext}");
+        rustc()
+            .target(target())
+            .crate_type("bin")
+            .arg("-Clinker-flavor=gcc")
+            .input("foo.rs")
+            .output(&file_name)
+            .run();
+        has_sdk_version(&file_name, current_sdk_version);
+
+        // Test with ld64
+        let file_name = format!("foo_ld{file_ext}");
+        rustc()
+            .target(target())
+            .crate_type("bin")
+            .arg("-Clinker-flavor=ld")
+            .input("foo.rs")
+            .output(&file_name)
+            .run();
+        // FIXME(madsmtm): This uses the current deployment target
+        // instead of the current SDK version like Clang does.
+        // https://github.com/rust-lang/rust/issues/129432
+        has_sdk_version(&file_name, current_deployment_target);
+    }
+}
diff --git a/tests/run-make/checksum-freshness/expected.d b/tests/run-make/checksum-freshness/expected.d
new file mode 100644
index 00000000000..51467af53a2
--- /dev/null
+++ b/tests/run-make/checksum-freshness/expected.d
@@ -0,0 +1,6 @@
+lib.d: lib.rs foo.rs
+
+lib.rs:
+foo.rs:
+# checksum:blake3=94af75ee4ed805434484c3de51c9025278e5c3ada2315e2592052e102168a503 file_len:120 lib.rs
+# checksum:blake3=2720e17bfda4f3b2a5c96bb61b7e76ed8ebe3359b34128c0e5d8032c090a4f1a file_len:119 foo.rs
diff --git a/tests/run-make/checksum-freshness/foo.rs b/tests/run-make/checksum-freshness/foo.rs
new file mode 100644
index 00000000000..d3ef768f187
--- /dev/null
+++ b/tests/run-make/checksum-freshness/foo.rs
@@ -0,0 +1,5 @@
+// This is another file, just to prove we can handle two of them
+
+pub fn subtract(a: i32, b: i32) -> i32 {
+    a - b
+}
diff --git a/tests/run-make/checksum-freshness/lib.rs b/tests/run-make/checksum-freshness/lib.rs
new file mode 100644
index 00000000000..7bc6757959b
--- /dev/null
+++ b/tests/run-make/checksum-freshness/lib.rs
@@ -0,0 +1,7 @@
+// A basic library to be used in tests with no real purpose.
+
+mod foo;
+
+pub fn sum(a: i32, b: i32) -> i32 {
+    a + b
+}
diff --git a/tests/run-make/checksum-freshness/rmake.rs b/tests/run-make/checksum-freshness/rmake.rs
new file mode 100644
index 00000000000..071db6b145b
--- /dev/null
+++ b/tests/run-make/checksum-freshness/rmake.rs
@@ -0,0 +1,9 @@
+use run_make_support::{rfs, rustc};
+
+fn main() {
+    rustc().input("lib.rs").arg("-Zchecksum-hash-algorithm=blake3").emit("dep-info").run();
+    let make_file_contents = rfs::read_to_string("lib.d");
+    let expected_contents = rfs::read_to_string("expected.d");
+    assert_eq!(make_file_contents, expected_contents);
+    assert!(!expected_contents.is_empty());
+}
diff --git a/tests/run-make/doctests-merge/doctest-standalone.rs b/tests/run-make/doctests-merge/doctest-standalone.rs
index 134ffb58285..ac9f8f9272a 100644
--- a/tests/run-make/doctests-merge/doctest-standalone.rs
+++ b/tests/run-make/doctests-merge/doctest-standalone.rs
@@ -1,11 +1,11 @@
 #![crate_name = "foo"]
 #![crate_type = "lib"]
 
-//! ```standalone
+//! ```standalone_crate
 //! foo::init();
 //! ```
 
-/// ```standalone
+/// ```standalone_crate
 /// foo::init();
 /// ```
 pub fn init() {
diff --git a/tests/run-make/dylib-soname/rmake.rs b/tests/run-make/dylib-soname/rmake.rs
index cec0d463842..714997cbc1a 100644
--- a/tests/run-make/dylib-soname/rmake.rs
+++ b/tests/run-make/dylib-soname/rmake.rs
@@ -7,12 +7,16 @@
 use run_make_support::{cmd, run_in_tmpdir, rustc};
 
 fn main() {
+    let check = |ty: &str| {
+        rustc().crate_name("foo").crate_type(ty).input("foo.rs").run();
+        cmd("readelf").arg("-d").arg("libfoo.so").run()
+    };
     run_in_tmpdir(|| {
-        rustc().crate_name("foo").crate_type("dylib").input("foo.rs").run();
-        cmd("readelf")
-            .arg("-d")
-            .arg("libfoo.so")
-            .run()
-            .assert_stdout_contains("Library soname: [libfoo.so]");
+        // Rust dylibs should get a relative SONAME
+        check("dylib").assert_stdout_contains("Library soname: [libfoo.so]");
+    });
+    run_in_tmpdir(|| {
+        // C dylibs should not implicitly get any SONAME
+        check("cdylib").assert_stdout_not_contains("Library soname:");
     });
 }
diff --git a/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs b/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs
index f00123f006b..8dd19e613bf 100644
--- a/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs
+++ b/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs
@@ -1,7 +1,7 @@
 #![feature(naked_functions, asm_const, linkage)]
 #![crate_type = "dylib"]
 
-use std::arch::asm;
+use std::arch::naked_asm;
 
 pub trait TraitWithConst {
     const COUNT: u32;
@@ -28,7 +28,7 @@ extern "C" fn private_vanilla() -> u32 {
 
 #[naked]
 extern "C" fn private_naked() -> u32 {
-    unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
+    unsafe { naked_asm!("mov rax, 42", "ret") }
 }
 
 #[no_mangle]
@@ -39,7 +39,7 @@ pub extern "C" fn public_vanilla() -> u32 {
 #[naked]
 #[no_mangle]
 pub extern "C" fn public_naked() -> u32 {
-    unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
+    unsafe { naked_asm!("mov rax, 42", "ret") }
 }
 
 pub extern "C" fn public_vanilla_generic<T: TraitWithConst>() -> u32 {
@@ -48,7 +48,7 @@ pub extern "C" fn public_vanilla_generic<T: TraitWithConst>() -> u32 {
 
 #[naked]
 pub extern "C" fn public_naked_generic<T: TraitWithConst>() -> u32 {
-    unsafe { asm!("mov rax, {}", "ret", const T::COUNT, options(noreturn)) }
+    unsafe { naked_asm!("mov rax, {}", "ret", const T::COUNT) }
 }
 
 #[linkage = "external"]
@@ -59,7 +59,7 @@ extern "C" fn vanilla_external_linkage() -> u32 {
 #[naked]
 #[linkage = "external"]
 extern "C" fn naked_external_linkage() -> u32 {
-    unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
+    unsafe { naked_asm!("mov rax, 42", "ret") }
 }
 
 #[cfg(not(windows))]
@@ -72,7 +72,7 @@ extern "C" fn vanilla_weak_linkage() -> u32 {
 #[cfg(not(windows))]
 #[linkage = "weak"]
 extern "C" fn naked_weak_linkage() -> u32 {
-    unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
+    unsafe { naked_asm!("mov rax, 42", "ret") }
 }
 
 // functions that are declared in an `extern "C"` block are currently not exported
diff --git a/tests/rustdoc-gui/README.md b/tests/rustdoc-gui/README.md
index 1126a72ab67..efd513715d4 100644
--- a/tests/rustdoc-gui/README.md
+++ b/tests/rustdoc-gui/README.md
@@ -23,12 +23,5 @@ $ ./x.py test tests/rustdoc-gui --stage 1 --test-args --no-headless
 
 To see the supported options, use `--help`.
 
-Important to be noted: if the chromium instance crashes when you run it, you might need to
-use `--no-sandbox` to make it work:
-
-```bash
-$ ./x.py test tests/rustdoc-gui --stage 1 --test-args --no-sandbox
-```
-
 [browser-ui-test]: https://github.com/GuillaumeGomez/browser-UI-test/
 [puppeteer]: https://pptr.dev/
diff --git a/tests/rustdoc-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml
index 53f756dfcd6..3c16626336e 100644
--- a/tests/rustdoc-gui/docblock-code-block-line-number.goml
+++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml
@@ -87,8 +87,7 @@ assert-css: ("#settings", {"display": "block"})
 
 // Then, click the toggle button.
 click: "input#line-numbers"
-wait-for: 100 // FIXME: `wait-for-false` does not exist
-assert-false: "pre.example-line-numbers"
+wait-for-false: "pre.example-line-numbers"
 assert-local-storage: {"rustdoc-line-numbers": "false" }
 
 // Check that the rounded corners are back.
@@ -107,8 +106,7 @@ assert-css: (
 click: "input#line-numbers"
 wait-for: "pre.example-line-numbers"
 assert-local-storage: {"rustdoc-line-numbers": "true" }
-wait-for: 100 // FIXME: `wait-for-false` does not exist
-assert: "pre.example-line-numbers"
+wait-for: "pre.example-line-numbers"
 
 // Same check with scraped examples line numbers.
 go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html"
@@ -195,15 +193,13 @@ define-function: ("check-line-numbers-existence", [], block {
 
     // Then, click the toggle button.
     click: "input#line-numbers"
-    wait-for: 100 // FIXME: `wait-for-false` does not exist
-    assert-local-storage-false: {"rustdoc-line-numbers": "true" }
+    wait-for-local-storage-false: {"rustdoc-line-numbers": "true" }
     assert-false: ".example-line-numbers"
     // Line numbers should still be there.
     assert: ".src-line-numbers"
     // Now disabling the setting.
     click: "input#line-numbers"
-    wait-for: 100 // FIXME: `wait-for-false` does not exist
-    assert-local-storage: {"rustdoc-line-numbers": "true" }
+    wait-for-local-storage: {"rustdoc-line-numbers": "true" }
     assert-false: ".example-line-numbers"
     // Line numbers should still be there.
     assert: ".src-line-numbers"
@@ -246,12 +242,10 @@ wait-for: "#settings"
 
 // Then, click the toggle button.
 click: "input#line-numbers"
-wait-for: 100 // FIXME: `wait-for-false` does not exist
+wait-for-count: (".example-wrap > pre.example-line-numbers", 0)
 assert-local-storage-false: {"rustdoc-line-numbers": "true" }
-assert-count: (".example-wrap > pre.example-line-numbers", 0)
 
 // Now turning off the setting.
 click: "input#line-numbers"
-wait-for: 100 // FIXME: `wait-for-false` does not exist
+wait-for-count: (".example-wrap > pre.example-line-numbers", 2)
 assert-local-storage: {"rustdoc-line-numbers": "true" }
-assert-count: (".example-wrap > pre.example-line-numbers", 2)
diff --git a/tests/rustdoc-gui/list-margins.goml b/tests/rustdoc-gui/list-margins.goml
new file mode 100644
index 00000000000..c83f5898e8e
--- /dev/null
+++ b/tests/rustdoc-gui/list-margins.goml
@@ -0,0 +1,11 @@
+// This test ensures that the documentation list markers are correctly placed.
+// It also serves as a regression test for <https://github.com/rust-lang/rust/issues/130622>.
+
+go-to: "file://" + |DOC_PATH| + "/test_docs/long_list/index.html"
+show-text: true
+
+// 0.3em
+assert-css: (".docblock li p:not(last-child)", {"margin-bottom": "4.8px"})
+assert-css: (".docblock li p + p:last-child", {"margin-bottom": "0px"})
+// 0.4em
+assert-css: (".docblock li", {"margin-bottom": "6.4px"})
diff --git a/tests/rustdoc-gui/scrape-examples-layout.goml b/tests/rustdoc-gui/scrape-examples-layout.goml
index fd0774c91b6..96c78bbfe8b 100644
--- a/tests/rustdoc-gui/scrape-examples-layout.goml
+++ b/tests/rustdoc-gui/scrape-examples-layout.goml
@@ -90,8 +90,8 @@ assert-css: (".scraped-example .example-wrap::after", {"bottom": "0px"})
 // Then with mobile
 set-window-size: (600, 600)
 store-size: (".scraped-example .scraped-example-title", {"height": title_height})
-assert-position: (".scraped-example", {"y": 281})
-assert-position: (".scraped-example .prev", {"y": 281 + |offset_y| + |title_height|})
+assert-position: (".scraped-example", {"y": 287})
+assert-position: (".scraped-example .prev", {"y": 287 + |offset_y| + |title_height|})
 
 define-function: (
     "check_title_and_code_position",
diff --git a/tests/rustdoc-gui/search-result-display.goml b/tests/rustdoc-gui/search-result-display.goml
index 156244f92b4..1521267956a 100644
--- a/tests/rustdoc-gui/search-result-display.goml
+++ b/tests/rustdoc-gui/search-result-display.goml
@@ -64,7 +64,7 @@ set-text: (
 )
 
 // Then we compare again to confirm the height didn't change.
-assert-size: ("#crate-search", {"width": 509})
+assert-size: ("#crate-search", {"width": 370})
 assert-size: (".search-results-title", {
     "height": |search_results_title_height|,
 })
diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml
index c3e02c4e9b4..742453c173b 100644
--- a/tests/rustdoc-gui/sidebar-source-code-display.goml
+++ b/tests/rustdoc-gui/sidebar-source-code-display.goml
@@ -141,7 +141,7 @@ click: "#sidebar-button"
 wait-for-css: (".src .sidebar > *", {"visibility": "hidden"})
 // We scroll to line 117 to change the scroll position.
 scroll-to: '//*[@id="117"]'
-store-value: (y_offset, "2564")
+store-value: (y_offset, "2570")
 assert-window-property: {"pageYOffset": |y_offset|}
 // Expanding the sidebar...
 click: "#sidebar-button"
diff --git a/tests/rustdoc-gui/source-anchor-scroll.goml b/tests/rustdoc-gui/source-anchor-scroll.goml
index 166890abe4b..f8794645705 100644
--- a/tests/rustdoc-gui/source-anchor-scroll.goml
+++ b/tests/rustdoc-gui/source-anchor-scroll.goml
@@ -8,13 +8,13 @@ set-window-size: (600, 800)
 assert-property: ("html", {"scrollTop": "0"})
 
 click: '//a[text() = "barbar" and @href="#5-7"]'
-assert-property: ("html", {"scrollTop": "194"})
+assert-property: ("html", {"scrollTop": "200"})
 click: '//a[text() = "bar" and @href="#28-36"]'
-assert-property: ("html", {"scrollTop": "225"})
+assert-property: ("html", {"scrollTop": "231"})
 click: '//a[normalize-space() = "sub_fn" and @href="#2-4"]'
-assert-property: ("html", {"scrollTop": "122"})
+assert-property: ("html", {"scrollTop": "128"})
 
 // We now check that clicking on lines doesn't change the scroll
 // Extra information: the "sub_fn" function header is on line 1.
 click: '//*[@id="6"]'
-assert-property: ("html", {"scrollTop": "122"})
+assert-property: ("html", {"scrollTop": "128"})
diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs
index 7397992c0ab..352995c4903 100644
--- a/tests/rustdoc-gui/src/test_docs/lib.rs
+++ b/tests/rustdoc-gui/src/test_docs/lib.rs
@@ -628,3 +628,27 @@ pub mod short_docs {
     /// subt_vec_num(x: &[f64], y: f64)
     pub fn subt_vec_num() {}
 }
+
+pub mod long_list {
+    //! bla
+    //!
+    //! * Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque et libero ut leo
+    //!   interdum laoreet vitae a mi. Aliquam erat volutpat. Suspendisse volutpat non quam non
+    //!   commodo.
+    //!
+    //!   Praesent enim neque, imperdiet sed nisl at, lobortis egestas augue. Sed vitae tristique
+    //!   augue. Phasellus vel pretium lectus.
+    //! * Praesent enim neque, imperdiet sed nisl at, lobortis egestas augue. Sed vitae tristique
+    //!   augue. Phasellus vel pretium lectus.
+    //! * Praesent enim neque, imperdiet sed nisl at, lobortis egestas augue. Sed vitae tristique
+    //!   augue. Phasellus vel pretium lectus.
+    //!
+    //! Another list:
+    //!
+    //! * [`TryFromBytes`](#a) indicates that a type may safely be converted from certain byte
+    //!   sequence (conditional on runtime checks)
+    //! * [`FromZeros`](#a) indicates that a sequence of zero bytes represents a valid instance of
+    //!   a type
+    //! * [`FromBytes`](#a) indicates that a type may safely be converted from an arbitrary byte
+    //!   sequence
+}
diff --git a/tests/rustdoc-gui/toggle-docs-mobile.goml b/tests/rustdoc-gui/toggle-docs-mobile.goml
index 59233d94fcc..b69aa6e30ca 100644
--- a/tests/rustdoc-gui/toggle-docs-mobile.goml
+++ b/tests/rustdoc-gui/toggle-docs-mobile.goml
@@ -3,12 +3,12 @@
 go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
 set-window-size: (433, 600)
 assert-attribute: (".top-doc", {"open": ""})
-click: (4, 260) // This is the position of the top doc comment toggle
+click: (4, 270) // This is the position of the top doc comment toggle
 assert-attribute-false: (".top-doc", {"open": ""})
-click: (4, 260)
+click: (4, 270)
 assert-attribute: (".top-doc", {"open": ""})
 // To ensure that the toggle isn't over the text, we check that the toggle isn't clicked.
-click: (3, 260)
+click: (3, 270)
 assert-attribute: (".top-doc", {"open": ""})
 
 // Assert the position of the toggle on the top doc block.
@@ -24,10 +24,10 @@ assert-position: (
 // Now we do the same but with a little bigger width
 set-window-size: (600, 600)
 assert-attribute: (".top-doc", {"open": ""})
-click: (4, 260) // New Y position since all search elements are back on one line.
+click: (4, 270) // New Y position since all search elements are back on one line.
 assert-attribute-false: (".top-doc", {"open": ""})
-click: (4, 260)
+click: (4, 270)
 assert-attribute: (".top-doc", {"open": ""})
 // To ensure that the toggle isn't over the text, we check that the toggle isn't clicked.
-click: (3, 260)
+click: (3, 270)
 assert-attribute: (".top-doc", {"open": ""})
diff --git a/tests/rustdoc-js-std/path-ordering.js b/tests/rustdoc-js-std/path-ordering.js
index e6b7bfab1e5..4bfc6256052 100644
--- a/tests/rustdoc-js-std/path-ordering.js
+++ b/tests/rustdoc-js-std/path-ordering.js
@@ -6,7 +6,6 @@ const EXPECTED = [
             { 'path': 'std::collections::hash_set::HashSet', 'name': 'insert' },
             { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert' },
             { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_with' },
-            { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_owned' },
         ],
     },
     {
diff --git a/tests/rustdoc-ui/cfg-boolean-literal.rs b/tests/rustdoc-ui/cfg-boolean-literal.rs
new file mode 100644
index 00000000000..4d4e599bfee
--- /dev/null
+++ b/tests/rustdoc-ui/cfg-boolean-literal.rs
@@ -0,0 +1,19 @@
+//@ check-pass
+
+#![feature(cfg_boolean_literals)]
+#![feature(doc_cfg)]
+
+#[doc(cfg(false))]
+pub fn foo() {}
+
+#[doc(cfg(true))]
+pub fn bar() {}
+
+#[doc(cfg(any(true)))]
+pub fn zoo() {}
+
+#[doc(cfg(all(true)))]
+pub fn toy() {}
+
+#[doc(cfg(not(true)))]
+pub fn nay() {}
diff --git a/tests/rustdoc-ui/doctest/check-attr-test.stderr b/tests/rustdoc-ui/doctest/check-attr-test.stderr
index 10f763a6f9d..257136d1633 100644
--- a/tests/rustdoc-ui/doctest/check-attr-test.stderr
+++ b/tests/rustdoc-ui/doctest/check-attr-test.stderr
@@ -8,8 +8,8 @@ error: unknown attribute `compile-fail`
 9 | | /// ```
   | |_______^
   |
-  = help: there is an attribute with a similar name: `compile_fail`
-  = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
+  = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can
+  = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 note: the lint level is defined here
  --> $DIR/check-attr-test.rs:3:9
   |
@@ -26,8 +26,8 @@ error: unknown attribute `compilefail`
 9 | | /// ```
   | |_______^
   |
-  = help: there is an attribute with a similar name: `compile_fail`
-  = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
+  = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can
+  = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `comPile_fail`
  --> $DIR/check-attr-test.rs:5:1
@@ -39,8 +39,8 @@ error: unknown attribute `comPile_fail`
 9 | | /// ```
   | |_______^
   |
-  = help: there is an attribute with a similar name: `compile_fail`
-  = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
+  = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can
+  = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `should-panic`
   --> $DIR/check-attr-test.rs:12:1
@@ -52,8 +52,8 @@ error: unknown attribute `should-panic`
 16 | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `should_panic`
-   = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
+   = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `shouldpanic`
   --> $DIR/check-attr-test.rs:12:1
@@ -65,8 +65,8 @@ error: unknown attribute `shouldpanic`
 16 | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `should_panic`
-   = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
+   = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `shOuld_panic`
   --> $DIR/check-attr-test.rs:12:1
@@ -78,8 +78,8 @@ error: unknown attribute `shOuld_panic`
 16 | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `should_panic`
-   = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
+   = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `no-run`
   --> $DIR/check-attr-test.rs:19:1
@@ -91,8 +91,8 @@ error: unknown attribute `no-run`
 23 | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `no_run`
-   = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
+   = help: use `no_run` to compile, but not run, the code sample during testing
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `norun`
   --> $DIR/check-attr-test.rs:19:1
@@ -104,8 +104,8 @@ error: unknown attribute `norun`
 23 | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `no_run`
-   = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
+   = help: use `no_run` to compile, but not run, the code sample during testing
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `nO_run`
   --> $DIR/check-attr-test.rs:19:1
@@ -117,8 +117,8 @@ error: unknown attribute `nO_run`
 23 | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `no_run`
-   = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
+   = help: use `no_run` to compile, but not run, the code sample during testing
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `test-harness`
   --> $DIR/check-attr-test.rs:26:1
@@ -130,8 +130,8 @@ error: unknown attribute `test-harness`
 30 | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `test_harness`
-   = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
+   = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `testharness`
   --> $DIR/check-attr-test.rs:26:1
@@ -143,8 +143,8 @@ error: unknown attribute `testharness`
 30 | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `test_harness`
-   = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
+   = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `tesT_harness`
   --> $DIR/check-attr-test.rs:26:1
@@ -156,8 +156,8 @@ error: unknown attribute `tesT_harness`
 30 | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `test_harness`
-   = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
+   = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: aborting due to 12 previous errors
 
diff --git a/tests/rustdoc-ui/doctest/standalone-warning-2024.rs b/tests/rustdoc-ui/doctest/standalone-warning-2024.rs
new file mode 100644
index 00000000000..aac43031546
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/standalone-warning-2024.rs
@@ -0,0 +1,16 @@
+// This test checks that it will output warnings for usage of `standalone` or `standalone_crate`.
+
+//@ compile-flags:--test -Zunstable-options --edition 2024
+//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
+//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout-test: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL"
+
+#![deny(warnings)]
+
+//! ```standalone
+//! bla
+//! ```
+//!
+//! ```standalone-crate
+//! bla
+//! ```
diff --git a/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr b/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr
new file mode 100644
index 00000000000..d69d03d8657
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr
@@ -0,0 +1,38 @@
+error: unknown attribute `standalone`
+  --> $DIR/standalone-warning-2024.rs:10:1
+   |
+10 | / //! ```standalone
+11 | | //! bla
+12 | | //! ```
+13 | | //!
+14 | | //! ```standalone-crate
+15 | | //! bla
+16 | | //! ```
+   | |_______^
+   |
+   = help: use `standalone_crate` to compile this code block separately
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
+note: the lint level is defined here
+  --> $DIR/standalone-warning-2024.rs:8:9
+   |
+8  | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(warnings)]`
+
+error: unknown attribute `standalone-crate`
+  --> $DIR/standalone-warning-2024.rs:10:1
+   |
+10 | / //! ```standalone
+11 | | //! bla
+12 | | //! ```
+13 | | //!
+14 | | //! ```standalone-crate
+15 | | //! bla
+16 | | //! ```
+   | |_______^
+   |
+   = help: use `standalone_crate` to compile this code block separately
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/rustdoc-ui/doctest/standalone-warning.rs b/tests/rustdoc-ui/doctest/standalone-warning.rs
new file mode 100644
index 00000000000..ce081c7641c
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/standalone-warning.rs
@@ -0,0 +1,10 @@
+// This test checks that it will not output warning for usage of `standalone` or `standalone_crate`.
+//@ check-pass
+
+//! ```standalone
+//! bla
+//! ```
+//!
+//! ```standalone-crate
+//! bla
+//! ```
diff --git a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs
index 2d66566119b..f63a9e87497 100644
--- a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs
+++ b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs
@@ -1,6 +1,8 @@
 #![deny(rustdoc::broken_intra_doc_links)]
 //~^ NOTE lint level is defined
-pub enum S {}
+pub enum S {
+    A,
+}
 fn S() {}
 
 #[macro_export]
@@ -13,6 +15,10 @@ const c: usize = 0;
 
 trait T {}
 
+struct X {
+    y: usize,
+}
+
 /// Link to [struct@S]
 //~^ ERROR incompatible link kind for `S`
 //~| NOTE this link resolved
@@ -78,4 +84,14 @@ trait T {}
 //~^ ERROR unresolved link to `std`
 //~| NOTE this link resolves to the crate `std`
 //~| HELP to link to the crate, prefix with `mod@`
+
+/// Link to [method@X::y]
+//~^ ERROR incompatible link kind for `X::y`
+//~| NOTE this link resolved
+//~| HELP prefix with `field@`
+
+/// Link to [field@S::A]
+//~^ ERROR unresolved link to `S::A`
+//~| NOTE this link resolves
+//~| HELP prefix with `variant@`
 pub fn f() {}
diff --git a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr
index ee35749ce7f..ef7fec77b1e 100644
--- a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr
+++ b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr
@@ -1,5 +1,5 @@
 error: incompatible link kind for `S`
-  --> $DIR/disambiguator-mismatch.rs:16:14
+  --> $DIR/disambiguator-mismatch.rs:22:14
    |
 LL | /// Link to [struct@S]
    |              ^^^^^^^^ this link resolved to an enum, which is not a struct
@@ -15,7 +15,7 @@ LL | /// Link to [enum@S]
    |              ~~~~~
 
 error: incompatible link kind for `S`
-  --> $DIR/disambiguator-mismatch.rs:21:14
+  --> $DIR/disambiguator-mismatch.rs:27:14
    |
 LL | /// Link to [mod@S]
    |              ^^^^^ this link resolved to an enum, which is not a module
@@ -26,7 +26,7 @@ LL | /// Link to [enum@S]
    |              ~~~~~
 
 error: incompatible link kind for `S`
-  --> $DIR/disambiguator-mismatch.rs:26:14
+  --> $DIR/disambiguator-mismatch.rs:32:14
    |
 LL | /// Link to [union@S]
    |              ^^^^^^^ this link resolved to an enum, which is not a union
@@ -37,7 +37,7 @@ LL | /// Link to [enum@S]
    |              ~~~~~
 
 error: incompatible link kind for `S`
-  --> $DIR/disambiguator-mismatch.rs:31:14
+  --> $DIR/disambiguator-mismatch.rs:37:14
    |
 LL | /// Link to [trait@S]
    |              ^^^^^^^ this link resolved to an enum, which is not a trait
@@ -48,7 +48,7 @@ LL | /// Link to [enum@S]
    |              ~~~~~
 
 error: incompatible link kind for `T`
-  --> $DIR/disambiguator-mismatch.rs:36:14
+  --> $DIR/disambiguator-mismatch.rs:42:14
    |
 LL | /// Link to [struct@T]
    |              ^^^^^^^^ this link resolved to a trait, which is not a struct
@@ -59,7 +59,7 @@ LL | /// Link to [trait@T]
    |              ~~~~~~
 
 error: incompatible link kind for `m`
-  --> $DIR/disambiguator-mismatch.rs:41:14
+  --> $DIR/disambiguator-mismatch.rs:47:14
    |
 LL | /// Link to [derive@m]
    |              ^^^^^^^^ this link resolved to a macro, which is not a derive macro
@@ -71,10 +71,10 @@ LL + /// Link to [m!]
    |
 
 error: unresolved link to `m`
-  --> $DIR/disambiguator-mismatch.rs:46:14
+  --> $DIR/disambiguator-mismatch.rs:52:14
    |
 LL | /// Link to [m()]
-   |              ^^^ this link resolves to the macro `m`, which is not in the value namespace
+   |              ^^^ this link resolves to the macro `m`, which is not a function
    |
 help: to link to the macro, add an exclamation mark
    |
@@ -82,7 +82,7 @@ LL | /// Link to [m!()]
    |               +
 
 error: incompatible link kind for `s`
-  --> $DIR/disambiguator-mismatch.rs:52:14
+  --> $DIR/disambiguator-mismatch.rs:58:14
    |
 LL | /// Link to [const@s]
    |              ^^^^^^^ this link resolved to a static, which is not a constant
@@ -93,7 +93,7 @@ LL | /// Link to [static@s]
    |              ~~~~~~~
 
 error: incompatible link kind for `c`
-  --> $DIR/disambiguator-mismatch.rs:57:14
+  --> $DIR/disambiguator-mismatch.rs:63:14
    |
 LL | /// Link to [static@c]
    |              ^^^^^^^^ this link resolved to a constant, which is not a static
@@ -104,7 +104,7 @@ LL | /// Link to [const@c]
    |              ~~~~~~
 
 error: incompatible link kind for `c`
-  --> $DIR/disambiguator-mismatch.rs:62:14
+  --> $DIR/disambiguator-mismatch.rs:68:14
    |
 LL | /// Link to [fn@c]
    |              ^^^^ this link resolved to a constant, which is not a function
@@ -115,7 +115,7 @@ LL | /// Link to [const@c]
    |              ~~~~~~
 
 error: incompatible link kind for `c`
-  --> $DIR/disambiguator-mismatch.rs:67:14
+  --> $DIR/disambiguator-mismatch.rs:73:14
    |
 LL | /// Link to [c()]
    |              ^^^ this link resolved to a constant, which is not a function
@@ -127,7 +127,7 @@ LL + /// Link to [const@c]
    |
 
 error: incompatible link kind for `f`
-  --> $DIR/disambiguator-mismatch.rs:72:14
+  --> $DIR/disambiguator-mismatch.rs:78:14
    |
 LL | /// Link to [const@f]
    |              ^^^^^^^ this link resolved to a function, which is not a constant
@@ -139,15 +139,37 @@ LL + /// Link to [f()]
    |
 
 error: unresolved link to `std`
-  --> $DIR/disambiguator-mismatch.rs:77:14
+  --> $DIR/disambiguator-mismatch.rs:83:14
    |
 LL | /// Link to [fn@std]
-   |              ^^^^^^ this link resolves to the crate `std`, which is not in the value namespace
+   |              ^^^^^^ this link resolves to the crate `std`, which is not a function
    |
 help: to link to the crate, prefix with `mod@`
    |
 LL | /// Link to [mod@std]
    |              ~~~~
 
-error: aborting due to 13 previous errors
+error: incompatible link kind for `X::y`
+  --> $DIR/disambiguator-mismatch.rs:88:14
+   |
+LL | /// Link to [method@X::y]
+   |              ^^^^^^^^^^^ this link resolved to a field, which is not a function
+   |
+help: to link to the field, prefix with `field@`
+   |
+LL | /// Link to [field@X::y]
+   |              ~~~~~~
+
+error: unresolved link to `S::A`
+  --> $DIR/disambiguator-mismatch.rs:93:14
+   |
+LL | /// Link to [field@S::A]
+   |              ^^^^^^^^^^ this link resolves to the variant `A`, which is not a field
+   |
+help: to link to the variant, prefix with `variant@`
+   |
+LL | /// Link to [variant@S::A]
+   |              ~~~~~~~~
+
+error: aborting due to 15 previous errors
 
diff --git a/tests/rustdoc-ui/intra-doc/errors.rs b/tests/rustdoc-ui/intra-doc/errors.rs
index f37f49c24cc..e885a3b35f6 100644
--- a/tests/rustdoc-ui/intra-doc/errors.rs
+++ b/tests/rustdoc-ui/intra-doc/errors.rs
@@ -98,7 +98,7 @@ pub trait T {
 /// [m()]
 //~^ ERROR unresolved link
 //~| HELP to link to the macro
-//~| NOTE not in the value namespace
+//~| NOTE not a function
 #[macro_export]
 macro_rules! m {
     () => {};
diff --git a/tests/rustdoc-ui/intra-doc/errors.stderr b/tests/rustdoc-ui/intra-doc/errors.stderr
index a982bba0095..07d328f99a3 100644
--- a/tests/rustdoc-ui/intra-doc/errors.stderr
+++ b/tests/rustdoc-ui/intra-doc/errors.stderr
@@ -104,7 +104,7 @@ error: unresolved link to `S`
   --> $DIR/errors.rs:68:6
    |
 LL | /// [S!]
-   |      ^^ this link resolves to the struct `S`, which is not in the macro namespace
+   |      ^^ this link resolves to the struct `S`, which is not a macro
    |
 help: to link to the struct, prefix with `struct@`
    |
@@ -158,7 +158,7 @@ error: unresolved link to `m`
   --> $DIR/errors.rs:98:6
    |
 LL | /// [m()]
-   |      ^^^ this link resolves to the macro `m`, which is not in the value namespace
+   |      ^^^ this link resolves to the macro `m`, which is not a function
    |
 help: to link to the macro, add an exclamation mark
    |
diff --git a/tests/rustdoc-ui/intra-doc/field-ice.rs b/tests/rustdoc-ui/intra-doc/field-ice.rs
index c5d501e38da..1ba865b53c2 100644
--- a/tests/rustdoc-ui/intra-doc/field-ice.rs
+++ b/tests/rustdoc-ui/intra-doc/field-ice.rs
@@ -4,8 +4,8 @@
 /// [`Foo::bar`]
 /// [`Foo::bar()`]
 //~^ERROR incompatible link kind for `Foo::bar`
-//~|HELP to link to the field, remove the disambiguator
+//~|HELP to link to the field, prefix with `field@`
 //~|NOTE this link resolved to a field, which is not a function
 pub struct Foo {
-    pub bar: u8
+    pub bar: u8,
 }
diff --git a/tests/rustdoc-ui/intra-doc/field-ice.stderr b/tests/rustdoc-ui/intra-doc/field-ice.stderr
index cc0ada873af..7321c87b790 100644
--- a/tests/rustdoc-ui/intra-doc/field-ice.stderr
+++ b/tests/rustdoc-ui/intra-doc/field-ice.stderr
@@ -9,10 +9,11 @@ note: the lint level is defined here
    |
 LL | #![deny(rustdoc::broken_intra_doc_links)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: to link to the field, remove the disambiguator
+help: to link to the field, prefix with `field@`
+   |
+LL - /// [`Foo::bar()`]
+LL + /// [`field@Foo::bar`]
    |
-LL | /// [`Foo::bar`]
-   |       ~~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr b/tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr
index ed89fa8391d..9cd855b69ff 100644
--- a/tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr
+++ b/tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr
@@ -43,10 +43,10 @@ help: to link to the associated function, add parentheses
    |
 LL | /// [`Self::IDENT()`]
    |                  ++
-help: to link to the variant, prefix with `type@`
+help: to link to the variant, prefix with `variant@`
    |
-LL | /// [`type@Self::IDENT`]
-   |       +++++
+LL | /// [`variant@Self::IDENT`]
+   |       ++++++++
 
 error: `Self::IDENT2` is both an associated constant and an associated type
   --> $DIR/issue-108653-associated-items.rs:30:7
diff --git a/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr b/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr
index 6c834fd0a1b..a347044bfe9 100644
--- a/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr
+++ b/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr
@@ -2,7 +2,7 @@ error: unresolved link to `Clone`
   --> $DIR/issue-110495-suffix-with-space.rs:3:6
    |
 LL | //! [Clone ()].
-   |      ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |      ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function
    |
 note: the lint level is defined here
   --> $DIR/issue-110495-suffix-with-space.rs:2:9
@@ -31,7 +31,7 @@ error: unresolved link to `Clone`
   --> $DIR/issue-110495-suffix-with-space.rs:5:7
    |
 LL | //! [`Clone ()`].
-   |       ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |       ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function
    |
 help: to link to the trait, prefix with `trait@`
    |
diff --git a/tests/rustdoc-ui/intra-doc/value-ctor.rs b/tests/rustdoc-ui/intra-doc/value-ctor.rs
new file mode 100644
index 00000000000..6f57b7c6f10
--- /dev/null
+++ b/tests/rustdoc-ui/intra-doc/value-ctor.rs
@@ -0,0 +1,35 @@
+// https://github.com/rust-lang/rust/issues/130591
+#![deny(rustdoc::broken_intra_doc_links)]
+#![crate_name = "foo"]
+
+/// [value@Foo::X] //~ERROR broken
+pub enum Foo {
+    X,
+}
+
+/// [tst][value@MyStruct] //~ERROR broken
+pub struct MyStruct;
+
+pub enum MyEnum {
+    Internals,
+}
+
+pub use MyEnum::*;
+
+/// In this context, [a][type@Internals] is a struct,
+/// while [b][value@Internals] fails. //~ERROR broken
+/// Also, [c][struct@Internals] is a struct,
+/// while [d][variant@Internals] fails. //~ERROR broken
+pub struct Internals {
+    foo: (),
+}
+
+pub mod inside {
+    pub struct Internals2;
+}
+
+use inside::*;
+
+/// In this context, [a][type@Internals2] is an enum,
+/// while [b][value@Internals2] fails. //~ERROR broken
+pub enum Internals2 {}
diff --git a/tests/rustdoc-ui/intra-doc/value-ctor.stderr b/tests/rustdoc-ui/intra-doc/value-ctor.stderr
new file mode 100644
index 00000000000..8d2a6649f4c
--- /dev/null
+++ b/tests/rustdoc-ui/intra-doc/value-ctor.stderr
@@ -0,0 +1,62 @@
+error: unresolved link to `Foo::X`
+  --> $DIR/value-ctor.rs:5:6
+   |
+LL | /// [value@Foo::X]
+   |      ^^^^^^^^^^^^ this link resolves to the variant `X`, which is not in the value namespace
+   |
+note: the lint level is defined here
+  --> $DIR/value-ctor.rs:2:9
+   |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to link to the variant, prefix with `variant@`
+   |
+LL | /// [variant@Foo::X]
+   |      ~~~~~~~~
+
+error: unresolved link to `MyStruct`
+  --> $DIR/value-ctor.rs:10:11
+   |
+LL | /// [tst][value@MyStruct]
+   |           ^^^^^^^^^^^^^^ this link resolves to the struct `MyStruct`, which is not in the value namespace
+   |
+help: to link to the struct, prefix with `struct@`
+   |
+LL | /// [tst][struct@MyStruct]
+   |           ~~~~~~~
+
+error: unresolved link to `Internals`
+  --> $DIR/value-ctor.rs:20:15
+   |
+LL | /// while [b][value@Internals] fails.
+   |               ^^^^^^^^^^^^^^^ this link resolves to the struct `Internals`, which is not in the value namespace
+   |
+help: to link to the struct, prefix with `struct@`
+   |
+LL | /// while [b][struct@Internals] fails.
+   |               ~~~~~~~
+
+error: incompatible link kind for `Internals`
+  --> $DIR/value-ctor.rs:22:15
+   |
+LL | /// while [d][variant@Internals] fails.
+   |               ^^^^^^^^^^^^^^^^^ this link resolved to a struct, which is not a variant
+   |
+help: to link to the struct, prefix with `struct@`
+   |
+LL | /// while [d][struct@Internals] fails.
+   |               ~~~~~~~
+
+error: unresolved link to `Internals2`
+  --> $DIR/value-ctor.rs:34:15
+   |
+LL | /// while [b][value@Internals2] fails.
+   |               ^^^^^^^^^^^^^^^^ this link resolves to the enum `Internals2`, which is not in the value namespace
+   |
+help: to link to the enum, prefix with `enum@`
+   |
+LL | /// while [b][enum@Internals2] fails.
+   |               ~~~~~
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr
index f50feb57fcc..17bcbc783fd 100644
--- a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr
+++ b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr
@@ -40,7 +40,7 @@ error: unresolved link to `Clone`
   --> $DIR/weird-syntax.rs:27:9
    |
 LL | /// [  `Clone ()`  ]
-   |         ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |         ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function
    |
 help: to link to the trait, prefix with `trait@`
    |
@@ -52,7 +52,7 @@ error: unresolved link to `Clone`
   --> $DIR/weird-syntax.rs:30:7
    |
 LL | /// [`Clone ()`  ]
-   |       ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |       ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function
    |
 help: to link to the trait, prefix with `trait@`
    |
@@ -64,7 +64,7 @@ error: unresolved link to `Clone`
   --> $DIR/weird-syntax.rs:33:9
    |
 LL | /// [  `Clone ()`]
-   |         ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |         ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function
    |
 help: to link to the trait, prefix with `trait@`
    |
@@ -76,7 +76,7 @@ error: unresolved link to `Clone`
   --> $DIR/weird-syntax.rs:36:9
    |
 LL | /// [```Clone ()```]
-   |         ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |         ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function
    |
 help: to link to the trait, prefix with `trait@`
    |
@@ -88,7 +88,7 @@ error: unresolved link to `Clone`
   --> $DIR/weird-syntax.rs:42:13
    |
 LL | /// [  ```  Clone ()  ```  ]
-   |             ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |             ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function
    |
 help: to link to the trait, prefix with `trait@`
    |
@@ -122,7 +122,7 @@ error: unresolved link to `Clone`
   --> $DIR/weird-syntax.rs:74:9
    |
 LL | /// [x][Clone()]
-   |         ^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |         ^^^^^^^ this link resolves to the trait `Clone`, which is not a function
    |
 help: to link to the trait, prefix with `trait@`
    |
@@ -134,7 +134,7 @@ error: unresolved link to `Clone`
   --> $DIR/weird-syntax.rs:77:9
    |
 LL | /// [x][Clone  ()]
-   |         ^^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |         ^^^^^^^^^ this link resolves to the trait `Clone`, which is not a function
    |
 help: to link to the trait, prefix with `trait@`
    |
@@ -176,7 +176,7 @@ error: unresolved link to `Clone`
   --> $DIR/weird-syntax.rs:97:9
    |
 LL | /// [w](Clone\(\))
-   |         ^^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |         ^^^^^^^^^ this link resolves to the trait `Clone`, which is not a function
    |
 help: to link to the trait, prefix with `trait@`
    |
@@ -188,7 +188,7 @@ error: unresolved link to `Clone`
   --> $DIR/weird-syntax.rs:103:9
    |
 LL | /// [w](Clone())
-   |         ^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |         ^^^^^^^ this link resolves to the trait `Clone`, which is not a function
    |
 help: to link to the trait, prefix with `trait@`
    |
@@ -256,7 +256,7 @@ error: unresolved link to `Clone`
   --> $DIR/weird-syntax.rs:132:9
    |
 LL | /// The [cln][] link here will produce a plain text suggestion
-   |         ^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace
+   |         ^^^^^ this link resolves to the trait `Clone`, which is not a function
    |
    = help: to link to the trait, prefix with `trait@`: trait@Clone
 
diff --git a/tests/rustdoc-ui/issues/issue-91713.stdout b/tests/rustdoc-ui/issues/issue-91713.stdout
index 1ea3dbfb59f..790e58b0df9 100644
--- a/tests/rustdoc-ui/issues/issue-91713.stdout
+++ b/tests/rustdoc-ui/issues/issue-91713.stdout
@@ -5,6 +5,7 @@ strip-aliased-non-local - strips all non-local private aliased items from the ou
        strip-private - strips all private items from a crate which cannot be seen externally, implies strip-priv-imports
   strip-priv-imports - strips all private import statements (`use`, `extern crate`) from a crate
    propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items
+ propagate-stability - propagates stability to child items
 collect-intra-doc-links - resolves intra-doc links
  collect-trait-impls - retrieves trait impls for items in the crate
 calculate-doc-coverage - counts the number of items with and without documentation
@@ -19,6 +20,7 @@ strip-aliased-non-local
   strip-priv-imports  (when --document-private-items)
 collect-intra-doc-links
    propagate-doc-cfg
+ propagate-stability
            run-lints
 
 Passes run with `--show-coverage`:
diff --git a/tests/rustdoc-ui/lints/check-attr.stderr b/tests/rustdoc-ui/lints/check-attr.stderr
index d640125ab51..e23806e0bab 100644
--- a/tests/rustdoc-ui/lints/check-attr.stderr
+++ b/tests/rustdoc-ui/lints/check-attr.stderr
@@ -10,8 +10,8 @@ LL | | /// boo
 LL | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `compile_fail`
-   = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
+   = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 note: the lint level is defined here
   --> $DIR/check-attr.rs:1:9
    |
@@ -30,8 +30,8 @@ LL | | /// boo
 LL | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `compile_fail`
-   = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
+   = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `comPile_fail`
   --> $DIR/check-attr.rs:3:1
@@ -45,8 +45,8 @@ LL | | /// boo
 LL | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `compile_fail`
-   = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
+   = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `should-panic`
   --> $DIR/check-attr.rs:13:1
@@ -60,8 +60,8 @@ LL | | /// boo
 LL | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `should_panic`
-   = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
+   = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `shouldpanic`
   --> $DIR/check-attr.rs:13:1
@@ -75,8 +75,8 @@ LL | | /// boo
 LL | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `should_panic`
-   = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
+   = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `sHould_panic`
   --> $DIR/check-attr.rs:13:1
@@ -90,8 +90,8 @@ LL | | /// boo
 LL | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `should_panic`
-   = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
+   = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `no-run`
   --> $DIR/check-attr.rs:23:1
@@ -105,8 +105,8 @@ LL | | /// boo
 LL | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `no_run`
-   = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
+   = help: use `no_run` to compile, but not run, the code sample during testing
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `norun`
   --> $DIR/check-attr.rs:23:1
@@ -120,8 +120,8 @@ LL | | /// boo
 LL | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `no_run`
-   = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
+   = help: use `no_run` to compile, but not run, the code sample during testing
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `no_Run`
   --> $DIR/check-attr.rs:23:1
@@ -135,8 +135,8 @@ LL | | /// boo
 LL | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `no_run`
-   = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
+   = help: use `no_run` to compile, but not run, the code sample during testing
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `test-harness`
   --> $DIR/check-attr.rs:33:1
@@ -150,8 +150,8 @@ LL | | /// boo
 LL | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `test_harness`
-   = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
+   = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `testharness`
   --> $DIR/check-attr.rs:33:1
@@ -165,8 +165,8 @@ LL | | /// boo
 LL | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `test_harness`
-   = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
+   = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `teSt_harness`
   --> $DIR/check-attr.rs:33:1
@@ -180,8 +180,8 @@ LL | | /// boo
 LL | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `test_harness`
-   = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
+   = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: unknown attribute `rust2018`
   --> $DIR/check-attr.rs:43:1
@@ -222,8 +222,8 @@ LL | | /// boo
 LL | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `should_panic`
-   = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
+   = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: aborting due to 15 previous errors
 
diff --git a/tests/rustdoc-ui/lints/check-fail.stderr b/tests/rustdoc-ui/lints/check-fail.stderr
index 99b01bac598..2eb9496e5dc 100644
--- a/tests/rustdoc-ui/lints/check-fail.stderr
+++ b/tests/rustdoc-ui/lints/check-fail.stderr
@@ -31,8 +31,8 @@ LL | | //! let x = 12;
 LL | | //! ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `test_harness`
-   = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
+   = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 note: the lint level is defined here
   --> $DIR/check-fail.rs:6:9
    |
@@ -51,8 +51,8 @@ LL | | /// let x = 12;
 LL | | /// ```
    | |_______^
    |
-   = help: there is an attribute with a similar name: `test_harness`
-   = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
+   = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function
+   = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust`
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/rustdoc/intra-doc/field.rs b/tests/rustdoc/intra-doc/field.rs
index ba6b320e560..e98419618e2 100644
--- a/tests/rustdoc/intra-doc/field.rs
+++ b/tests/rustdoc/intra-doc/field.rs
@@ -1,4 +1,24 @@
 //@ has field/index.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start'
 //@ has field/index.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found'
+//@ has field/index.html '//a[@href="struct.FieldAndMethod.html#structfield.x"]' 'x'
+//@ has field/index.html '//a[@href="enum.VariantAndMethod.html#variant.X"]' 'X'
 //! [start][std::ops::Range::start]
 //! [not_found][std::io::ErrorKind::NotFound]
+//! [x][field@crate::FieldAndMethod::x]
+//! [X][variant@crate::VariantAndMethod::X]
+
+pub struct FieldAndMethod {
+    pub x: i32,
+}
+
+impl FieldAndMethod {
+    pub fn x(&self) {}
+}
+
+pub enum VariantAndMethod {
+    X {},
+}
+
+impl VariantAndMethod {
+    fn X() {}
+}
diff --git a/tests/rustdoc/stability.rs b/tests/rustdoc/stability.rs
index de855b43ba5..fc72154cad8 100644
--- a/tests/rustdoc/stability.rs
+++ b/tests/rustdoc/stability.rs
@@ -25,28 +25,61 @@ pub struct ZzStable;
 
 #[unstable(feature = "unstable", issue = "none")]
 pub mod unstable {
-    //@ !hasraw stability/unstable/struct.Foo.html '//span[@class="since"]'
+    //@ !hasraw stability/unstable/struct.StableInUnstable.html \
+    //      '//span[@class="since"]'
     //@ has - '//div[@class="stab unstable"]' 'experimental'
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub struct Foo;
+    pub struct StableInUnstable;
+
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub mod stable_in_unstable {
+        //@ !hasraw stability/unstable/stable_in_unstable/struct.Inner.html \
+        //      '//span[@class="since"]'
+        //@ has - '//div[@class="stab unstable"]' 'experimental'
+        #[stable(feature = "rust1", since = "1.0.0")]
+        pub struct Inner;
+    }
 }
 
 #[stable(feature = "rust2", since = "2.2.2")]
 pub mod stable_later {
-    //@ has stability/stable_later/struct.Bar.html '//span[@class="since"]' '2.2.2'
+    //@ has stability/stable_later/struct.StableInLater.html \
+    //      '//span[@class="since"]' '2.2.2'
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub struct Bar;
+    pub struct StableInLater;
+
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub mod stable_in_later {
+        //@ has stability/stable_later/stable_in_later/struct.Inner.html \
+        //      '//span[@class="since"]' '2.2.2'
+        #[stable(feature = "rust1", since = "1.0.0")]
+        pub struct Inner;
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub mod stable_earlier {
-    //@ has stability/stable_earlier/struct.Foo.html '//span[@class="since"]' '1.0.0'
+    //@ has stability/stable_earlier/struct.StableInUnstable.html \
+    //      '//span[@class="since"]' '1.0.0'
+    #[doc(inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use crate::unstable::StableInUnstable;
+
+    //@ has stability/stable_earlier/stable_in_unstable/struct.Inner.html \
+    //      '//span[@class="since"]' '1.0.0'
+    #[doc(inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use crate::unstable::stable_in_unstable;
+
+    //@ has stability/stable_earlier/struct.StableInLater.html \
+    //      '//span[@class="since"]' '1.0.0'
     #[doc(inline)]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub use crate::unstable::Foo;
+    pub use crate::stable_later::StableInLater;
 
-    //@ has stability/stable_earlier/struct.Bar.html '//span[@class="since"]' '1.0.0'
+    //@ has stability/stable_earlier/stable_in_later/struct.Inner.html \
+    //      '//span[@class="since"]' '1.0.0'
     #[doc(inline)]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub use crate::stable_later::Bar;
+    pub use crate::stable_later::stable_in_later;
 }
diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs
index 7518ea902ec..5b7da7bb129 100644
--- a/tests/ui-fulldeps/stable-mir/check_abi.rs
+++ b/tests/ui-fulldeps/stable-mir/check_abi.rs
@@ -8,7 +8,6 @@
 
 #![feature(rustc_private)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 #![feature(ascii_char, ascii_char_variants)]
 
 extern crate rustc_hir;
diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs
index 7752ff51ac8..1e2f640f39f 100644
--- a/tests/ui-fulldeps/stable-mir/check_allocation.rs
+++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs
@@ -10,7 +10,6 @@
 
 #![feature(rustc_private)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 #![feature(ascii_char, ascii_char_variants)]
 
 extern crate rustc_hir;
diff --git a/tests/ui-fulldeps/stable-mir/check_attribute.rs b/tests/ui-fulldeps/stable-mir/check_attribute.rs
index be52853a479..131fd99ebaa 100644
--- a/tests/ui-fulldeps/stable-mir/check_attribute.rs
+++ b/tests/ui-fulldeps/stable-mir/check_attribute.rs
@@ -7,7 +7,6 @@
 //@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
 
 #![feature(rustc_private)]
-#![feature(control_flow_enum)]
 
 extern crate rustc_hir;
 #[macro_use]
diff --git a/tests/ui-fulldeps/stable-mir/check_def_ty.rs b/tests/ui-fulldeps/stable-mir/check_def_ty.rs
index 9f45b62d343..ec3cf1753e2 100644
--- a/tests/ui-fulldeps/stable-mir/check_def_ty.rs
+++ b/tests/ui-fulldeps/stable-mir/check_def_ty.rs
@@ -10,7 +10,6 @@
 
 #![feature(rustc_private)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 
 #[macro_use]
 extern crate rustc_smir;
diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs
index 5bb1053f187..3402b345818 100644
--- a/tests/ui-fulldeps/stable-mir/check_defs.rs
+++ b/tests/ui-fulldeps/stable-mir/check_defs.rs
@@ -9,7 +9,6 @@
 
 #![feature(rustc_private)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 
 #[macro_use]
 extern crate rustc_smir;
diff --git a/tests/ui-fulldeps/stable-mir/check_foreign.rs b/tests/ui-fulldeps/stable-mir/check_foreign.rs
index 06d2af4ac8a..4acbabbb6be 100644
--- a/tests/ui-fulldeps/stable-mir/check_foreign.rs
+++ b/tests/ui-fulldeps/stable-mir/check_foreign.rs
@@ -9,7 +9,6 @@
 
 #![feature(rustc_private)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 
 extern crate rustc_middle;
 #[macro_use]
diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs
index 68eb3c54593..7d63e202fa6 100644
--- a/tests/ui-fulldeps/stable-mir/check_instance.rs
+++ b/tests/ui-fulldeps/stable-mir/check_instance.rs
@@ -9,7 +9,6 @@
 
 #![feature(rustc_private)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 
 #[macro_use]
 extern crate rustc_smir;
diff --git a/tests/ui-fulldeps/stable-mir/check_item_kind.rs b/tests/ui-fulldeps/stable-mir/check_item_kind.rs
index 1d5b19304c1..91baa074c10 100644
--- a/tests/ui-fulldeps/stable-mir/check_item_kind.rs
+++ b/tests/ui-fulldeps/stable-mir/check_item_kind.rs
@@ -9,7 +9,6 @@
 
 #![feature(rustc_private)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 
 #[macro_use]
 extern crate rustc_smir;
diff --git a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs
index 5098547c2c8..8721f243587 100644
--- a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs
+++ b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs
@@ -9,7 +9,6 @@
 
 #![feature(rustc_private)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 
 #[macro_use]
 extern crate rustc_smir;
diff --git a/tests/ui-fulldeps/stable-mir/check_transform.rs b/tests/ui-fulldeps/stable-mir/check_transform.rs
index 1d3e4c6845b..40217b9aa95 100644
--- a/tests/ui-fulldeps/stable-mir/check_transform.rs
+++ b/tests/ui-fulldeps/stable-mir/check_transform.rs
@@ -8,7 +8,6 @@
 
 #![feature(rustc_private)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 #![feature(ascii_char, ascii_char_variants)]
 
 extern crate rustc_hir;
diff --git a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs
index 0b8cfcf27fd..0715e0cfc52 100644
--- a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs
+++ b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs
@@ -10,7 +10,6 @@
 
 #![feature(rustc_private)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 
 #[macro_use]
 extern crate rustc_smir;
diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs
index 4c9a8a665b8..6b458c5d923 100644
--- a/tests/ui-fulldeps/stable-mir/crate-info.rs
+++ b/tests/ui-fulldeps/stable-mir/crate-info.rs
@@ -9,7 +9,6 @@
 
 #![feature(rustc_private)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 
 extern crate rustc_hir;
 #[macro_use]
diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs
index d68e7d37950..a8bf4c1d399 100644
--- a/tests/ui-fulldeps/stable-mir/projections.rs
+++ b/tests/ui-fulldeps/stable-mir/projections.rs
@@ -9,7 +9,6 @@
 
 #![feature(rustc_private)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 
 extern crate rustc_hir;
 #[macro_use]
diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs
index 07f404fd471..6f5478c08bf 100644
--- a/tests/ui-fulldeps/stable-mir/smir_internal.rs
+++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs
@@ -10,7 +10,6 @@
 
 #![feature(rustc_private)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 
 #[macro_use]
 extern crate rustc_smir;
diff --git a/tests/ui-fulldeps/stable-mir/smir_serde.rs b/tests/ui-fulldeps/stable-mir/smir_serde.rs
index 957d840f7a2..7dbf892f9e4 100644
--- a/tests/ui-fulldeps/stable-mir/smir_serde.rs
+++ b/tests/ui-fulldeps/stable-mir/smir_serde.rs
@@ -9,7 +9,6 @@
 
 #![feature(rustc_private)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 
 #[macro_use]
 extern crate rustc_smir;
diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs
index ac428c80e0f..f1bc03781b9 100644
--- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs
+++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs
@@ -9,7 +9,6 @@
 
 #![feature(rustc_private)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 
 #[macro_use]
 extern crate rustc_smir;
diff --git a/tests/ui/abi/riscv32e-registers.riscv32e.stderr b/tests/ui/abi/riscv32e-registers.riscv32e.stderr
new file mode 100644
index 00000000000..e3894431eb4
--- /dev/null
+++ b/tests/ui/abi/riscv32e-registers.riscv32e.stderr
@@ -0,0 +1,194 @@
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:43:11
+   |
+LL |     asm!("li x16, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x16, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:46:11
+   |
+LL |     asm!("li x17, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x17, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:49:11
+   |
+LL |     asm!("li x18, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x18, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:52:11
+   |
+LL |     asm!("li x19, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x19, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:55:11
+   |
+LL |     asm!("li x20, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x20, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:58:11
+   |
+LL |     asm!("li x21, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x21, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:61:11
+   |
+LL |     asm!("li x22, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x22, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:64:11
+   |
+LL |     asm!("li x23, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x23, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:67:11
+   |
+LL |     asm!("li x24, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x24, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:70:11
+   |
+LL |     asm!("li x25, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x25, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:73:11
+   |
+LL |     asm!("li x26, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x26, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:76:11
+   |
+LL |     asm!("li x27, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x27, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:79:11
+   |
+LL |     asm!("li x28, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x28, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:82:11
+   |
+LL |     asm!("li x29, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x29, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:85:11
+   |
+LL |     asm!("li x30, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x30, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:88:11
+   |
+LL |     asm!("li x31, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x31, 0
+   |        ^
+
+error: aborting due to 16 previous errors
+
diff --git a/tests/ui/abi/riscv32e-registers.riscv32em.stderr b/tests/ui/abi/riscv32e-registers.riscv32em.stderr
new file mode 100644
index 00000000000..e3894431eb4
--- /dev/null
+++ b/tests/ui/abi/riscv32e-registers.riscv32em.stderr
@@ -0,0 +1,194 @@
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:43:11
+   |
+LL |     asm!("li x16, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x16, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:46:11
+   |
+LL |     asm!("li x17, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x17, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:49:11
+   |
+LL |     asm!("li x18, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x18, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:52:11
+   |
+LL |     asm!("li x19, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x19, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:55:11
+   |
+LL |     asm!("li x20, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x20, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:58:11
+   |
+LL |     asm!("li x21, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x21, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:61:11
+   |
+LL |     asm!("li x22, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x22, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:64:11
+   |
+LL |     asm!("li x23, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x23, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:67:11
+   |
+LL |     asm!("li x24, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x24, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:70:11
+   |
+LL |     asm!("li x25, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x25, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:73:11
+   |
+LL |     asm!("li x26, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x26, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:76:11
+   |
+LL |     asm!("li x27, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x27, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:79:11
+   |
+LL |     asm!("li x28, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x28, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:82:11
+   |
+LL |     asm!("li x29, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x29, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:85:11
+   |
+LL |     asm!("li x30, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x30, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:88:11
+   |
+LL |     asm!("li x31, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x31, 0
+   |        ^
+
+error: aborting due to 16 previous errors
+
diff --git a/tests/ui/abi/riscv32e-registers.riscv32emc.stderr b/tests/ui/abi/riscv32e-registers.riscv32emc.stderr
new file mode 100644
index 00000000000..e3894431eb4
--- /dev/null
+++ b/tests/ui/abi/riscv32e-registers.riscv32emc.stderr
@@ -0,0 +1,194 @@
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:43:11
+   |
+LL |     asm!("li x16, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x16, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:46:11
+   |
+LL |     asm!("li x17, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x17, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:49:11
+   |
+LL |     asm!("li x18, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x18, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:52:11
+   |
+LL |     asm!("li x19, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x19, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:55:11
+   |
+LL |     asm!("li x20, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x20, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:58:11
+   |
+LL |     asm!("li x21, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x21, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:61:11
+   |
+LL |     asm!("li x22, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x22, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:64:11
+   |
+LL |     asm!("li x23, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x23, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:67:11
+   |
+LL |     asm!("li x24, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x24, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:70:11
+   |
+LL |     asm!("li x25, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x25, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:73:11
+   |
+LL |     asm!("li x26, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x26, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:76:11
+   |
+LL |     asm!("li x27, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x27, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:79:11
+   |
+LL |     asm!("li x28, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x28, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:82:11
+   |
+LL |     asm!("li x29, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x29, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:85:11
+   |
+LL |     asm!("li x30, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x30, 0
+   |        ^
+
+error: invalid operand for instruction
+  --> $DIR/riscv32e-registers.rs:88:11
+   |
+LL |     asm!("li x31, 0");
+   |           ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:5
+   |
+LL |     li x31, 0
+   |        ^
+
+error: aborting due to 16 previous errors
+
diff --git a/tests/ui/abi/riscv32e-registers.rs b/tests/ui/abi/riscv32e-registers.rs
new file mode 100644
index 00000000000..714b0ee4633
--- /dev/null
+++ b/tests/ui/abi/riscv32e-registers.rs
@@ -0,0 +1,91 @@
+// Test that loads into registers x16..=x31 are never generated for riscv32{e,em,emc} targets
+//
+//@ build-fail
+//@ revisions: riscv32e riscv32em riscv32emc
+//
+//@ compile-flags: --crate-type=rlib
+//@ [riscv32e] needs-llvm-components: riscv
+//@ [riscv32e] compile-flags: --target=riscv32e-unknown-none-elf
+//@ [riscv32em] needs-llvm-components: riscv
+//@ [riscv32em] compile-flags: --target=riscv32em-unknown-none-elf
+//@ [riscv32emc] needs-llvm-components: riscv
+//@ [riscv32emc] compile-flags: --target=riscv32emc-unknown-none-elf
+
+#![no_core]
+#![feature(no_core, lang_items, rustc_attrs)]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+    () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+
+// Verify registers x1..=x15 are addressable on riscv32e, but registers x16..=x31 are not
+#[no_mangle]
+pub unsafe fn registers() {
+    asm!("li x1, 0");
+    asm!("li x2, 0");
+    asm!("li x3, 0");
+    asm!("li x4, 0");
+    asm!("li x5, 0");
+    asm!("li x6, 0");
+    asm!("li x7, 0");
+    asm!("li x8, 0");
+    asm!("li x9, 0");
+    asm!("li x10, 0");
+    asm!("li x11, 0");
+    asm!("li x12, 0");
+    asm!("li x13, 0");
+    asm!("li x14, 0");
+    asm!("li x15, 0");
+    asm!("li x16, 0");
+    //~^ ERROR invalid operand for instruction
+    //~| NOTE instantiated into assembly here
+    asm!("li x17, 0");
+    //~^ ERROR invalid operand for instruction
+    //~| NOTE instantiated into assembly here
+    asm!("li x18, 0");
+    //~^ ERROR invalid operand for instruction
+    //~| NOTE instantiated into assembly here
+    asm!("li x19, 0");
+    //~^ ERROR invalid operand for instruction
+    //~| NOTE instantiated into assembly here
+    asm!("li x20, 0");
+    //~^ ERROR invalid operand for instruction
+    //~| NOTE instantiated into assembly here
+    asm!("li x21, 0");
+    //~^ ERROR invalid operand for instruction
+    //~| NOTE instantiated into assembly here
+    asm!("li x22, 0");
+    //~^ ERROR invalid operand for instruction
+    //~| NOTE instantiated into assembly here
+    asm!("li x23, 0");
+    //~^ ERROR invalid operand for instruction
+    //~| NOTE instantiated into assembly here
+    asm!("li x24, 0");
+    //~^ ERROR invalid operand for instruction
+    //~| NOTE instantiated into assembly here
+    asm!("li x25, 0");
+    //~^ ERROR invalid operand for instruction
+    //~| NOTE instantiated into assembly here
+    asm!("li x26, 0");
+    //~^ ERROR invalid operand for instruction
+    //~| NOTE instantiated into assembly here
+    asm!("li x27, 0");
+    //~^ ERROR invalid operand for instruction
+    //~| NOTE instantiated into assembly here
+    asm!("li x28, 0");
+    //~^ ERROR invalid operand for instruction
+    //~| NOTE instantiated into assembly here
+    asm!("li x29, 0");
+    //~^ ERROR invalid operand for instruction
+    //~| NOTE instantiated into assembly here
+    asm!("li x30, 0");
+    //~^ ERROR invalid operand for instruction
+    //~| NOTE instantiated into assembly here
+    asm!("li x31, 0");
+    //~^ ERROR invalid operand for instruction
+    //~| NOTE instantiated into assembly here
+}
diff --git a/tests/ui/asm/aarch64/type-check-4.rs b/tests/ui/asm/aarch64/type-check-4.rs
deleted file mode 100644
index c24567bd5b0..00000000000
--- a/tests/ui/asm/aarch64/type-check-4.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-//@ only-aarch64
-//@ build-fail
-
-use std::arch::global_asm;
-
-fn main() {}
-
-// Constants must be... constant
-
-static mut S: i32 = 1;
-const fn const_foo(x: i32) -> i32 {
-    x
-}
-const fn const_bar<T>(x: T) -> T {
-    x
-}
-global_asm!("{}", const unsafe { S });
-//~^ ERROR: evaluation of constant value failed
-//~| mutable global memory
-global_asm!("{}", const const_foo(0));
-global_asm!("{}", const const_foo(unsafe { S }));
-//~^ ERROR: evaluation of constant value failed
-//~| mutable global memory
-global_asm!("{}", const const_bar(0));
-global_asm!("{}", const const_bar(unsafe { S }));
-//~^ ERROR: evaluation of constant value failed
-//~| mutable global memory
diff --git a/tests/ui/asm/aarch64/type-check-4.stderr b/tests/ui/asm/aarch64/type-check-4.stderr
deleted file mode 100644
index 8c22dfcdb5e..00000000000
--- a/tests/ui/asm/aarch64/type-check-4.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0080]: evaluation of constant value failed
-  --> $DIR/type-check-4.rs:17:34
-   |
-LL | global_asm!("{}", const unsafe { S });
-   |                                  ^ constant accesses mutable global memory
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/type-check-4.rs:21:44
-   |
-LL | global_asm!("{}", const const_foo(unsafe { S }));
-   |                                            ^ constant accesses mutable global memory
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/type-check-4.rs:25:44
-   |
-LL | global_asm!("{}", const const_bar(unsafe { S }));
-   |                                            ^ constant accesses mutable global memory
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/asm/const-error.rs b/tests/ui/asm/const-error.rs
index 40d0590c33e..8c722906284 100644
--- a/tests/ui/asm/const-error.rs
+++ b/tests/ui/asm/const-error.rs
@@ -1,14 +1,16 @@
 //@ only-x86_64
 //@ needs-asm-support
+//@ check-pass
 
-// Test to make sure that we emit const errors eagerly for inline asm
+// Test to make sure that we emit const errors late for inline asm,
+// which is consistent with inline const blocks.
 
 use std::arch::asm;
 
 fn test<T>() {
     unsafe {
+        // No error here, as this does not get monomorphized.
         asm!("/* {} */", const 1 / 0);
-        //~^ ERROR evaluation of
     }
 }
 
diff --git a/tests/ui/asm/const-error.stderr b/tests/ui/asm/const-error.stderr
deleted file mode 100644
index 02e54457e89..00000000000
--- a/tests/ui/asm/const-error.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0080]: evaluation of `test::<T>::{constant#0}` failed
-  --> $DIR/const-error.rs:10:32
-   |
-LL |         asm!("/* {} */", const 1 / 0);
-   |                                ^^^^^ attempt to divide `1_i32` by zero
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/asm/naked-functions-ffi.rs b/tests/ui/asm/naked-functions-ffi.rs
index 93d23885b13..b78d1e6a0d1 100644
--- a/tests/ui/asm/naked-functions-ffi.rs
+++ b/tests/ui/asm/naked-functions-ffi.rs
@@ -3,13 +3,13 @@
 #![feature(naked_functions)]
 #![crate_type = "lib"]
 
-use std::arch::asm;
+use std::arch::naked_asm;
 
 #[naked]
 pub extern "C" fn naked(p: char) -> u128 {
     //~^ WARN uses type `char`
     //~| WARN uses type `u128`
     unsafe {
-        asm!("", options(noreturn));
+        naked_asm!("");
     }
 }
diff --git a/tests/ui/asm/naked-functions-instruction-set.rs b/tests/ui/asm/naked-functions-instruction-set.rs
index b81b65cff74..37c7b52c191 100644
--- a/tests/ui/asm/naked-functions-instruction-set.rs
+++ b/tests/ui/asm/naked-functions-instruction-set.rs
@@ -8,7 +8,7 @@
 #![no_core]
 
 #[rustc_builtin_macro]
-macro_rules! asm {
+macro_rules! naked_asm {
     () => {};
 }
 
@@ -19,12 +19,12 @@ trait Sized {}
 #[naked]
 #[instruction_set(arm::t32)]
 unsafe extern "C" fn test_thumb() {
-    asm!("bx lr", options(noreturn));
+    naked_asm!("bx lr");
 }
 
 #[no_mangle]
 #[naked]
 #[instruction_set(arm::t32)]
 unsafe extern "C" fn test_arm() {
-    asm!("bx lr", options(noreturn));
+    naked_asm!("bx lr");
 }
diff --git a/tests/ui/asm/naked-functions-testattrs.rs b/tests/ui/asm/naked-functions-testattrs.rs
index 12943ac0378..7e373270e9f 100644
--- a/tests/ui/asm/naked-functions-testattrs.rs
+++ b/tests/ui/asm/naked-functions-testattrs.rs
@@ -6,13 +6,13 @@
 #![feature(test)]
 #![crate_type = "lib"]
 
-use std::arch::asm;
+use std::arch::naked_asm;
 
 #[test]
 #[naked]
 //~^ ERROR [E0736]
 fn test_naked() {
-    unsafe { asm!("", options(noreturn)) };
+    unsafe { naked_asm!("") };
 }
 
 #[should_panic]
@@ -20,7 +20,7 @@ fn test_naked() {
 #[naked]
 //~^ ERROR [E0736]
 fn test_naked_should_panic() {
-    unsafe { asm!("", options(noreturn)) };
+    unsafe { naked_asm!("") };
 }
 
 #[ignore]
@@ -28,12 +28,12 @@ fn test_naked_should_panic() {
 #[naked]
 //~^ ERROR [E0736]
 fn test_naked_ignore() {
-    unsafe { asm!("", options(noreturn)) };
+    unsafe { naked_asm!("") };
 }
 
 #[bench]
 #[naked]
 //~^ ERROR [E0736]
 fn bench_naked() {
-    unsafe { asm!("", options(noreturn)) };
+    unsafe { naked_asm!("") };
 }
diff --git a/tests/ui/asm/naked-functions-unused.aarch64.stderr b/tests/ui/asm/naked-functions-unused.aarch64.stderr
index 8d3c300e058..ea63ced1aab 100644
--- a/tests/ui/asm/naked-functions-unused.aarch64.stderr
+++ b/tests/ui/asm/naked-functions-unused.aarch64.stderr
@@ -18,49 +18,49 @@ LL |     pub extern "C" fn function(a: usize, b: usize) -> usize {
    |                                          ^ help: if this is intentional, prefix it with an underscore: `_b`
 
 error: unused variable: `a`
-  --> $DIR/naked-functions-unused.rs:26:38
+  --> $DIR/naked-functions-unused.rs:28:38
    |
 LL |         pub extern "C" fn associated(a: usize, b: usize) -> usize {
    |                                      ^ help: if this is intentional, prefix it with an underscore: `_a`
 
 error: unused variable: `b`
-  --> $DIR/naked-functions-unused.rs:26:48
+  --> $DIR/naked-functions-unused.rs:28:48
    |
 LL |         pub extern "C" fn associated(a: usize, b: usize) -> usize {
    |                                                ^ help: if this is intentional, prefix it with an underscore: `_b`
 
 error: unused variable: `a`
-  --> $DIR/naked-functions-unused.rs:32:41
+  --> $DIR/naked-functions-unused.rs:36:41
    |
 LL |         pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
    |                                         ^ help: if this is intentional, prefix it with an underscore: `_a`
 
 error: unused variable: `b`
-  --> $DIR/naked-functions-unused.rs:32:51
+  --> $DIR/naked-functions-unused.rs:36:51
    |
 LL |         pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
    |                                                   ^ help: if this is intentional, prefix it with an underscore: `_b`
 
 error: unused variable: `a`
-  --> $DIR/naked-functions-unused.rs:40:40
+  --> $DIR/naked-functions-unused.rs:46:40
    |
 LL |         extern "C" fn trait_associated(a: usize, b: usize) -> usize {
    |                                        ^ help: if this is intentional, prefix it with an underscore: `_a`
 
 error: unused variable: `b`
-  --> $DIR/naked-functions-unused.rs:40:50
+  --> $DIR/naked-functions-unused.rs:46:50
    |
 LL |         extern "C" fn trait_associated(a: usize, b: usize) -> usize {
    |                                                  ^ help: if this is intentional, prefix it with an underscore: `_b`
 
 error: unused variable: `a`
-  --> $DIR/naked-functions-unused.rs:46:43
+  --> $DIR/naked-functions-unused.rs:54:43
    |
 LL |         extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
    |                                           ^ help: if this is intentional, prefix it with an underscore: `_a`
 
 error: unused variable: `b`
-  --> $DIR/naked-functions-unused.rs:46:53
+  --> $DIR/naked-functions-unused.rs:54:53
    |
 LL |         extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
    |                                                     ^ help: if this is intentional, prefix it with an underscore: `_b`
diff --git a/tests/ui/asm/naked-functions-unused.rs b/tests/ui/asm/naked-functions-unused.rs
index 745d30e6a84..c27037819a4 100644
--- a/tests/ui/asm/naked-functions-unused.rs
+++ b/tests/ui/asm/naked-functions-unused.rs
@@ -17,7 +17,9 @@ pub mod normal {
     pub extern "C" fn function(a: usize, b: usize) -> usize {
         //~^ ERROR unused variable: `a`
         //~| ERROR unused variable: `b`
-        unsafe { asm!("", options(noreturn)); }
+        unsafe {
+            asm!("", options(noreturn));
+        }
     }
 
     pub struct Normal;
@@ -26,13 +28,17 @@ pub mod normal {
         pub extern "C" fn associated(a: usize, b: usize) -> usize {
             //~^ ERROR unused variable: `a`
             //~| ERROR unused variable: `b`
-            unsafe { asm!("", options(noreturn)); }
+            unsafe {
+                asm!("", options(noreturn));
+            }
         }
 
         pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
             //~^ ERROR unused variable: `a`
             //~| ERROR unused variable: `b`
-            unsafe { asm!("", options(noreturn)); }
+            unsafe {
+                asm!("", options(noreturn));
+            }
         }
     }
 
@@ -40,23 +46,29 @@ pub mod normal {
         extern "C" fn trait_associated(a: usize, b: usize) -> usize {
             //~^ ERROR unused variable: `a`
             //~| ERROR unused variable: `b`
-            unsafe { asm!("", options(noreturn)); }
+            unsafe {
+                asm!("", options(noreturn));
+            }
         }
 
         extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
             //~^ ERROR unused variable: `a`
             //~| ERROR unused variable: `b`
-            unsafe { asm!("", options(noreturn)); }
+            unsafe {
+                asm!("", options(noreturn));
+            }
         }
     }
 }
 
 pub mod naked {
-    use std::arch::asm;
+    use std::arch::naked_asm;
 
     #[naked]
     pub extern "C" fn function(a: usize, b: usize) -> usize {
-        unsafe { asm!("", options(noreturn)); }
+        unsafe {
+            naked_asm!("");
+        }
     }
 
     pub struct Naked;
@@ -64,24 +76,32 @@ pub mod naked {
     impl Naked {
         #[naked]
         pub extern "C" fn associated(a: usize, b: usize) -> usize {
-            unsafe { asm!("", options(noreturn)); }
+            unsafe {
+                naked_asm!("");
+            }
         }
 
         #[naked]
         pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
-            unsafe { asm!("", options(noreturn)); }
+            unsafe {
+                naked_asm!("");
+            }
         }
     }
 
     impl super::Trait for Naked {
         #[naked]
         extern "C" fn trait_associated(a: usize, b: usize) -> usize {
-            unsafe { asm!("", options(noreturn)); }
+            unsafe {
+                naked_asm!("");
+            }
         }
 
         #[naked]
         extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
-            unsafe { asm!("", options(noreturn)); }
+            unsafe {
+                naked_asm!("");
+            }
         }
     }
 }
diff --git a/tests/ui/asm/naked-functions-unused.x86_64.stderr b/tests/ui/asm/naked-functions-unused.x86_64.stderr
index 8d3c300e058..ea63ced1aab 100644
--- a/tests/ui/asm/naked-functions-unused.x86_64.stderr
+++ b/tests/ui/asm/naked-functions-unused.x86_64.stderr
@@ -18,49 +18,49 @@ LL |     pub extern "C" fn function(a: usize, b: usize) -> usize {
    |                                          ^ help: if this is intentional, prefix it with an underscore: `_b`
 
 error: unused variable: `a`
-  --> $DIR/naked-functions-unused.rs:26:38
+  --> $DIR/naked-functions-unused.rs:28:38
    |
 LL |         pub extern "C" fn associated(a: usize, b: usize) -> usize {
    |                                      ^ help: if this is intentional, prefix it with an underscore: `_a`
 
 error: unused variable: `b`
-  --> $DIR/naked-functions-unused.rs:26:48
+  --> $DIR/naked-functions-unused.rs:28:48
    |
 LL |         pub extern "C" fn associated(a: usize, b: usize) -> usize {
    |                                                ^ help: if this is intentional, prefix it with an underscore: `_b`
 
 error: unused variable: `a`
-  --> $DIR/naked-functions-unused.rs:32:41
+  --> $DIR/naked-functions-unused.rs:36:41
    |
 LL |         pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
    |                                         ^ help: if this is intentional, prefix it with an underscore: `_a`
 
 error: unused variable: `b`
-  --> $DIR/naked-functions-unused.rs:32:51
+  --> $DIR/naked-functions-unused.rs:36:51
    |
 LL |         pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
    |                                                   ^ help: if this is intentional, prefix it with an underscore: `_b`
 
 error: unused variable: `a`
-  --> $DIR/naked-functions-unused.rs:40:40
+  --> $DIR/naked-functions-unused.rs:46:40
    |
 LL |         extern "C" fn trait_associated(a: usize, b: usize) -> usize {
    |                                        ^ help: if this is intentional, prefix it with an underscore: `_a`
 
 error: unused variable: `b`
-  --> $DIR/naked-functions-unused.rs:40:50
+  --> $DIR/naked-functions-unused.rs:46:50
    |
 LL |         extern "C" fn trait_associated(a: usize, b: usize) -> usize {
    |                                                  ^ help: if this is intentional, prefix it with an underscore: `_b`
 
 error: unused variable: `a`
-  --> $DIR/naked-functions-unused.rs:46:43
+  --> $DIR/naked-functions-unused.rs:54:43
    |
 LL |         extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
    |                                           ^ help: if this is intentional, prefix it with an underscore: `_a`
 
 error: unused variable: `b`
-  --> $DIR/naked-functions-unused.rs:46:53
+  --> $DIR/naked-functions-unused.rs:54:53
    |
 LL |         extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
    |                                                     ^ help: if this is intentional, prefix it with an underscore: `_b`
diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs
index 116a84506c5..5c58f1498cc 100644
--- a/tests/ui/asm/naked-functions.rs
+++ b/tests/ui/asm/naked-functions.rs
@@ -6,7 +6,13 @@
 #![feature(asm_unwind, linkage)]
 #![crate_type = "lib"]
 
-use std::arch::asm;
+use std::arch::{asm, naked_asm};
+
+#[naked]
+pub unsafe extern "C" fn inline_asm_macro() {
+    asm!("", options(raw));
+    //~^ERROR the `asm!` macro is not allowed in naked functions
+}
 
 #[repr(C)]
 pub struct P {
@@ -25,12 +31,12 @@ pub unsafe extern "C" fn patterns(
     P { x, y }: P,
     //~^ ERROR patterns not allowed in naked function parameters
 ) {
-    asm!("", options(noreturn))
+    naked_asm!("")
 }
 
 #[naked]
 pub unsafe extern "C" fn inc(a: u32) -> u32 {
-    //~^ ERROR naked functions must contain a single asm block
+    //~^ ERROR naked functions must contain a single `naked_asm!` invocation
     a + 1
     //~^ ERROR referencing function parameters is not allowed in naked functions
 }
@@ -38,20 +44,19 @@ pub unsafe extern "C" fn inc(a: u32) -> u32 {
 #[naked]
 #[allow(asm_sub_register)]
 pub unsafe extern "C" fn inc_asm(a: u32) -> u32 {
-    asm!("/* {0} */", in(reg) a, options(noreturn));
-    //~^ ERROR referencing function parameters is not allowed in naked functions
-    //~| ERROR only `const` and `sym` operands are supported in naked functions
+    naked_asm!("/* {0} */", in(reg) a)
+    //~^ ERROR the `in` operand cannot be used with `naked_asm!`
 }
 
 #[naked]
 pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
-    //~^ ERROR naked functions must contain a single asm block
+    //~^ ERROR naked functions must contain a single `naked_asm!` invocation
     (|| a + 1)()
 }
 
 #[naked]
 pub unsafe extern "C" fn unsupported_operands() {
-    //~^ ERROR naked functions must contain a single asm block
+    //~^ ERROR naked functions must contain a single `naked_asm!` invocation
     let mut a = 0usize;
     let mut b = 0usize;
     let mut c = 0usize;
@@ -59,10 +64,9 @@ pub unsafe extern "C" fn unsupported_operands() {
     let mut e = 0usize;
     const F: usize = 0usize;
     static G: usize = 0usize;
-    asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
-         //~^ ERROR asm in naked functions must use `noreturn` option
+    naked_asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
          in(reg) a,
-         //~^ ERROR only `const` and `sym` operands are supported in naked functions
+         //~^ ERROR the `in` operand cannot be used with `naked_asm!`
          inlateout(reg) b,
          inout(reg) c,
          lateout(reg) d,
@@ -74,27 +78,23 @@ pub unsafe extern "C" fn unsupported_operands() {
 
 #[naked]
 pub extern "C" fn missing_assembly() {
-    //~^ ERROR naked functions must contain a single asm block
+    //~^ ERROR naked functions must contain a single `naked_asm!` invocation
 }
 
 #[naked]
 pub extern "C" fn too_many_asm_blocks() {
-    //~^ ERROR naked functions must contain a single asm block
+    //~^ ERROR naked functions must contain a single `naked_asm!` invocation
     unsafe {
-        asm!("");
-        //~^ ERROR asm in naked functions must use `noreturn` option
-        asm!("");
-        //~^ ERROR asm in naked functions must use `noreturn` option
-        asm!("");
-        //~^ ERROR asm in naked functions must use `noreturn` option
-        asm!("", options(noreturn));
+        naked_asm!("", options(noreturn));
+        //~^ ERROR the `noreturn` option cannot be used with `naked_asm!`
+        naked_asm!("");
     }
 }
 
 pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
     #[naked]
     pub extern "C" fn inner(y: usize) -> usize {
-        //~^ ERROR naked functions must contain a single asm block
+        //~^ ERROR naked functions must contain a single `naked_asm!` invocation
         *&y
         //~^ ERROR referencing function parameters is not allowed in naked functions
     }
@@ -103,40 +103,41 @@ pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
 
 #[naked]
 unsafe extern "C" fn invalid_options() {
-    asm!("", options(nomem, preserves_flags, noreturn));
-    //~^ ERROR asm options unsupported in naked functions: `nomem`, `preserves_flags`
+    naked_asm!("", options(nomem, preserves_flags));
+    //~^ ERROR the `nomem` option cannot be used with `naked_asm!`
+    //~| ERROR the `preserves_flags` option cannot be used with `naked_asm!`
 }
 
 #[naked]
 unsafe extern "C" fn invalid_options_continued() {
-    asm!("", options(readonly, nostack), options(pure));
-    //~^ ERROR asm with the `pure` option must have at least one output
-    //~| ERROR asm options unsupported in naked functions: `pure`, `readonly`, `nostack`
-    //~| ERROR asm in naked functions must use `noreturn` option
+    naked_asm!("", options(readonly, nostack), options(pure));
+    //~^ ERROR the `readonly` option cannot be used with `naked_asm!`
+    //~| ERROR the `nostack` option cannot be used with `naked_asm!`
+    //~| ERROR the `pure` option cannot be used with `naked_asm!`
 }
 
 #[naked]
 unsafe extern "C" fn invalid_may_unwind() {
-    asm!("", options(noreturn, may_unwind));
-    //~^ ERROR asm options unsupported in naked functions: `may_unwind`
+    naked_asm!("", options(may_unwind));
+    //~^ ERROR the `may_unwind` option cannot be used with `naked_asm!`
 }
 
 #[naked]
 pub unsafe fn default_abi() {
     //~^ WARN Rust ABI is unsupported in naked functions
-    asm!("", options(noreturn));
+    naked_asm!("");
 }
 
 #[naked]
 pub unsafe fn rust_abi() {
     //~^ WARN Rust ABI is unsupported in naked functions
-    asm!("", options(noreturn));
+    naked_asm!("");
 }
 
 #[naked]
 pub extern "C" fn valid_a<T>() -> T {
     unsafe {
-        asm!("", options(noreturn));
+        naked_asm!("");
     }
 }
 
@@ -145,7 +146,7 @@ pub extern "C" fn valid_b() {
     unsafe {
         {
             {
-                asm!("", options(noreturn));
+                naked_asm!("");
             };
         };
     }
@@ -153,13 +154,13 @@ pub extern "C" fn valid_b() {
 
 #[naked]
 pub unsafe extern "C" fn valid_c() {
-    asm!("", options(noreturn));
+    naked_asm!("");
 }
 
 #[cfg(target_arch = "x86_64")]
 #[naked]
 pub unsafe extern "C" fn valid_att_syntax() {
-    asm!("", options(noreturn, att_syntax));
+    naked_asm!("", options(att_syntax));
 }
 
 #[naked]
@@ -173,12 +174,12 @@ pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 {
 pub unsafe extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 {
     compile_error!("this is a user specified error");
     //~^ ERROR this is a user specified error
-    asm!("", options(noreturn))
+    naked_asm!("")
 }
 
 #[naked]
 pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 {
-    asm!(invalid_syntax)
+    naked_asm!(invalid_syntax)
     //~^ ERROR asm template must be a string literal
 }
 
@@ -186,7 +187,7 @@ pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 {
 #[cfg_attr(target_pointer_width = "64", no_mangle)]
 #[naked]
 pub unsafe extern "C" fn compatible_cfg_attributes() {
-    asm!("", options(noreturn, att_syntax));
+    naked_asm!("", options(att_syntax));
 }
 
 #[allow(dead_code)]
@@ -195,25 +196,24 @@ pub unsafe extern "C" fn compatible_cfg_attributes() {
 #[forbid(dead_code)]
 #[naked]
 pub unsafe extern "C" fn compatible_diagnostic_attributes() {
-    asm!("", options(noreturn, raw));
+    naked_asm!("", options(raw));
 }
 
 #[deprecated = "test"]
 #[naked]
 pub unsafe extern "C" fn compatible_deprecated_attributes() {
-    asm!("", options(noreturn, raw));
+    naked_asm!("", options(raw));
 }
 
 #[cfg(target_arch = "x86_64")]
 #[must_use]
 #[naked]
 pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 {
-    asm!(
+    naked_asm!(
         "
         mov rax, 42
         ret
         ",
-        options(noreturn)
     )
 }
 
@@ -222,20 +222,20 @@ pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 {
 #[no_mangle]
 #[naked]
 pub unsafe extern "C" fn compatible_ffi_attributes_1() {
-    asm!("", options(noreturn, raw));
+    naked_asm!("", options(raw));
 }
 
 #[cold]
 #[naked]
 pub unsafe extern "C" fn compatible_codegen_attributes() {
-    asm!("", options(noreturn, raw));
+    naked_asm!("", options(raw));
 }
 
 #[cfg(target_arch = "x86_64")]
 #[target_feature(enable = "sse2")]
 #[naked]
 pub unsafe extern "C" fn compatible_target_feature() {
-    asm!("", options(noreturn));
+    naked_asm!("");
 }
 
 #[doc = "foo bar baz"]
@@ -244,11 +244,11 @@ pub unsafe extern "C" fn compatible_target_feature() {
 #[doc(alias = "ADocAlias")]
 #[naked]
 pub unsafe extern "C" fn compatible_doc_attributes() {
-    asm!("", options(noreturn, raw));
+    naked_asm!("", options(raw));
 }
 
 #[linkage = "external"]
 #[naked]
 pub unsafe extern "C" fn compatible_linkage() {
-    asm!("", options(noreturn, raw));
+    naked_asm!("", options(raw));
 }
diff --git a/tests/ui/asm/naked-functions.stderr b/tests/ui/asm/naked-functions.stderr
index 93c02e2fbef..0898f3620f2 100644
--- a/tests/ui/asm/naked-functions.stderr
+++ b/tests/ui/asm/naked-functions.stderr
@@ -1,193 +1,162 @@
-error: asm with the `pure` option must have at least one output
-  --> $DIR/naked-functions.rs:112:14
+error: the `in` operand cannot be used with `naked_asm!`
+  --> $DIR/naked-functions.rs:47:29
    |
-LL |     asm!("", options(readonly, nostack), options(pure));
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^
+LL |     naked_asm!("/* {0} */", in(reg) a)
+   |                             ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it
+
+error: the `in` operand cannot be used with `naked_asm!`
+  --> $DIR/naked-functions.rs:68:10
+   |
+LL |          in(reg) a,
+   |          ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it
+
+error: the `noreturn` option cannot be used with `naked_asm!`
+  --> $DIR/naked-functions.rs:88:32
+   |
+LL |         naked_asm!("", options(noreturn));
+   |                                ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly
+
+error: the `nomem` option cannot be used with `naked_asm!`
+  --> $DIR/naked-functions.rs:106:28
+   |
+LL |     naked_asm!("", options(nomem, preserves_flags));
+   |                            ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly
+
+error: the `preserves_flags` option cannot be used with `naked_asm!`
+  --> $DIR/naked-functions.rs:106:35
+   |
+LL |     naked_asm!("", options(nomem, preserves_flags));
+   |                                   ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly
+
+error: the `readonly` option cannot be used with `naked_asm!`
+  --> $DIR/naked-functions.rs:113:28
+   |
+LL |     naked_asm!("", options(readonly, nostack), options(pure));
+   |                            ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly
+
+error: the `nostack` option cannot be used with `naked_asm!`
+  --> $DIR/naked-functions.rs:113:38
+   |
+LL |     naked_asm!("", options(readonly, nostack), options(pure));
+   |                                      ^^^^^^^ the `nostack` option is not meaningful for global-scoped inline assembly
+
+error: the `pure` option cannot be used with `naked_asm!`
+  --> $DIR/naked-functions.rs:113:56
+   |
+LL |     naked_asm!("", options(readonly, nostack), options(pure));
+   |                                                        ^^^^ the `pure` option is not meaningful for global-scoped inline assembly
+
+error: the `may_unwind` option cannot be used with `naked_asm!`
+  --> $DIR/naked-functions.rs:121:28
+   |
+LL |     naked_asm!("", options(may_unwind));
+   |                            ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly
 
 error: this is a user specified error
-  --> $DIR/naked-functions.rs:168:5
+  --> $DIR/naked-functions.rs:169:5
    |
 LL |     compile_error!("this is a user specified error")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this is a user specified error
-  --> $DIR/naked-functions.rs:174:5
+  --> $DIR/naked-functions.rs:175:5
    |
 LL |     compile_error!("this is a user specified error");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: asm template must be a string literal
-  --> $DIR/naked-functions.rs:181:10
+  --> $DIR/naked-functions.rs:182:16
    |
-LL |     asm!(invalid_syntax)
-   |          ^^^^^^^^^^^^^^
+LL |     naked_asm!(invalid_syntax)
+   |                ^^^^^^^^^^^^^^
+
+error[E0787]: the `asm!` macro is not allowed in naked functions
+  --> $DIR/naked-functions.rs:13:5
+   |
+LL |     asm!("", options(raw));
+   |     ^^^^^^^^^^^^^^^^^^^^^^ consider using the `naked_asm!` macro instead
 
 error: patterns not allowed in naked function parameters
-  --> $DIR/naked-functions.rs:19:5
+  --> $DIR/naked-functions.rs:25:5
    |
 LL |     mut a: u32,
    |     ^^^^^
 
 error: patterns not allowed in naked function parameters
-  --> $DIR/naked-functions.rs:21:5
+  --> $DIR/naked-functions.rs:27:5
    |
 LL |     &b: &i32,
    |     ^^
 
 error: patterns not allowed in naked function parameters
-  --> $DIR/naked-functions.rs:23:6
+  --> $DIR/naked-functions.rs:29:6
    |
 LL |     (None | Some(_)): Option<std::ptr::NonNull<u8>>,
    |      ^^^^^^^^^^^^^^
 
 error: patterns not allowed in naked function parameters
-  --> $DIR/naked-functions.rs:25:5
+  --> $DIR/naked-functions.rs:31:5
    |
 LL |     P { x, y }: P,
    |     ^^^^^^^^^^
 
 error: referencing function parameters is not allowed in naked functions
-  --> $DIR/naked-functions.rs:34:5
+  --> $DIR/naked-functions.rs:40:5
    |
 LL |     a + 1
    |     ^
    |
    = help: follow the calling convention in asm block to use parameters
 
-error[E0787]: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:32:1
+error[E0787]: naked functions must contain a single `naked_asm!` invocation
+  --> $DIR/naked-functions.rs:38:1
    |
 LL | pub unsafe extern "C" fn inc(a: u32) -> u32 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL |
 LL |     a + 1
-   |     ----- non-asm is unsupported in naked functions
-
-error: referencing function parameters is not allowed in naked functions
-  --> $DIR/naked-functions.rs:41:31
-   |
-LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
-   |                               ^
-   |
-   = help: follow the calling convention in asm block to use parameters
-
-error[E0787]: only `const` and `sym` operands are supported in naked functions
-  --> $DIR/naked-functions.rs:41:23
-   |
-LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
-   |                       ^^^^^^^^^
+   |     ----- not allowed in naked functions
 
-error[E0787]: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:47:1
+error[E0787]: naked functions must contain a single `naked_asm!` invocation
+  --> $DIR/naked-functions.rs:52:1
    |
 LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL |
 LL |     (|| a + 1)()
-   |     ------------ non-asm is unsupported in naked functions
+   |     ------------ not allowed in naked functions
 
-error[E0787]: only `const` and `sym` operands are supported in naked functions
-  --> $DIR/naked-functions.rs:64:10
-   |
-LL |          in(reg) a,
-   |          ^^^^^^^^^
-LL |
-LL |          inlateout(reg) b,
-   |          ^^^^^^^^^^^^^^^^
-LL |          inout(reg) c,
-   |          ^^^^^^^^^^^^
-LL |          lateout(reg) d,
-   |          ^^^^^^^^^^^^^^
-LL |          out(reg) e,
-   |          ^^^^^^^^^^
-
-error[E0787]: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:62:5
-   |
-LL | /     asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
-LL | |
-LL | |          in(reg) a,
-LL | |
-...  |
-LL | |          sym G,
-LL | |     );
-   | |_____^
-   |
-help: consider specifying that the asm block is responsible for returning from the function
-   |
-LL |          sym G, options(noreturn),
-   |               +++++++++++++++++++
-
-error[E0787]: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:53:1
+error[E0787]: naked functions must contain a single `naked_asm!` invocation
+  --> $DIR/naked-functions.rs:58:1
    |
 LL | pub unsafe extern "C" fn unsupported_operands() {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL |
 LL |     let mut a = 0usize;
-   |     ------------------- non-asm is unsupported in naked functions
+   |     ------------------- not allowed in naked functions
 LL |     let mut b = 0usize;
-   |     ------------------- non-asm is unsupported in naked functions
+   |     ------------------- not allowed in naked functions
 LL |     let mut c = 0usize;
-   |     ------------------- non-asm is unsupported in naked functions
+   |     ------------------- not allowed in naked functions
 LL |     let mut d = 0usize;
-   |     ------------------- non-asm is unsupported in naked functions
+   |     ------------------- not allowed in naked functions
 LL |     let mut e = 0usize;
-   |     ------------------- non-asm is unsupported in naked functions
+   |     ------------------- not allowed in naked functions
 
-error[E0787]: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:76:1
+error[E0787]: naked functions must contain a single `naked_asm!` invocation
+  --> $DIR/naked-functions.rs:80:1
    |
 LL | pub extern "C" fn missing_assembly() {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0787]: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:84:9
-   |
-LL |         asm!("");
-   |         ^^^^^^^^
-   |
-help: consider specifying that the asm block is responsible for returning from the function
-   |
-LL |         asm!("", options(noreturn));
-   |                +++++++++++++++++++
-
-error[E0787]: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:86:9
-   |
-LL |         asm!("");
-   |         ^^^^^^^^
-   |
-help: consider specifying that the asm block is responsible for returning from the function
-   |
-LL |         asm!("", options(noreturn));
-   |                +++++++++++++++++++
-
-error[E0787]: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:88:9
-   |
-LL |         asm!("");
-   |         ^^^^^^^^
-   |
-help: consider specifying that the asm block is responsible for returning from the function
-   |
-LL |         asm!("", options(noreturn));
-   |                +++++++++++++++++++
-
-error[E0787]: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:81:1
+error[E0787]: naked functions must contain a single `naked_asm!` invocation
+  --> $DIR/naked-functions.rs:85:1
    |
 LL | pub extern "C" fn too_many_asm_blocks() {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 ...
-LL |         asm!("");
-   |         -------- multiple asm blocks are unsupported in naked functions
-LL |
-LL |         asm!("");
-   |         -------- multiple asm blocks are unsupported in naked functions
-LL |
-LL |         asm!("", options(noreturn));
-   |         --------------------------- multiple asm blocks are unsupported in naked functions
+LL |         naked_asm!("");
+   |         -------------- multiple `naked_asm!` invocations are not allowed in naked functions
 
 error: referencing function parameters is not allowed in naked functions
   --> $DIR/naked-functions.rs:98:11
@@ -197,46 +166,17 @@ LL |         *&y
    |
    = help: follow the calling convention in asm block to use parameters
 
-error[E0787]: naked functions must contain a single asm block
+error[E0787]: naked functions must contain a single `naked_asm!` invocation
   --> $DIR/naked-functions.rs:96:5
    |
 LL |     pub extern "C" fn inner(y: usize) -> usize {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL |
 LL |         *&y
-   |         --- non-asm is unsupported in naked functions
-
-error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags`
-  --> $DIR/naked-functions.rs:106:5
-   |
-LL |     asm!("", options(nomem, preserves_flags, noreturn));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0787]: asm options unsupported in naked functions: `pure`, `readonly`, `nostack`
-  --> $DIR/naked-functions.rs:112:5
-   |
-LL |     asm!("", options(readonly, nostack), options(pure));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0787]: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:112:5
-   |
-LL |     asm!("", options(readonly, nostack), options(pure));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: consider specifying that the asm block is responsible for returning from the function
-   |
-LL |     asm!("", options(noreturn), options(readonly, nostack), options(pure));
-   |            +++++++++++++++++++
-
-error[E0787]: asm options unsupported in naked functions: `may_unwind`
-  --> $DIR/naked-functions.rs:120:5
-   |
-LL |     asm!("", options(noreturn, may_unwind));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         --- not allowed in naked functions
 
 warning: Rust ABI is unsupported in naked functions
-  --> $DIR/naked-functions.rs:125:1
+  --> $DIR/naked-functions.rs:126:1
    |
 LL | pub unsafe fn default_abi() {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -244,11 +184,11 @@ LL | pub unsafe fn default_abi() {
    = note: `#[warn(undefined_naked_function_abi)]` on by default
 
 warning: Rust ABI is unsupported in naked functions
-  --> $DIR/naked-functions.rs:131:1
+  --> $DIR/naked-functions.rs:132:1
    |
 LL | pub unsafe fn rust_abi() {
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 27 previous errors; 2 warnings emitted
+error: aborting due to 25 previous errors; 2 warnings emitted
 
 For more information about this error, try `rustc --explain E0787`.
diff --git a/tests/ui/asm/naked-invalid-attr.rs b/tests/ui/asm/naked-invalid-attr.rs
index 57edd57de99..4053c58fb51 100644
--- a/tests/ui/asm/naked-invalid-attr.rs
+++ b/tests/ui/asm/naked-invalid-attr.rs
@@ -4,7 +4,7 @@
 #![feature(naked_functions)]
 #![naked] //~ ERROR should be applied to a function definition
 
-use std::arch::asm;
+use std::arch::naked_asm;
 
 extern "C" {
     #[naked] //~ ERROR should be applied to a function definition
@@ -26,27 +26,28 @@ trait Invoke {
 impl Invoke for S {
     #[naked]
     extern "C" fn invoke(&self) {
-        unsafe { asm!("", options(noreturn)) }
+        unsafe { naked_asm!("") }
     }
 }
 
 #[naked]
 extern "C" fn ok() {
-    unsafe { asm!("", options(noreturn)) }
+    unsafe { naked_asm!("") }
 }
 
 impl S {
     #[naked]
     extern "C" fn g() {
-        unsafe { asm!("", options(noreturn)) }
+        unsafe { naked_asm!("") }
     }
 
     #[naked]
     extern "C" fn h(&self) {
-        unsafe { asm!("", options(noreturn)) }
+        unsafe { naked_asm!("") }
     }
 }
 
 fn main() {
-    #[naked] || {}; //~ ERROR should be applied to a function definition
+    #[naked] //~ ERROR should be applied to a function definition
+    || {};
 }
diff --git a/tests/ui/asm/naked-invalid-attr.stderr b/tests/ui/asm/naked-invalid-attr.stderr
index e8ddccc854a..640f9d9510d 100644
--- a/tests/ui/asm/naked-invalid-attr.stderr
+++ b/tests/ui/asm/naked-invalid-attr.stderr
@@ -13,8 +13,10 @@ LL | | }
 error: attribute should be applied to a function definition
   --> $DIR/naked-invalid-attr.rs:51:5
    |
-LL |     #[naked] || {};
-   |     ^^^^^^^^ ----- not a function definition
+LL |     #[naked]
+   |     ^^^^^^^^
+LL |     || {};
+   |     ----- not a function definition
 
 error: attribute should be applied to a function definition
   --> $DIR/naked-invalid-attr.rs:22:5
diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.rs b/tests/ui/asm/naked-with-invalid-repr-attr.rs
index 687fe1ad73d..18b9c1014c3 100644
--- a/tests/ui/asm/naked-with-invalid-repr-attr.rs
+++ b/tests/ui/asm/naked-with-invalid-repr-attr.rs
@@ -2,14 +2,14 @@
 #![feature(naked_functions)]
 #![feature(fn_align)]
 #![crate_type = "lib"]
-use std::arch::asm;
+use std::arch::naked_asm;
 
 #[repr(C)]
 //~^ ERROR attribute should be applied to a struct, enum, or union [E0517]
 #[naked]
 extern "C" fn example1() {
     //~^ NOTE not a struct, enum, or union
-    unsafe { asm!("", options(noreturn)) }
+    unsafe { naked_asm!("") }
 }
 
 #[repr(transparent)]
@@ -17,7 +17,7 @@ extern "C" fn example1() {
 #[naked]
 extern "C" fn example2() {
     //~^ NOTE not a struct, enum, or union
-    unsafe { asm!("", options(noreturn)) }
+    unsafe { naked_asm!("") }
 }
 
 #[repr(align(16), C)]
@@ -25,7 +25,7 @@ extern "C" fn example2() {
 #[naked]
 extern "C" fn example3() {
     //~^ NOTE not a struct, enum, or union
-    unsafe { asm!("", options(noreturn)) }
+    unsafe { naked_asm!("") }
 }
 
 // note: two errors because of packed and C
@@ -36,7 +36,7 @@ extern "C" fn example3() {
 extern "C" fn example4() {
     //~^ NOTE not a struct, enum, or union
     //~| NOTE not a struct or union
-    unsafe { asm!("", options(noreturn)) }
+    unsafe { naked_asm!("") }
 }
 
 #[repr(u8)]
@@ -44,5 +44,5 @@ extern "C" fn example4() {
 #[naked]
 extern "C" fn example5() {
     //~^ NOTE not an enum
-    unsafe { asm!("", options(noreturn)) }
+    unsafe { naked_asm!("") }
 }
diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.stderr b/tests/ui/asm/naked-with-invalid-repr-attr.stderr
index 3740f17a9dc..8248a8c1657 100644
--- a/tests/ui/asm/naked-with-invalid-repr-attr.stderr
+++ b/tests/ui/asm/naked-with-invalid-repr-attr.stderr
@@ -6,7 +6,7 @@ LL |   #[repr(C)]
 ...
 LL | / extern "C" fn example1() {
 LL | |
-LL | |     unsafe { asm!("", options(noreturn)) }
+LL | |     unsafe { naked_asm!("") }
 LL | | }
    | |_- not a struct, enum, or union
 
@@ -18,7 +18,7 @@ LL |   #[repr(transparent)]
 ...
 LL | / extern "C" fn example2() {
 LL | |
-LL | |     unsafe { asm!("", options(noreturn)) }
+LL | |     unsafe { naked_asm!("") }
 LL | | }
    | |_- not a struct, enum, or union
 
@@ -30,7 +30,7 @@ LL |   #[repr(align(16), C)]
 ...
 LL | / extern "C" fn example3() {
 LL | |
-LL | |     unsafe { asm!("", options(noreturn)) }
+LL | |     unsafe { naked_asm!("") }
 LL | | }
    | |_- not a struct, enum, or union
 
@@ -43,7 +43,7 @@ LL |   #[repr(C, packed)]
 LL | / extern "C" fn example4() {
 LL | |
 LL | |
-LL | |     unsafe { asm!("", options(noreturn)) }
+LL | |     unsafe { naked_asm!("") }
 LL | | }
    | |_- not a struct, enum, or union
 
@@ -56,7 +56,7 @@ LL |   #[repr(C, packed)]
 LL | / extern "C" fn example4() {
 LL | |
 LL | |
-LL | |     unsafe { asm!("", options(noreturn)) }
+LL | |     unsafe { naked_asm!("") }
 LL | | }
    | |_- not a struct or union
 
@@ -68,7 +68,7 @@ LL |   #[repr(u8)]
 ...
 LL | / extern "C" fn example5() {
 LL | |
-LL | |     unsafe { asm!("", options(noreturn)) }
+LL | |     unsafe { naked_asm!("") }
 LL | | }
    | |_- not an enum
 
diff --git a/tests/ui/asm/named-asm-labels.rs b/tests/ui/asm/named-asm-labels.rs
index 043aab9029d..77831e679ed 100644
--- a/tests/ui/asm/named-asm-labels.rs
+++ b/tests/ui/asm/named-asm-labels.rs
@@ -12,7 +12,7 @@
 
 #![feature(naked_functions)]
 
-use std::arch::{asm, global_asm};
+use std::arch::{asm, global_asm, naked_asm};
 
 #[no_mangle]
 pub static FOO: usize = 42;
@@ -177,7 +177,7 @@ fn main() {
 // label or LTO can cause labels to break
 #[naked]
 pub extern "C" fn foo() -> i32 {
-    unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) }
+    unsafe { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) }
     //~^ ERROR avoid using named labels
 }
 
@@ -192,7 +192,7 @@ pub extern "C" fn bar() {
 pub extern "C" fn aaa() {
     fn _local() {}
 
-    unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) } //~ ERROR avoid using named labels
+    unsafe { naked_asm!(".Laaa: nop; ret;") } //~ ERROR avoid using named labels
 }
 
 pub fn normal() {
@@ -202,7 +202,7 @@ pub fn normal() {
     pub extern "C" fn bbb() {
         fn _very_local() {}
 
-        unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } //~ ERROR avoid using named labels
+        unsafe { naked_asm!(".Lbbb: nop; ret;") } //~ ERROR avoid using named labels
     }
 
     fn _local2() {}
@@ -221,7 +221,7 @@ fn closures() {
     || {
         #[naked]
         unsafe extern "C" fn _nested() {
-            asm!("ret;", options(noreturn));
+            naked_asm!("ret;");
         }
 
         unsafe {
diff --git a/tests/ui/asm/named-asm-labels.stderr b/tests/ui/asm/named-asm-labels.stderr
index e5e177fb8b8..44ce358c62b 100644
--- a/tests/ui/asm/named-asm-labels.stderr
+++ b/tests/ui/asm/named-asm-labels.stderr
@@ -475,10 +475,10 @@ LL |         #[warn(named_asm_labels)]
    |                ^^^^^^^^^^^^^^^^
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:180:20
+  --> $DIR/named-asm-labels.rs:180:26
    |
-LL |     unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) }
-   |                    ^^^^^
+LL |     unsafe { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) }
+   |                          ^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
@@ -493,19 +493,19 @@ LL |     unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noret
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:195:20
+  --> $DIR/named-asm-labels.rs:195:26
    |
-LL |     unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) }
-   |                    ^^^^^
+LL |     unsafe { naked_asm!(".Laaa: nop; ret;") }
+   |                          ^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:205:24
+  --> $DIR/named-asm-labels.rs:205:30
    |
-LL |         unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) }
-   |                        ^^^^^
+LL |         unsafe { naked_asm!(".Lbbb: nop; ret;") }
+   |                              ^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
    = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
diff --git a/tests/ui/asm/non-const.rs b/tests/ui/asm/non-const.rs
new file mode 100644
index 00000000000..63c46563226
--- /dev/null
+++ b/tests/ui/asm/non-const.rs
@@ -0,0 +1,11 @@
+//@ needs-asm-support
+
+use std::arch::global_asm;
+
+fn main() {}
+
+// Constants must be... constant
+fn non_const_fn(x: i32) -> i32 { x }
+
+global_asm!("/* {} */", const non_const_fn(0));
+//~^ERROR: cannot call non-const fn
diff --git a/tests/ui/asm/non-const.stderr b/tests/ui/asm/non-const.stderr
new file mode 100644
index 00000000000..5fae2ac9843
--- /dev/null
+++ b/tests/ui/asm/non-const.stderr
@@ -0,0 +1,11 @@
+error[E0015]: cannot call non-const fn `non_const_fn` in constants
+  --> $DIR/non-const.rs:10:31
+   |
+LL | global_asm!("/* {} */", const non_const_fn(0));
+   |                               ^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/asm/x86_64/type-check-4.rs b/tests/ui/asm/x86_64/type-check-4.rs
deleted file mode 100644
index ebc6edc07e4..00000000000
--- a/tests/ui/asm/x86_64/type-check-4.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-//@ only-x86_64
-//@ build-fail
-
-use std::arch::global_asm;
-
-fn main() {}
-
-// Constants must be... constant
-
-static mut S: i32 = 1;
-const fn const_foo(x: i32) -> i32 {
-    x
-}
-const fn const_bar<T>(x: T) -> T {
-    x
-}
-global_asm!("{}", const unsafe { S });
-//~^ ERROR evaluation of constant value failed
-//~| mutable global memory
-global_asm!("{}", const const_foo(0));
-global_asm!("{}", const const_foo(unsafe { S }));
-//~^ ERROR evaluation of constant value failed
-//~| mutable global memory
-global_asm!("{}", const const_bar(0));
-global_asm!("{}", const const_bar(unsafe { S }));
-//~^ ERROR evaluation of constant value failed
-//~| mutable global memory
diff --git a/tests/ui/asm/x86_64/type-check-4.stderr b/tests/ui/asm/x86_64/type-check-4.stderr
deleted file mode 100644
index 8c22dfcdb5e..00000000000
--- a/tests/ui/asm/x86_64/type-check-4.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0080]: evaluation of constant value failed
-  --> $DIR/type-check-4.rs:17:34
-   |
-LL | global_asm!("{}", const unsafe { S });
-   |                                  ^ constant accesses mutable global memory
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/type-check-4.rs:21:44
-   |
-LL | global_asm!("{}", const const_foo(unsafe { S }));
-   |                                            ^ constant accesses mutable global memory
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/type-check-4.rs:25:44
-   |
-LL | global_asm!("{}", const const_bar(unsafe { S }));
-   |                                            ^ constant accesses mutable global memory
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/associated-type-bounds/duplicate.stderr b/tests/ui/associated-type-bounds/duplicate.stderr
index cf4809991c3..0dabcbdce1b 100644
--- a/tests/ui/associated-type-bounds/duplicate.stderr
+++ b/tests/ui/associated-type-bounds/duplicate.stderr
@@ -208,17 +208,6 @@ LL | fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> {
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0282]: type annotations needed
-  --> $DIR/duplicate.rs:136:5
-   |
-LL |     iter::empty()
-   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
-   |
-help: consider specifying the generic argument
-   |
-LL |     iter::empty::<T>()
-   |                +++++
-
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
   --> $DIR/duplicate.rs:139:42
    |
@@ -237,17 +226,6 @@ LL | fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> {
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0282]: type annotations needed
-  --> $DIR/duplicate.rs:142:5
-   |
-LL |     iter::empty()
-   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
-   |
-help: consider specifying the generic argument
-   |
-LL |     iter::empty::<T>()
-   |                +++++
-
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
   --> $DIR/duplicate.rs:145:45
    |
@@ -266,17 +244,6 @@ LL | fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> {
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0282]: type annotations needed
-  --> $DIR/duplicate.rs:148:5
-   |
-LL |     iter::empty()
-   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
-   |
-help: consider specifying the generic argument
-   |
-LL |     iter::empty::<T>()
-   |                +++++
-
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
   --> $DIR/duplicate.rs:151:40
    |
@@ -697,6 +664,39 @@ LL |     type A: Iterator<Item: 'static, Item: 'static>;
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
+error[E0282]: type annotations needed
+  --> $DIR/duplicate.rs:136:5
+   |
+LL |     iter::empty()
+   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
+   |
+help: consider specifying the generic argument
+   |
+LL |     iter::empty::<T>()
+   |                +++++
+
+error[E0282]: type annotations needed
+  --> $DIR/duplicate.rs:142:5
+   |
+LL |     iter::empty()
+   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
+   |
+help: consider specifying the generic argument
+   |
+LL |     iter::empty::<T>()
+   |                +++++
+
+error[E0282]: type annotations needed
+  --> $DIR/duplicate.rs:148:5
+   |
+LL |     iter::empty()
+   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
+   |
+help: consider specifying the generic argument
+   |
+LL |     iter::empty::<T>()
+   |                +++++
+
 error: aborting due to 81 previous errors
 
 Some errors have detailed explanations: E0282, E0719.
diff --git a/tests/ui/async-await/async-fn/edition-2015.stderr b/tests/ui/async-await/async-fn/edition-2015.stderr
index 23ffee0d0a6..358bb3e112e 100644
--- a/tests/ui/async-await/async-fn/edition-2015.stderr
+++ b/tests/ui/async-await/async-fn/edition-2015.stderr
@@ -39,20 +39,20 @@ LL | fn foo(x: impl async Fn()) -> impl async Fn() { x }
    = help: to use an async block, remove the `||`: `async {`
 
 error[E0658]: use of unstable library feature 'async_closure'
-  --> $DIR/edition-2015.rs:1:22
+  --> $DIR/edition-2015.rs:1:42
    |
 LL | fn foo(x: impl async Fn()) -> impl async Fn() { x }
-   |                      ^^^^
+   |                                          ^^^^
    |
    = note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
    = help: add `#![feature(async_closure)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: use of unstable library feature 'async_closure'
-  --> $DIR/edition-2015.rs:1:42
+  --> $DIR/edition-2015.rs:1:22
    |
 LL | fn foo(x: impl async Fn()) -> impl async Fn() { x }
-   |                                          ^^^^
+   |                      ^^^^
    |
    = note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
    = help: add `#![feature(async_closure)]` to the crate attributes to enable
diff --git a/tests/ui/async-await/inference_var_self_argument.stderr b/tests/ui/async-await/inference_var_self_argument.stderr
index 7bfa9be66dd..7b7b3dbc757 100644
--- a/tests/ui/async-await/inference_var_self_argument.stderr
+++ b/tests/ui/async-await/inference_var_self_argument.stderr
@@ -1,3 +1,12 @@
+error[E0307]: invalid `self` parameter type: `&dyn Foo`
+  --> $DIR/inference_var_self_argument.rs:5:24
+   |
+LL |     async fn foo(self: &dyn Foo) {
+   |                        ^^^^^^^^
+   |
+   = note: type of `self` must be `Self` or a type that dereferences to it
+   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/inference_var_self_argument.rs:5:5
    |
@@ -13,15 +22,6 @@ LL |     async fn foo(self: &dyn Foo) {
    |              ^^^ ...because method `foo` is `async`
    = help: consider moving `foo` to another trait
 
-error[E0307]: invalid `self` parameter type: `&dyn Foo`
-  --> $DIR/inference_var_self_argument.rs:5:24
-   |
-LL |     async fn foo(self: &dyn Foo) {
-   |                        ^^^^^^^^
-   |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0038, E0307.
diff --git a/tests/ui/async-await/issue-66312.stderr b/tests/ui/async-await/issue-66312.stderr
index 702e0b375e5..c95ae1147df 100644
--- a/tests/ui/async-await/issue-66312.stderr
+++ b/tests/ui/async-await/issue-66312.stderr
@@ -1,9 +1,3 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-66312.rs:9:8
-   |
-LL |     if x.is_some() {
-   |        ^^^^^^^^^^^ expected `bool`, found `()`
-
 error[E0307]: invalid `self` parameter type: `T`
   --> $DIR/issue-66312.rs:4:22
    |
@@ -13,6 +7,12 @@ LL |     fn is_some(self: T);
    = note: type of `self` must be `Self` or a type that dereferences to it
    = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
+error[E0308]: mismatched types
+  --> $DIR/issue-66312.rs:9:8
+   |
+LL |     if x.is_some() {
+   |        ^^^^^^^^^^^ expected `bool`, found `()`
+
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0307, E0308.
diff --git a/tests/ui/async-await/pin-reborrow-self.rs b/tests/ui/async-await/pin-reborrow-self.rs
index b60b6982bb8..ee617617da0 100644
--- a/tests/ui/async-await/pin-reborrow-self.rs
+++ b/tests/ui/async-await/pin-reborrow-self.rs
@@ -1,24 +1,33 @@
 //@ check-pass
-//@ignore-test
-
-// Currently ignored due to self reborrowing not being implemented for Pin
 
 #![feature(pin_ergonomics)]
 #![allow(incomplete_features)]
 
 use std::pin::Pin;
 
-struct Foo;
+pub struct Foo;
 
 impl Foo {
     fn foo(self: Pin<&mut Self>) {
     }
+
+    fn baz(self: Pin<&Self>) {
+    }
 }
 
-fn bar(x: Pin<&mut Foo>) {
+pub fn bar(x: Pin<&mut Foo>) {
     x.foo();
     x.foo(); // for this to work we need to automatically reborrow,
              // as if the user had written `x.as_mut().foo()`.
+
+    Foo::baz(x);
+
+    x.baz();
+}
+
+pub fn baaz(x: Pin<&Foo>) {
+    x.baz();
+    x.baz();
 }
 
 fn main() {}
diff --git a/tests/ui/attributes/rustc_confusables_std_cases.rs b/tests/ui/attributes/rustc_confusables_std_cases.rs
index d9121695950..4f6baea26df 100644
--- a/tests/ui/attributes/rustc_confusables_std_cases.rs
+++ b/tests/ui/attributes/rustc_confusables_std_cases.rs
@@ -23,4 +23,8 @@ fn main() {
     //~^ HELP you might have meant to use `push_str`
     String::new().append(""); //~ ERROR E0599
     //~^ HELP you might have meant to use `push_str`
+    let mut buffer = String::new();
+    let stdin = std::io::stdin();
+    stdin.get_line(&mut buffer).unwrap(); //~ ERROR E0599
+    //~^ HELP you might have meant to use `read_line`
 }
diff --git a/tests/ui/attributes/rustc_confusables_std_cases.stderr b/tests/ui/attributes/rustc_confusables_std_cases.stderr
index f4b6947ccd9..7bf96241ca7 100644
--- a/tests/ui/attributes/rustc_confusables_std_cases.stderr
+++ b/tests/ui/attributes/rustc_confusables_std_cases.stderr
@@ -106,7 +106,18 @@ help: you might have meant to use `push_str`
 LL |     String::new().push_str("");
    |                   ~~~~~~~~
 
-error: aborting due to 8 previous errors
+error[E0599]: no method named `get_line` found for struct `Stdin` in the current scope
+  --> $DIR/rustc_confusables_std_cases.rs:28:11
+   |
+LL |     stdin.get_line(&mut buffer).unwrap();
+   |           ^^^^^^^^ method not found in `Stdin`
+   |
+help: you might have meant to use `read_line`
+   |
+LL |     stdin.read_line(&mut buffer).unwrap();
+   |           ~~~~~~~~~
+
+error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0308, E0599.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs
index b561550c198..273b127bf9c 100644
--- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs
+++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs
@@ -27,4 +27,8 @@ mod inner {
 #[unsafe(used)] //~ ERROR: is not an unsafe attribute
 static FOO: usize = 0;
 
-fn main() {}
+fn main() {
+    let _a = cfg!(unsafe(foo));
+    //~^ ERROR: expected identifier, found keyword `unsafe`
+    //~^^ ERROR: invalid predicate `r#unsafe`
+}
diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr
index 9fb7f062b91..445d239d867 100644
--- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr
+++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr
@@ -22,6 +22,23 @@ LL | #[unsafe(test)]
    |
    = note: extraneous unsafe is not allowed in attributes
 
+error: expected identifier, found keyword `unsafe`
+  --> $DIR/extraneous-unsafe-attributes.rs:31:19
+   |
+LL |     let _a = cfg!(unsafe(foo));
+   |                   ^^^^^^ expected identifier, found keyword
+   |
+help: escape `unsafe` to use it as an identifier
+   |
+LL |     let _a = cfg!(r#unsafe(foo));
+   |                   ++
+
+error[E0537]: invalid predicate `r#unsafe`
+  --> $DIR/extraneous-unsafe-attributes.rs:31:19
+   |
+LL |     let _a = cfg!(unsafe(foo));
+   |                   ^^^^^^^^^^^
+
 error: `ignore` is not an unsafe attribute
   --> $DIR/extraneous-unsafe-attributes.rs:13:3
    |
@@ -62,5 +79,6 @@ LL | #[unsafe(used)]
    |
    = note: extraneous unsafe is not allowed in attributes
 
-error: aborting due to 8 previous errors
+error: aborting due to 10 previous errors
 
+For more information about this error, try `rustc --explain E0537`.
diff --git a/tests/ui/cast/fat-ptr-cast.stderr b/tests/ui/cast/fat-ptr-cast.stderr
index 18e7b68ff3c..2b0bceebf15 100644
--- a/tests/ui/cast/fat-ptr-cast.stderr
+++ b/tests/ui/cast/fat-ptr-cast.stderr
@@ -44,7 +44,7 @@ LL |     p as usize;
    |
    = help: cast through a thin pointer first
 
-error[E0607]: cannot cast thin pointer `*const i32` to fat pointer `*const [i32]`
+error[E0607]: cannot cast thin pointer `*const i32` to wide pointer `*const [i32]`
   --> $DIR/fat-ptr-cast.rs:19:5
    |
 LL |     q as *const [i32];
diff --git a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs b/tests/ui/cfg/crate-attributes-using-cfg_attr.rs
index 3ced3a630e3..f99fad881f2 100644
--- a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs
+++ b/tests/ui/cfg/crate-attributes-using-cfg_attr.rs
@@ -3,13 +3,9 @@
 
 #![cfg_attr(foo, crate_type="bin")]
 //~^ERROR `crate_type` within
-//~| WARN this was previously accepted
 //~|ERROR `crate_type` within
-//~| WARN this was previously accepted
 #![cfg_attr(foo, crate_name="bar")]
 //~^ERROR `crate_name` within
-//~| WARN this was previously accepted
 //~|ERROR `crate_name` within
-//~| WARN this was previously accepted
 
 fn main() {}
diff --git a/tests/ui/cfg/crate-attributes-using-cfg_attr.stderr b/tests/ui/cfg/crate-attributes-using-cfg_attr.stderr
new file mode 100644
index 00000000000..1dfca2b88d0
--- /dev/null
+++ b/tests/ui/cfg/crate-attributes-using-cfg_attr.stderr
@@ -0,0 +1,30 @@
+error: `crate_type` within an `#![cfg_attr]` attribute is forbidden
+  --> $DIR/crate-attributes-using-cfg_attr.rs:4:18
+   |
+LL | #![cfg_attr(foo, crate_type="bin")]
+   |                  ^^^^^^^^^^^^^^^^
+
+error: `crate_name` within an `#![cfg_attr]` attribute is forbidden
+  --> $DIR/crate-attributes-using-cfg_attr.rs:7:18
+   |
+LL | #![cfg_attr(foo, crate_name="bar")]
+   |                  ^^^^^^^^^^^^^^^^
+
+error: `crate_type` within an `#![cfg_attr]` attribute is forbidden
+  --> $DIR/crate-attributes-using-cfg_attr.rs:4:18
+   |
+LL | #![cfg_attr(foo, crate_type="bin")]
+   |                  ^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `crate_name` within an `#![cfg_attr]` attribute is forbidden
+  --> $DIR/crate-attributes-using-cfg_attr.rs:7:18
+   |
+LL | #![cfg_attr(foo, crate_name="bar")]
+   |                  ^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr b/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr
deleted file mode 100644
index 82b2d7d1b1d..00000000000
--- a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr
+++ /dev/null
@@ -1,41 +0,0 @@
-error: `crate_type` within an `#![cfg_attr]` attribute is deprecated
-  --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:4:18
-   |
-LL | #![cfg_attr(foo, crate_type="bin")]
-   |                  ^^^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632>
-   = note: `#[deny(deprecated_cfg_attr_crate_type_name)]` on by default
-
-error: `crate_name` within an `#![cfg_attr]` attribute is deprecated
-  --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:9:18
-   |
-LL | #![cfg_attr(foo, crate_name="bar")]
-   |                  ^^^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632>
-
-error: `crate_type` within an `#![cfg_attr]` attribute is deprecated
-  --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:4:18
-   |
-LL | #![cfg_attr(foo, crate_type="bin")]
-   |                  ^^^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632>
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `crate_name` within an `#![cfg_attr]` attribute is deprecated
-  --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:9:18
-   |
-LL | #![cfg_attr(foo, crate_name="bar")]
-   |                  ^^^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632>
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 4 previous errors
-
diff --git a/tests/ui/cfg/raw-true-false.rs b/tests/ui/cfg/raw-true-false.rs
new file mode 100644
index 00000000000..4cb8bb71c92
--- /dev/null
+++ b/tests/ui/cfg/raw-true-false.rs
@@ -0,0 +1,19 @@
+//@ check-pass
+//@ compile-flags: --cfg false --check-cfg=cfg(r#false)
+
+#![deny(warnings)]
+
+#[expect(unexpected_cfgs)]
+mod a {
+  #[cfg(r#true)]
+  pub fn foo() {}
+}
+
+mod b {
+  #[cfg(r#false)]
+  pub fn bar() {}
+}
+
+fn main() {
+    b::bar()
+}
diff --git a/tests/ui/cfg/true-false.rs b/tests/ui/cfg/true-false.rs
new file mode 100644
index 00000000000..03d96fbafec
--- /dev/null
+++ b/tests/ui/cfg/true-false.rs
@@ -0,0 +1,30 @@
+//@ run-pass
+
+#![feature(link_cfg)]
+#![feature(cfg_boolean_literals)]
+
+#[cfg(true)]
+fn foo() -> bool {
+    cfg!(true)
+}
+
+#[cfg(false)]
+fn foo() -> bool {
+    cfg!(false)
+}
+
+#[cfg_attr(true, cfg(false))]
+fn foo() {}
+
+#[link(name = "foo", cfg(false))]
+extern "C" {}
+
+fn main() {
+    assert!(foo());
+    assert!(cfg!(true));
+    assert!(!cfg!(false));
+    assert!(cfg!(not(false)));
+    assert!(cfg!(all(true)));
+    assert!(cfg!(any(true)));
+    assert!(!cfg!(not(true)));
+}
diff --git a/tests/ui/check-cfg/invalid-arguments.rs b/tests/ui/check-cfg/invalid-arguments.rs
index b8588ecb4ff..c6b1218ce27 100644
--- a/tests/ui/check-cfg/invalid-arguments.rs
+++ b/tests/ui/check-cfg/invalid-arguments.rs
@@ -8,7 +8,7 @@
 //@ revisions: values_any_missing_values values_any_before_ident ident_in_values_1
 //@ revisions: ident_in_values_2 unknown_meta_item_1 unknown_meta_item_2 unknown_meta_item_3
 //@ revisions: mixed_values_any mixed_any any_values giberich unterminated
-//@ revisions: none_not_empty cfg_none
+//@ revisions: none_not_empty cfg_none unsafe_attr
 //
 //@ [anything_else]compile-flags: --check-cfg=anything_else(...)
 //@ [boolean]compile-flags: --check-cfg=cfg(true)
@@ -33,5 +33,6 @@
 //@ [cfg_none]compile-flags: --check-cfg=cfg(none())
 //@ [giberich]compile-flags: --check-cfg=cfg(...)
 //@ [unterminated]compile-flags: --check-cfg=cfg(
+//@ [unsafe_attr]compile-flags: --check-cfg=unsafe(cfg(foo))
 
 fn main() {}
diff --git a/tests/ui/check-cfg/invalid-arguments.unsafe_attr.stderr b/tests/ui/check-cfg/invalid-arguments.unsafe_attr.stderr
new file mode 100644
index 00000000000..5236ed6f605
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.unsafe_attr.stderr
@@ -0,0 +1,5 @@
+error: invalid `--check-cfg` argument: `unsafe(cfg(foo))`
+   |
+   = note: expected `cfg(name, values("value1", "value2", ... "valueN"))`
+   = note: visit <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more details
+
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr
index 653c1c983e2..7726c2d52f5 100644
--- a/tests/ui/check-cfg/mix.stderr
+++ b/tests/ui/check-cfg/mix.stderr
@@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra`
 LL |     cfg!(target_feature = "zebra");
    |          ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 241 more
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 244 more
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: 27 warnings emitted
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 14832e7ff43..c6d403104ea 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -129,7 +129,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_abi = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elf`, `fortanix`, `ilp32`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32`
+   = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `fortanix`, `ilp32`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -174,7 +174,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_feature = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
diff --git a/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr b/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
index f8ed792e3c6..e0d900a1eb5 100644
--- a/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
+++ b/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
@@ -7,14 +7,12 @@ LL |     let c1 = || match x { };
    |                       ^ `x` used here but it isn't initialized
 
 error[E0381]: used binding `x` isn't initialized
-  --> $DIR/pattern-matching-should-fail.rs:15:14
+  --> $DIR/pattern-matching-should-fail.rs:15:23
    |
 LL |     let x: !;
    |         - binding declared here but left uninitialized
 LL |     let c2 = || match x { _ => () };
-   |              ^^       - borrow occurs due to use in closure
-   |              |
-   |              `x` used here but it isn't initialized
+   |                       ^ `x` used here but it isn't initialized
 
 error[E0381]: used binding `variant` isn't initialized
   --> $DIR/pattern-matching-should-fail.rs:27:13
diff --git a/tests/ui/codegen/sub-principals-in-codegen.rs b/tests/ui/codegen/sub-principals-in-codegen.rs
new file mode 100644
index 00000000000..178c10da596
--- /dev/null
+++ b/tests/ui/codegen/sub-principals-in-codegen.rs
@@ -0,0 +1,8 @@
+//@ build-pass
+
+// Regression test for an overly aggressive assertion in #130855.
+
+fn main() {
+    let subtype: &(dyn for<'a> Fn(&'a i32) -> &'a i32) = &|x| x;
+    let supertype: &(dyn Fn(&'static i32) -> &'static i32) = subtype;
+}
diff --git a/tests/ui/command/command-current-dir.rs b/tests/ui/command/command-current-dir.rs
index 95c16bce6e8..23269e41231 100644
--- a/tests/ui/command/command-current-dir.rs
+++ b/tests/ui/command/command-current-dir.rs
@@ -1,4 +1,5 @@
 //@ run-pass
+//@ no-prefer-dynamic We move the binary around, so do not depend dynamically on libstd
 //@ ignore-wasm32 no processes
 //@ ignore-sgx no processes
 //@ ignore-fuchsia Needs directory creation privilege
diff --git a/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr b/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr
index aafc0640dd2..8c54aef36ca 100644
--- a/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr
+++ b/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr
@@ -4,7 +4,7 @@ error: `&'static mut ()` is forbidden as the type of a const generic parameter
 LL | fn uwu_0<const N: &'static mut ()>() {}
    |                   ^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: `&'static u32` is forbidden as the type of a const generic parameter
   --> $DIR/suggest_feature_only_when_possible.rs:15:19
@@ -12,7 +12,7 @@ error: `&'static u32` is forbidden as the type of a const generic parameter
 LL | fn owo_0<const N: &'static u32>() {}
    |                   ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -28,7 +28,7 @@ error: `Meow` is forbidden as the type of a const generic parameter
 LL | fn meow_0<const N: Meow>() {}
    |                    ^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -40,7 +40,7 @@ error: `&'static Meow` is forbidden as the type of a const generic parameter
 LL | fn meow_1<const N: &'static Meow>() {}
    |                    ^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -56,7 +56,7 @@ error: `[Meow; 100]` is forbidden as the type of a const generic parameter
 LL | fn meow_2<const N: [Meow; 100]>() {}
    |                    ^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: `(Meow, u8)` is forbidden as the type of a const generic parameter
   --> $DIR/suggest_feature_only_when_possible.rs:29:20
@@ -64,7 +64,7 @@ error: `(Meow, u8)` is forbidden as the type of a const generic parameter
 LL | fn meow_3<const N: (Meow, u8)>() {}
    |                    ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: `(Meow, String)` is forbidden as the type of a const generic parameter
   --> $DIR/suggest_feature_only_when_possible.rs:34:20
@@ -72,7 +72,7 @@ error: `(Meow, String)` is forbidden as the type of a const generic parameter
 LL | fn meow_4<const N: (Meow, String)>() {}
    |                    ^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: `String` is forbidden as the type of a const generic parameter
   --> $DIR/suggest_feature_only_when_possible.rs:38:19
@@ -80,7 +80,7 @@ error: `String` is forbidden as the type of a const generic parameter
 LL | fn nya_0<const N: String>() {}
    |                   ^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: `Vec<u32>` is forbidden as the type of a const generic parameter
   --> $DIR/suggest_feature_only_when_possible.rs:40:19
@@ -88,7 +88,7 @@ error: `Vec<u32>` is forbidden as the type of a const generic parameter
 LL | fn nya_1<const N: Vec<u32>>() {}
    |                   ^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 9 previous errors
 
diff --git a/tests/ui/const-generics/const-param-elided-lifetime.full.stderr b/tests/ui/const-generics/const-param-elided-lifetime.full.stderr
index d6753a74f85..34510f546c8 100644
--- a/tests/ui/const-generics/const-param-elided-lifetime.full.stderr
+++ b/tests/ui/const-generics/const-param-elided-lifetime.full.stderr
@@ -5,25 +5,25 @@ LL | struct A<const N: &u8>;
    |                   ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:14:15
+  --> $DIR/const-param-elided-lifetime.rs:13:15
    |
 LL | impl<const N: &u8> A<N> {
    |               ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:17:21
+  --> $DIR/const-param-elided-lifetime.rs:15:21
    |
 LL |     fn foo<const M: &u8>(&self) {}
    |                     ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:22:15
+  --> $DIR/const-param-elided-lifetime.rs:19:15
    |
 LL | impl<const N: &u8> B for A<N> {}
    |               ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:26:17
+  --> $DIR/const-param-elided-lifetime.rs:22:17
    |
 LL | fn bar<const N: &u8>() {}
    |                 ^ explicit lifetime name needed here
diff --git a/tests/ui/const-generics/const-param-elided-lifetime.min.stderr b/tests/ui/const-generics/const-param-elided-lifetime.min.stderr
index 62267224738..34510f546c8 100644
--- a/tests/ui/const-generics/const-param-elided-lifetime.min.stderr
+++ b/tests/ui/const-generics/const-param-elided-lifetime.min.stderr
@@ -5,109 +5,29 @@ LL | struct A<const N: &u8>;
    |                   ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:14:15
+  --> $DIR/const-param-elided-lifetime.rs:13:15
    |
 LL | impl<const N: &u8> A<N> {
    |               ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:17:21
+  --> $DIR/const-param-elided-lifetime.rs:15:21
    |
 LL |     fn foo<const M: &u8>(&self) {}
    |                     ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:22:15
+  --> $DIR/const-param-elided-lifetime.rs:19:15
    |
 LL | impl<const N: &u8> B for A<N> {}
    |               ^ explicit lifetime name needed here
 
 error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/const-param-elided-lifetime.rs:26:17
+  --> $DIR/const-param-elided-lifetime.rs:22:17
    |
 LL | fn bar<const N: &u8>() {}
    |                 ^ explicit lifetime name needed here
 
-error: `&u8` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-elided-lifetime.rs:9:19
-   |
-LL | struct A<const N: &u8>;
-   |                   ^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
-   |
-LL + #![feature(unsized_const_params)]
-   |
-
-error: `&u8` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-elided-lifetime.rs:14:15
-   |
-LL | impl<const N: &u8> A<N> {
-   |               ^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
-   |
-LL + #![feature(unsized_const_params)]
-   |
-
-error: `&u8` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-elided-lifetime.rs:22:15
-   |
-LL | impl<const N: &u8> B for A<N> {}
-   |               ^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
-   |
-LL + #![feature(unsized_const_params)]
-   |
-
-error: `&u8` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-elided-lifetime.rs:26:17
-   |
-LL | fn bar<const N: &u8>() {}
-   |                 ^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
-   |
-LL + #![feature(unsized_const_params)]
-   |
-
-error: `&u8` is forbidden as the type of a const generic parameter
-  --> $DIR/const-param-elided-lifetime.rs:17:21
-   |
-LL |     fn foo<const M: &u8>(&self) {}
-   |                     ^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
-   |
-LL + #![feature(unsized_const_params)]
-   |
-
-error: aborting due to 10 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0637`.
diff --git a/tests/ui/const-generics/const-param-elided-lifetime.rs b/tests/ui/const-generics/const-param-elided-lifetime.rs
index e75073de98d..b1cdb6a46c5 100644
--- a/tests/ui/const-generics/const-param-elided-lifetime.rs
+++ b/tests/ui/const-generics/const-param-elided-lifetime.rs
@@ -8,23 +8,18 @@
 
 struct A<const N: &u8>;
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
-//[min]~^^ ERROR `&u8` is forbidden
 trait B {}
 
 impl<const N: &u8> A<N> {
     //~^ ERROR `&` without an explicit lifetime name cannot be used here
-    //[min]~^^ ERROR `&u8` is forbidden
     fn foo<const M: &u8>(&self) {}
     //~^ ERROR `&` without an explicit lifetime name cannot be used here
-    //[min]~^^ ERROR `&u8` is forbidden
 }
 
 impl<const N: &u8> B for A<N> {}
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
-//[min]~^^ ERROR `&u8` is forbidden
 
 fn bar<const N: &u8>() {}
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
-//[min]~^^ ERROR `&u8` is forbidden
 
 fn main() {}
diff --git a/tests/ui/const-generics/const-param-type-depends-on-const-param.min.stderr b/tests/ui/const-generics/const-param-type-depends-on-const-param.min.stderr
index fcc86b9ac33..18b89963267 100644
--- a/tests/ui/const-generics/const-param-type-depends-on-const-param.min.stderr
+++ b/tests/ui/const-generics/const-param-type-depends-on-const-param.min.stderr
@@ -20,7 +20,7 @@ error: `[u8; N]` is forbidden as the type of a const generic parameter
 LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
    |                                               ^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -32,7 +32,7 @@ error: `[u8; N]` is forbidden as the type of a const generic parameter
 LL | pub struct SelfDependent<const N: [u8; N]>;
    |                                   ^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/default-ty-closure.stderr b/tests/ui/const-generics/default-ty-closure.stderr
index 9c737c1a19d..3f6ca9aea4e 100644
--- a/tests/ui/const-generics/default-ty-closure.stderr
+++ b/tests/ui/const-generics/default-ty-closure.stderr
@@ -4,7 +4,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | struct X<const FN: fn() = { || {} }>;
    |                    ^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/float-generic.simple.stderr b/tests/ui/const-generics/float-generic.simple.stderr
index 2999bce32d6..abc5e7c5a99 100644
--- a/tests/ui/const-generics/float-generic.simple.stderr
+++ b/tests/ui/const-generics/float-generic.simple.stderr
@@ -4,7 +4,7 @@ error: `f32` is forbidden as the type of a const generic parameter
 LL | fn foo<const F: f32>() {}
    |                 ^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/fn-const-param-call.min.stderr b/tests/ui/const-generics/fn-const-param-call.min.stderr
index d37766b28c9..b5b809d2787 100644
--- a/tests/ui/const-generics/fn-const-param-call.min.stderr
+++ b/tests/ui/const-generics/fn-const-param-call.min.stderr
@@ -4,7 +4,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | struct Wrapper<const F: fn() -> u32>;
    |                         ^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: using function pointers as const generic parameters is forbidden
   --> $DIR/fn-const-param-call.rs:15:15
@@ -12,7 +12,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | impl<const F: fn() -> u32> Wrapper<F> {
    |               ^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/fn-const-param-infer.min.stderr b/tests/ui/const-generics/fn-const-param-infer.min.stderr
index 4da503d344a..5e08f71a267 100644
--- a/tests/ui/const-generics/fn-const-param-infer.min.stderr
+++ b/tests/ui/const-generics/fn-const-param-infer.min.stderr
@@ -4,7 +4,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | struct Checked<const F: fn(usize) -> bool>;
    |                         ^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error[E0308]: mismatched types
   --> $DIR/fn-const-param-infer.rs:33:25
diff --git a/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr b/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr
index 1f67a5c09f1..a8b6f06ab1c 100644
--- a/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr
@@ -22,7 +22,7 @@ error: `Config` is forbidden as the type of a const generic parameter
 LL | struct B<const CFG: Config> {
    |                     ^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr b/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr
index 0e40255bcf5..d822fa5894a 100644
--- a/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr
@@ -12,7 +12,7 @@ error: `[usize; x]` is forbidden as the type of a const generic parameter
 LL | pub struct A<const z: [usize; x]> {}
    |                       ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr
index 15d3c472585..45be31c7ba3 100644
--- a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr
@@ -66,7 +66,7 @@ error: `[[usize; v4]; v4]` is forbidden as the type of a const generic parameter
 LL |     pub struct v17<const v10: usize, const v7: v11> {
    |                                                ^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/ice-118285-fn-ptr-value.stderr b/tests/ui/const-generics/ice-118285-fn-ptr-value.stderr
index 46a8a975d50..4ff386c8163 100644
--- a/tests/ui/const-generics/ice-118285-fn-ptr-value.stderr
+++ b/tests/ui/const-generics/ice-118285-fn-ptr-value.stderr
@@ -4,7 +4,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | struct Checked<const F: fn(usize) -> bool>;
    |                         ^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
index 2a6d9f53317..506f7d05fa6 100644
--- a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
+++ b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
@@ -13,7 +13,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter
 LL | trait Trait<const S: &'static str> {}
    |                      ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-56445-1.min.stderr b/tests/ui/const-generics/issues/issue-56445-1.min.stderr
index ff0a1bfc0b5..86eb57355bd 100644
--- a/tests/ui/const-generics/issues/issue-56445-1.min.stderr
+++ b/tests/ui/const-generics/issues/issue-56445-1.min.stderr
@@ -6,22 +6,6 @@ LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
    |
    = note: lifetime parameters may not be used in the type of const parameters
 
-error: `&str` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-56445-1.rs:9:25
-   |
-LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
-   |                         ^^^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
-   |
-LL + #![feature(unsized_const_params)]
-   |
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0770`.
diff --git a/tests/ui/const-generics/issues/issue-56445-1.rs b/tests/ui/const-generics/issues/issue-56445-1.rs
index 53aab40b0ad..681e0e147cf 100644
--- a/tests/ui/const-generics/issues/issue-56445-1.rs
+++ b/tests/ui/const-generics/issues/issue-56445-1.rs
@@ -8,6 +8,5 @@ use std::marker::PhantomData;
 
 struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
 //~^ ERROR: the type of const parameters must not depend on other generic parameters
-//[min]~| ERROR: `&str` is forbidden as the type of a const generic parameter
 
 impl Bug<'_, ""> {}
diff --git a/tests/ui/const-generics/issues/issue-62878.min.stderr b/tests/ui/const-generics/issues/issue-62878.min.stderr
index 5205726d738..bd17d70a50b 100644
--- a/tests/ui/const-generics/issues/issue-62878.min.stderr
+++ b/tests/ui/const-generics/issues/issue-62878.min.stderr
@@ -12,7 +12,7 @@ error: `[u8; N]` is forbidden as the type of a const generic parameter
 LL | fn foo<const N: usize, const A: [u8; N]>() {}
    |                                 ^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
index 101ca456cd9..f14485a4976 100644
--- a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
+++ b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
@@ -4,7 +4,7 @@ error: `&'static (dyn A + 'static)` is forbidden as the type of a const generic
 LL | fn test<const T: &'static dyn A>() {
    |                  ^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-68366.full.stderr b/tests/ui/const-generics/issues/issue-68366.full.stderr
index 3363a895e47..caed3c1bf3f 100644
--- a/tests/ui/const-generics/issues/issue-68366.full.stderr
+++ b/tests/ui/const-generics/issues/issue-68366.full.stderr
@@ -4,7 +4,7 @@ error: `Option<usize>` is forbidden as the type of a const generic parameter
 LL | struct Collatz<const N: Option<usize>>;
    |                         ^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-68366.min.stderr b/tests/ui/const-generics/issues/issue-68366.min.stderr
index 276f91e76dd..10b5a06682f 100644
--- a/tests/ui/const-generics/issues/issue-68366.min.stderr
+++ b/tests/ui/const-generics/issues/issue-68366.min.stderr
@@ -13,7 +13,7 @@ error: `Option<usize>` is forbidden as the type of a const generic parameter
 LL | struct Collatz<const N: Option<usize>>;
    |                         ^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-68615-adt.min.stderr b/tests/ui/const-generics/issues/issue-68615-adt.min.stderr
index 2f95eef98c0..d25b34435ed 100644
--- a/tests/ui/const-generics/issues/issue-68615-adt.min.stderr
+++ b/tests/ui/const-generics/issues/issue-68615-adt.min.stderr
@@ -4,7 +4,7 @@ error: `[usize; 0]` is forbidden as the type of a const generic parameter
 LL | struct Const<const V: [usize; 0]> {}
    |                       ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-68615-array.min.stderr b/tests/ui/const-generics/issues/issue-68615-array.min.stderr
index 6d18f8195d2..60cbc9b4eab 100644
--- a/tests/ui/const-generics/issues/issue-68615-array.min.stderr
+++ b/tests/ui/const-generics/issues/issue-68615-array.min.stderr
@@ -4,7 +4,7 @@ error: `[usize; 0]` is forbidden as the type of a const generic parameter
 LL | struct Foo<const V: [usize; 0] > {}
    |                     ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-71169.min.stderr b/tests/ui/const-generics/issues/issue-71169.min.stderr
index 94d11f969ff..2ecbc337951 100644
--- a/tests/ui/const-generics/issues/issue-71169.min.stderr
+++ b/tests/ui/const-generics/issues/issue-71169.min.stderr
@@ -12,7 +12,7 @@ error: `[u8; LEN]` is forbidden as the type of a const generic parameter
 LL | fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
    |                                      ^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-71381.min.stderr b/tests/ui/const-generics/issues/issue-71381.min.stderr
index e16d3b7a8a4..38d2cbe6368 100644
--- a/tests/ui/const-generics/issues/issue-71381.min.stderr
+++ b/tests/ui/const-generics/issues/issue-71381.min.stderr
@@ -20,7 +20,7 @@ error: using function pointers as const generic parameters is forbidden
 LL |     pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
    |                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: using function pointers as const generic parameters is forbidden
   --> $DIR/issue-71381.rs:23:19
@@ -28,7 +28,7 @@ error: using function pointers as const generic parameters is forbidden
 LL |         const FN: unsafe extern "C" fn(Args),
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/const-generics/issues/issue-71382.min.stderr b/tests/ui/const-generics/issues/issue-71382.min.stderr
index 0c58b10c0b7..f70e1733a97 100644
--- a/tests/ui/const-generics/issues/issue-71382.min.stderr
+++ b/tests/ui/const-generics/issues/issue-71382.min.stderr
@@ -4,7 +4,7 @@ error: using function pointers as const generic parameters is forbidden
 LL |     fn test<const FN: fn()>(&self) {
    |                       ^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/issues/issue-71611.min.stderr b/tests/ui/const-generics/issues/issue-71611.min.stderr
index b01936f4d25..7252bfd1d6a 100644
--- a/tests/ui/const-generics/issues/issue-71611.min.stderr
+++ b/tests/ui/const-generics/issues/issue-71611.min.stderr
@@ -12,7 +12,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | fn func<A, const F: fn(inner: A)>(outer: A) {
    |                     ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/issues/issue-72352.min.stderr b/tests/ui/const-generics/issues/issue-72352.min.stderr
index ede0faec7c6..17ccfa8a0da 100644
--- a/tests/ui/const-generics/issues/issue-72352.min.stderr
+++ b/tests/ui/const-generics/issues/issue-72352.min.stderr
@@ -4,7 +4,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | unsafe fn unsafely_do_the_thing<const F: fn(&CStr) -> usize>(ptr: *const c_char) -> usize {
    |                                          ^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/issues/issue-73491.min.stderr b/tests/ui/const-generics/issues/issue-73491.min.stderr
index 8fdd65894ef..2cdbeea2fd6 100644
--- a/tests/ui/const-generics/issues/issue-73491.min.stderr
+++ b/tests/ui/const-generics/issues/issue-73491.min.stderr
@@ -4,7 +4,7 @@ error: `[u32; LEN]` is forbidden as the type of a const generic parameter
 LL | fn hoge<const IN: [u32; LEN]>() {}
    |                   ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr b/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr
index cba03b1cb1f..256636c0628 100644
--- a/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr
+++ b/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr
@@ -4,7 +4,7 @@ error: `&'static [u32]` is forbidden as the type of a const generic parameter
 LL | fn a<const X: &'static [u32]>() {}
    |               ^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-74101.min.stderr b/tests/ui/const-generics/issues/issue-74101.min.stderr
index 236556addce..65fb51d7df9 100644
--- a/tests/ui/const-generics/issues/issue-74101.min.stderr
+++ b/tests/ui/const-generics/issues/issue-74101.min.stderr
@@ -4,7 +4,7 @@ error: `[u8; 1 + 2]` is forbidden as the type of a const generic parameter
 LL | fn test<const N: [u8; 1 + 2]>() {}
    |                  ^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -16,7 +16,7 @@ error: `[u8; 1 + 2]` is forbidden as the type of a const generic parameter
 LL | struct Foo<const N: [u8; 1 + 2]>;
    |                     ^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-74255.min.stderr b/tests/ui/const-generics/issues/issue-74255.min.stderr
index 800902860a7..3b30227a9a6 100644
--- a/tests/ui/const-generics/issues/issue-74255.min.stderr
+++ b/tests/ui/const-generics/issues/issue-74255.min.stderr
@@ -4,7 +4,7 @@ error: `IceEnum` is forbidden as the type of a const generic parameter
 LL |     fn ice_struct_fn<const I: IceEnum>() {}
    |                               ^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-74950.min.stderr b/tests/ui/const-generics/issues/issue-74950.min.stderr
index 086176d9959..22537af786b 100644
--- a/tests/ui/const-generics/issues/issue-74950.min.stderr
+++ b/tests/ui/const-generics/issues/issue-74950.min.stderr
@@ -4,7 +4,7 @@ error: `Inner` is forbidden as the type of a const generic parameter
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -16,7 +16,7 @@ error: `Inner` is forbidden as the type of a const generic parameter
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
@@ -29,7 +29,7 @@ error: `Inner` is forbidden as the type of a const generic parameter
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
@@ -42,7 +42,7 @@ error: `Inner` is forbidden as the type of a const generic parameter
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
diff --git a/tests/ui/const-generics/issues/issue-75047.min.stderr b/tests/ui/const-generics/issues/issue-75047.min.stderr
index f2cc76b9bed..d78ab671820 100644
--- a/tests/ui/const-generics/issues/issue-75047.min.stderr
+++ b/tests/ui/const-generics/issues/issue-75047.min.stderr
@@ -4,7 +4,7 @@ error: `[u8; Bar::<u32>::value()]` is forbidden as the type of a const generic p
 LL | struct Foo<const N: [u8; Bar::<u32>::value()]>;
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/issues/issue-82956.stderr b/tests/ui/const-generics/issues/issue-82956.stderr
index a956fc741f4..5e380eea81c 100644
--- a/tests/ui/const-generics/issues/issue-82956.stderr
+++ b/tests/ui/const-generics/issues/issue-82956.stderr
@@ -14,7 +14,7 @@ LL + use std::collections::btree_map::IntoIter;
    |
 LL + use std::collections::btree_set::IntoIter;
    |
-     and 8 other candidates
+     and 9 other candidates
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/lifetime-in-const-param.rs b/tests/ui/const-generics/lifetime-in-const-param.rs
index be90dbb213e..ce6b52b229f 100644
--- a/tests/ui/const-generics/lifetime-in-const-param.rs
+++ b/tests/ui/const-generics/lifetime-in-const-param.rs
@@ -4,6 +4,5 @@ struct S2<'b>(&'b ());
 
 struct S<'a, const N: S2>(&'a ());
 //~^ ERROR missing lifetime specifier [E0106]
-//~| ERROR `S2<'_>` is forbidden as the type of a const generic parameter
 
 fn main() {}
diff --git a/tests/ui/const-generics/lifetime-in-const-param.stderr b/tests/ui/const-generics/lifetime-in-const-param.stderr
index 4096725c52a..7c9d27c1e28 100644
--- a/tests/ui/const-generics/lifetime-in-const-param.stderr
+++ b/tests/ui/const-generics/lifetime-in-const-param.stderr
@@ -4,18 +4,6 @@ error[E0106]: missing lifetime specifier
 LL | struct S<'a, const N: S2>(&'a ());
    |                       ^^ expected named lifetime parameter
 
-error: `S2<'_>` is forbidden as the type of a const generic parameter
-  --> $DIR/lifetime-in-const-param.rs:5:23
-   |
-LL | struct S<'a, const N: S2>(&'a ());
-   |                       ^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0106`.
diff --git a/tests/ui/const-generics/min_const_generics/complex-types.stderr b/tests/ui/const-generics/min_const_generics/complex-types.stderr
index 0211770f9e5..bca68982c39 100644
--- a/tests/ui/const-generics/min_const_generics/complex-types.stderr
+++ b/tests/ui/const-generics/min_const_generics/complex-types.stderr
@@ -4,7 +4,7 @@ error: `[u8; 0]` is forbidden as the type of a const generic parameter
 LL | struct Foo<const N: [u8; 0]>;
    |                     ^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -16,7 +16,7 @@ error: `()` is forbidden as the type of a const generic parameter
 LL | struct Bar<const N: ()>;
    |                     ^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -28,7 +28,7 @@ error: `No` is forbidden as the type of a const generic parameter
 LL | struct Fez<const N: No>;
    |                     ^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -40,7 +40,7 @@ error: `&'static u8` is forbidden as the type of a const generic parameter
 LL | struct Faz<const N: &'static u8>;
    |                     ^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -56,7 +56,7 @@ error: `!` is forbidden as the type of a const generic parameter
 LL | struct Fiz<const N: !>;
    |                     ^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: `()` is forbidden as the type of a const generic parameter
   --> $DIR/complex-types.rs:20:19
@@ -64,7 +64,7 @@ error: `()` is forbidden as the type of a const generic parameter
 LL | enum Goo<const N: ()> { A, B }
    |                   ^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -76,7 +76,7 @@ error: `()` is forbidden as the type of a const generic parameter
 LL | union Boo<const N: ()> { a: () }
    |                    ^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/nested-type.min.stderr b/tests/ui/const-generics/nested-type.min.stderr
index 0da2b30e3f1..8696be3faf3 100644
--- a/tests/ui/const-generics/nested-type.min.stderr
+++ b/tests/ui/const-generics/nested-type.min.stderr
@@ -29,7 +29,7 @@ LL | |
 LL | | }]>;
    | |__^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/not_wf_param_in_rpitit.rs b/tests/ui/const-generics/not_wf_param_in_rpitit.rs
index 5471dc9022f..eb672194340 100644
--- a/tests/ui/const-generics/not_wf_param_in_rpitit.rs
+++ b/tests/ui/const-generics/not_wf_param_in_rpitit.rs
@@ -6,7 +6,6 @@ trait Trait<const N: Trait = bar> {
     //~| ERROR: the trait `Trait` cannot be made into an object
     //~| ERROR: the trait `Trait` cannot be made into an object
     //~| ERROR: the trait `Trait` cannot be made into an object
-    //~| ERROR: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
     //~| ERROR: trait objects must include the `dyn` keyword
     async fn a() {}
 }
diff --git a/tests/ui/const-generics/not_wf_param_in_rpitit.stderr b/tests/ui/const-generics/not_wf_param_in_rpitit.stderr
index 82e251f1306..ade40550c73 100644
--- a/tests/ui/const-generics/not_wf_param_in_rpitit.stderr
+++ b/tests/ui/const-generics/not_wf_param_in_rpitit.stderr
@@ -25,7 +25,7 @@ LL | trait Trait<const N: Trait = bar> {
    |                      ^^^^^ `Trait` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/not_wf_param_in_rpitit.rs:11:14
+  --> $DIR/not_wf_param_in_rpitit.rs:10:14
    |
 LL | trait Trait<const N: Trait = bar> {
    |       ----- this trait cannot be made into an object...
@@ -48,7 +48,7 @@ LL | trait Trait<const N: Trait = bar> {
    |             ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/not_wf_param_in_rpitit.rs:11:14
+  --> $DIR/not_wf_param_in_rpitit.rs:10:14
    |
 LL | trait Trait<const N: Trait = bar> {
    |       ----- this trait cannot be made into an object...
@@ -64,14 +64,6 @@ help: alternatively, consider constraining `a` so it does not apply to trait obj
 LL |     async fn a() where Self: Sized {}
    |                  +++++++++++++++++
 
-error: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
-  --> $DIR/not_wf_param_in_rpitit.rs:3:22
-   |
-LL | trait Trait<const N: Trait = bar> {
-   |                      ^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-
 error[E0038]: the trait `Trait` cannot be made into an object
   --> $DIR/not_wf_param_in_rpitit.rs:3:13
    |
@@ -79,7 +71,7 @@ LL | trait Trait<const N: Trait = bar> {
    |             ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/not_wf_param_in_rpitit.rs:11:14
+  --> $DIR/not_wf_param_in_rpitit.rs:10:14
    |
 LL | trait Trait<const N: Trait = bar> {
    |       ----- this trait cannot be made into an object...
@@ -107,7 +99,7 @@ help: add `dyn` keyword before this trait
 LL | trait Trait<const N: dyn Trait = bar> {
    |                      +++
 
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0038, E0391, E0425, E0782.
 For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/const-generics/opaque_types.stderr b/tests/ui/const-generics/opaque_types.stderr
index 3947d645fcb..a060488b328 100644
--- a/tests/ui/const-generics/opaque_types.stderr
+++ b/tests/ui/const-generics/opaque_types.stderr
@@ -1,3 +1,11 @@
+error: `Foo` is forbidden as the type of a const generic parameter
+  --> $DIR/opaque_types.rs:7:17
+   |
+LL | fn foo<const C: Foo>() {}
+   |                 ^^^
+   |
+   = note: the only supported types are integers, `bool`, and `char`
+
 error: item does not constrain `Foo::{opaque#0}`, but has it in its signature
   --> $DIR/opaque_types.rs:7:4
    |
@@ -68,14 +76,6 @@ LL | type Foo = impl Sized;
    |            ^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
-error: `Foo` is forbidden as the type of a const generic parameter
-  --> $DIR/opaque_types.rs:7:17
-   |
-LL | fn foo<const C: Foo>() {}
-   |                 ^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-
 error[E0391]: cycle detected when computing type of opaque `Foo::{opaque#0}`
   --> $DIR/opaque_types.rs:3:12
    |
diff --git a/tests/ui/const-generics/projection-as-arg-const.stderr b/tests/ui/const-generics/projection-as-arg-const.stderr
index 88672bce0a7..f6e7620db7d 100644
--- a/tests/ui/const-generics/projection-as-arg-const.stderr
+++ b/tests/ui/const-generics/projection-as-arg-const.stderr
@@ -4,7 +4,7 @@ error: `<i32 as Identity>::Identity` is forbidden as the type of a const generic
 LL | pub fn foo<const X: <i32 as Identity>::Identity>() {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr b/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr
index 6027dbb01cd..fca2966e3a3 100644
--- a/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr
+++ b/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr
@@ -4,7 +4,7 @@ error: using raw pointers as const generic parameters is forbidden
 LL | struct Const<const P: *const u32>;
    |                       ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: using raw pointers as const generic parameters is forbidden
   --> $DIR/raw-ptr-const-param-deref.rs:13:15
@@ -12,7 +12,7 @@ error: using raw pointers as const generic parameters is forbidden
 LL | impl<const P: *const u32> Const<P> {
    |               ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/raw-ptr-const-param.min.stderr b/tests/ui/const-generics/raw-ptr-const-param.min.stderr
index c48eea069e0..5694b12f2d5 100644
--- a/tests/ui/const-generics/raw-ptr-const-param.min.stderr
+++ b/tests/ui/const-generics/raw-ptr-const-param.min.stderr
@@ -4,7 +4,7 @@ error: using raw pointers as const generic parameters is forbidden
 LL | struct Const<const P: *const u32>;
    |                       ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error[E0308]: mismatched types
   --> $DIR/raw-ptr-const-param.rs:11:40
diff --git a/tests/ui/const-generics/slice-const-param-mismatch.min.stderr b/tests/ui/const-generics/slice-const-param-mismatch.min.stderr
index 3b2410c9894..594f8b9b79a 100644
--- a/tests/ui/const-generics/slice-const-param-mismatch.min.stderr
+++ b/tests/ui/const-generics/slice-const-param-mismatch.min.stderr
@@ -4,7 +4,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter
 LL | struct ConstString<const T: &'static str>;
    |                             ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -20,7 +20,7 @@ error: `&'static [u8]` is forbidden as the type of a const generic parameter
 LL | struct ConstBytes<const T: &'static [u8]>;
    |                            ^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/std/const-generics-range.min.stderr b/tests/ui/const-generics/std/const-generics-range.min.stderr
index 67f137cf1a0..fd23b9b248a 100644
--- a/tests/ui/const-generics/std/const-generics-range.min.stderr
+++ b/tests/ui/const-generics/std/const-generics-range.min.stderr
@@ -4,7 +4,7 @@ error: `std::ops::Range<usize>` is forbidden as the type of a const generic para
 LL | struct _Range<const R: std::ops::Range<usize>>;
    |                        ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -16,7 +16,7 @@ error: `RangeFrom<usize>` is forbidden as the type of a const generic parameter
 LL | struct _RangeFrom<const R: std::ops::RangeFrom<usize>>;
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -28,7 +28,7 @@ error: `RangeFull` is forbidden as the type of a const generic parameter
 LL | struct _RangeFull<const R: std::ops::RangeFull>;
    |                            ^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -40,7 +40,7 @@ error: `RangeInclusive<usize>` is forbidden as the type of a const generic param
 LL | struct _RangeInclusive<const R: std::ops::RangeInclusive<usize>>;
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -52,7 +52,7 @@ error: `RangeTo<usize>` is forbidden as the type of a const generic parameter
 LL | struct _RangeTo<const R: std::ops::RangeTo<usize>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -64,7 +64,7 @@ error: `RangeToInclusive<usize>` is forbidden as the type of a const generic par
 LL | struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>;
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr b/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr
index cf236487cf0..911afa3391d 100644
--- a/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr
+++ b/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr
@@ -4,7 +4,7 @@ error: `&'static ()` is forbidden as the type of a const generic parameter
 LL | struct Const<const P: &'static ()>;
    |                       ^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr
index 5aee282952a..8995c415863 100644
--- a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr
+++ b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr
@@ -12,7 +12,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter
 LL | trait Get<'a, const N: &'static str> {
    |                        ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -28,7 +28,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter
 LL |     fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
    |                         ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/const-generics/type-dependent/issue-71382.stderr b/tests/ui/const-generics/type-dependent/issue-71382.stderr
index 69fd6f1c7d5..3830b1527c3 100644
--- a/tests/ui/const-generics/type-dependent/issue-71382.stderr
+++ b/tests/ui/const-generics/type-dependent/issue-71382.stderr
@@ -4,7 +4,7 @@ error: using function pointers as const generic parameters is forbidden
 LL |     fn test<const FN: fn() -> u8>(&self) -> u8 {
    |                       ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/auxiliary/unstable_but_const_stable.rs b/tests/ui/consts/auxiliary/unstable_but_const_stable.rs
new file mode 100644
index 00000000000..88044b0272c
--- /dev/null
+++ b/tests/ui/consts/auxiliary/unstable_but_const_stable.rs
@@ -0,0 +1,13 @@
+#![feature(staged_api, rustc_attrs, intrinsics)]
+#![stable(since="1.0.0", feature = "stable")]
+
+extern "rust-intrinsic" {
+    #[unstable(feature = "unstable", issue = "42")]
+    #[rustc_const_stable(feature = "stable", since = "1.0.0")]
+    #[rustc_nounwind]
+    pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
+}
+
+#[unstable(feature = "unstable", issue = "42")]
+#[rustc_const_stable(feature = "stable", since = "1.0.0")]
+pub const fn some_unstable_fn() {}
diff --git a/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs
new file mode 100644
index 00000000000..19c78f019aa
--- /dev/null
+++ b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs
@@ -0,0 +1,70 @@
+const fn foo(ptr: *const u8) -> usize {
+    unsafe {
+        std::mem::transmute(ptr)
+        //~^ WARN pointers cannot be transmuted to integers
+    }
+}
+
+trait Human {
+    const ID: usize = {
+        let value = 10;
+        let ptr: *const usize = &value;
+        unsafe {
+            std::mem::transmute(ptr)
+            //~^ WARN pointers cannot be transmuted to integers
+        }
+    };
+
+    fn id_plus_one() -> usize {
+        Self::ID + 1
+    }
+}
+
+struct Type<T>(T);
+
+impl<T> Type<T> {
+    const ID: usize = {
+        let value = 10;
+        let ptr: *const usize = &value;
+        unsafe {
+            std::mem::transmute(ptr)
+            //~^ WARN pointers cannot be transmuted to integers
+        }
+    };
+
+    fn id_plus_one() -> usize {
+        Self::ID + 1
+    }
+}
+
+fn control(ptr: *const u8) -> usize {
+    unsafe {
+        std::mem::transmute(ptr)
+    }
+}
+
+struct ControlStruct;
+
+impl ControlStruct {
+    fn new() -> usize {
+        let value = 10;
+        let ptr: *const i32 = &value;
+        unsafe {
+            std::mem::transmute(ptr)
+        }
+    }
+}
+
+
+const fn zoom(ptr: *const u8) -> usize {
+    unsafe {
+        std::mem::transmute(ptr)
+        //~^ WARN pointers cannot be transmuted to integers
+    }
+}
+
+fn main() {
+    const a: u8 = 10;
+    const value: usize = zoom(&a);
+    //~^ ERROR evaluation of constant value failed
+}
diff --git a/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr
new file mode 100644
index 00000000000..ca6ad9408ab
--- /dev/null
+++ b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr
@@ -0,0 +1,53 @@
+warning: pointers cannot be transmuted to integers during const eval
+  --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:61:9
+   |
+LL |         std::mem::transmute(ptr)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: at compile-time, pointers do not have an integer value
+   = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
+   = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
+   = note: `#[warn(ptr_to_integer_transmute_in_consts)]` on by default
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:68:26
+   |
+LL |     const value: usize = zoom(&a);
+   |                          ^^^^^^^^ unable to turn pointer into integer
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+warning: pointers cannot be transmuted to integers during const eval
+  --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:3:9
+   |
+LL |         std::mem::transmute(ptr)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: at compile-time, pointers do not have an integer value
+   = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
+   = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
+
+warning: pointers cannot be transmuted to integers during const eval
+  --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:13:13
+   |
+LL |             std::mem::transmute(ptr)
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: at compile-time, pointers do not have an integer value
+   = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
+   = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
+
+warning: pointers cannot be transmuted to integers during const eval
+  --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:30:13
+   |
+LL |             std::mem::transmute(ptr)
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: at compile-time, pointers do not have an integer value
+   = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
+   = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
+
+error: aborting due to 1 previous error; 4 warnings emitted
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/issue-103790.rs b/tests/ui/consts/issue-103790.rs
index d19115ede74..869a43e4018 100644
--- a/tests/ui/consts/issue-103790.rs
+++ b/tests/ui/consts/issue-103790.rs
@@ -6,6 +6,5 @@ struct S<const S: (), const S: S = { S }>;
 //~| ERROR missing generics for struct `S`
 //~| ERROR cycle detected when computing type of `S::S`
 //~| ERROR `()` is forbidden as the type of a const generic parameter
-//~| ERROR `S<{const error}, {const error}>` is forbidden as the type of a const generic parameter
 
 fn main() {}
diff --git a/tests/ui/consts/issue-103790.stderr b/tests/ui/consts/issue-103790.stderr
index c671f078cb5..1515fa60a5c 100644
--- a/tests/ui/consts/issue-103790.stderr
+++ b/tests/ui/consts/issue-103790.stderr
@@ -42,25 +42,13 @@ error: `()` is forbidden as the type of a const generic parameter
 LL | struct S<const S: (), const S: S = { S }>;
    |                   ^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
    |
 
-error: `S<{const error}, {const error}>` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-103790.rs:4:32
-   |
-LL | struct S<const S: (), const S: S = { S }>;
-   |                                ^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0107, E0391, E0403.
 For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs
index 56c4b6ea36f..2e30eebb07b 100644
--- a/tests/ui/consts/issue-94675.rs
+++ b/tests/ui/consts/issue-94675.rs
@@ -1,6 +1,6 @@
 //@ known-bug: #103507
 
-#![feature(const_trait_impl)]
+#![feature(const_trait_impl, const_vec_string_slice)]
 
 struct Foo<'a> {
     bar: &'a mut Vec<usize>,
diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr
index ebfa09b2e5d..a85c5e10374 100644
--- a/tests/ui/consts/issue-94675.stderr
+++ b/tests/ui/consts/issue-94675.stderr
@@ -1,11 +1,3 @@
-error[E0015]: cannot call non-const fn `Vec::<u32>::len` in constant functions
-  --> $DIR/issue-94675.rs:11:27
-   |
-LL |         self.bar[0] = baz.len();
-   |                           ^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-
 error[E0015]: cannot call non-const operator in constant functions
   --> $DIR/issue-94675.rs:11:17
    |
@@ -20,6 +12,6 @@ help: add `#![feature(effects)]` to the crate attributes to enable
 LL + #![feature(effects)]
    |
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr b/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr
index 3b861d784d8..19e7a723a22 100644
--- a/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr
+++ b/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr
@@ -1,4 +1,4 @@
-error[E0607]: cannot cast thin pointer `*const [i64; 0]` to fat pointer `*const [u8]`
+error[E0607]: cannot cast thin pointer `*const [i64; 0]` to wide pointer `*const [u8]`
   --> $DIR/slice_elem_ty_mismatch_in_unsizing_cast.rs:1:31
    |
 LL | const FOO: &str = unsafe { &*(1_usize as *const [i64; 0] as *const [u8] as *const str) };
diff --git a/tests/ui/consts/unstable-const-stable.rs b/tests/ui/consts/unstable-const-stable.rs
new file mode 100644
index 00000000000..f69e8d0efe5
--- /dev/null
+++ b/tests/ui/consts/unstable-const-stable.rs
@@ -0,0 +1,14 @@
+//@ aux-build:unstable_but_const_stable.rs
+
+extern crate unstable_but_const_stable;
+use unstable_but_const_stable::*;
+
+fn main() {
+    some_unstable_fn(); //~ERROR use of unstable library feature
+    unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature
+}
+
+const fn const_main() {
+    some_unstable_fn(); //~ERROR use of unstable library feature
+    unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature
+}
diff --git a/tests/ui/consts/unstable-const-stable.stderr b/tests/ui/consts/unstable-const-stable.stderr
new file mode 100644
index 00000000000..c4ffbbb60db
--- /dev/null
+++ b/tests/ui/consts/unstable-const-stable.stderr
@@ -0,0 +1,43 @@
+error[E0658]: use of unstable library feature 'unstable'
+  --> $DIR/unstable-const-stable.rs:7:5
+   |
+LL |     some_unstable_fn();
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'unstable'
+  --> $DIR/unstable-const-stable.rs:8:14
+   |
+LL |     unsafe { write_bytes(4 as *mut u8, 0, 0) };
+   |              ^^^^^^^^^^^
+   |
+   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'unstable'
+  --> $DIR/unstable-const-stable.rs:12:5
+   |
+LL |     some_unstable_fn();
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'unstable'
+  --> $DIR/unstable-const-stable.rs:13:14
+   |
+LL |     unsafe { write_bytes(4 as *mut u8, 0, 0) };
+   |              ^^^^^^^^^^^
+   |
+   = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+   = help: add `#![feature(unstable)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/coverage-attr/bad-attr-ice.feat.stderr b/tests/ui/coverage-attr/bad-attr-ice.feat.stderr
new file mode 100644
index 00000000000..9e3cd41c277
--- /dev/null
+++ b/tests/ui/coverage-attr/bad-attr-ice.feat.stderr
@@ -0,0 +1,15 @@
+error: malformed `coverage` attribute input
+  --> $DIR/bad-attr-ice.rs:10:1
+   |
+LL | #[coverage]
+   | ^^^^^^^^^^^
+   |
+help: the following are the possible correct uses
+   |
+LL | #[coverage(off)]
+   |
+LL | #[coverage(on)]
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr b/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr
new file mode 100644
index 00000000000..d73636e158b
--- /dev/null
+++ b/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr
@@ -0,0 +1,26 @@
+error: malformed `coverage` attribute input
+  --> $DIR/bad-attr-ice.rs:10:1
+   |
+LL | #[coverage]
+   | ^^^^^^^^^^^
+   |
+help: the following are the possible correct uses
+   |
+LL | #[coverage(off)]
+   |
+LL | #[coverage(on)]
+   |
+
+error[E0658]: the `#[coverage]` attribute is an experimental feature
+  --> $DIR/bad-attr-ice.rs:10:1
+   |
+LL | #[coverage]
+   | ^^^^^^^^^^^
+   |
+   = note: see issue #84605 <https://github.com/rust-lang/rust/issues/84605> for more information
+   = help: add `#![feature(coverage_attribute)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/coverage-attr/bad-attr-ice.rs b/tests/ui/coverage-attr/bad-attr-ice.rs
new file mode 100644
index 00000000000..ae4d27d65eb
--- /dev/null
+++ b/tests/ui/coverage-attr/bad-attr-ice.rs
@@ -0,0 +1,16 @@
+#![cfg_attr(feat, feature(coverage_attribute))]
+//@ revisions: feat nofeat
+//@ compile-flags: -Cinstrument-coverage
+//@ needs-profiler-support
+
+// Malformed `#[coverage(..)]` attributes should not cause an ICE when built
+// with `-Cinstrument-coverage`.
+// Regression test for <https://github.com/rust-lang/rust/issues/127880>.
+
+#[coverage]
+//~^ ERROR malformed `coverage` attribute input
+//[nofeat]~| the `#[coverage]` attribute is an experimental feature
+fn main() {}
+
+// FIXME(#130766): When the `#[coverage(..)]` attribute is stabilized,
+// get rid of the revisions and just make this a normal test.
diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr
index 03ded300bb4..6a627be3b64 100644
--- a/tests/ui/delegation/unsupported.stderr
+++ b/tests/ui/delegation/unsupported.stderr
@@ -3,22 +3,6 @@ error: using `#![feature(effects)]` without enabling next trait solver globally
    = note: the next trait solver must be enabled globally for the effects feature to work correctly
    = help: use `-Znext-solver` to enable
 
-warning: this function depends on never type fallback being `()`
-  --> $DIR/unsupported.rs:20:9
-   |
-LL |         fn opaque_ret() -> impl Trait { unimplemented!() }
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
-   = help: specify the types explicitly
-note: in edition 2024, the requirement `!: opaque::Trait` will fail
-  --> $DIR/unsupported.rs:20:28
-   |
-LL |         fn opaque_ret() -> impl Trait { unimplemented!() }
-   |                            ^^^^^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
-
 error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:26:5: 26:24>::{synthetic#0}`
   --> $DIR/unsupported.rs:27:25
    |
@@ -52,6 +36,22 @@ note: in edition 2024, the requirement `!: opaque::Trait` will fail
    |
 LL |         pub fn opaque_ret() -> impl Trait { unimplemented!() }
    |                                ^^^^^^^^^^
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+
+warning: this function depends on never type fallback being `()`
+  --> $DIR/unsupported.rs:20:9
+   |
+LL |         fn opaque_ret() -> impl Trait { unimplemented!() }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the types explicitly
+note: in edition 2024, the requirement `!: opaque::Trait` will fail
+  --> $DIR/unsupported.rs:20:28
+   |
+LL |         fn opaque_ret() -> impl Trait { unimplemented!() }
+   |                            ^^^^^^^^^^
 
 error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:29:5: 29:25>::{synthetic#0}`
   --> $DIR/unsupported.rs:30:24
diff --git a/tests/ui/drop/lint-if-let-rescope.fixed b/tests/ui/drop/lint-if-let-rescope.fixed
index f228783f88b..199068d0fd2 100644
--- a/tests/ui/drop/lint-if-let-rescope.fixed
+++ b/tests/ui/drop/lint-if-let-rescope.fixed
@@ -1,8 +1,8 @@
 //@ run-rustfix
 
 #![deny(if_let_rescope)]
-#![feature(if_let_rescope)]
-#![allow(irrefutable_let_patterns)]
+#![feature(if_let_rescope, stmt_expr_attributes)]
+#![allow(irrefutable_let_patterns, unused_parens)]
 
 fn droppy() -> Droppy {
     Droppy
@@ -68,4 +68,30 @@ fn main() {
         //~| HELP: the value is now dropped here in Edition 2024
         //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
     }
+
+    #[rustfmt::skip]
+    if (match droppy().get() { Some(_value) => { true } _ => { false }}) {
+        //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
+        //~| WARN: this changes meaning in Rust 2024
+        //~| HELP: the value is now dropped here in Edition 2024
+        //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
+        // do something
+    } else if (((match droppy().get() { Some(_value) => { true } _ => { false }}))) {
+        //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
+        //~| WARN: this changes meaning in Rust 2024
+        //~| HELP: the value is now dropped here in Edition 2024
+        //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
+    }
+
+    while let Some(_value) = droppy().get() {
+        // Should not lint
+        break;
+    }
+
+    while (match droppy().get() { Some(_value) => { false } _ => { true }}) {
+        //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
+        //~| WARN: this changes meaning in Rust 2024
+        //~| HELP: the value is now dropped here in Edition 2024
+        //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
+    }
 }
diff --git a/tests/ui/drop/lint-if-let-rescope.rs b/tests/ui/drop/lint-if-let-rescope.rs
index 241fb897fce..4c043c0266c 100644
--- a/tests/ui/drop/lint-if-let-rescope.rs
+++ b/tests/ui/drop/lint-if-let-rescope.rs
@@ -1,8 +1,8 @@
 //@ run-rustfix
 
 #![deny(if_let_rescope)]
-#![feature(if_let_rescope)]
-#![allow(irrefutable_let_patterns)]
+#![feature(if_let_rescope, stmt_expr_attributes)]
+#![allow(irrefutable_let_patterns, unused_parens)]
 
 fn droppy() -> Droppy {
     Droppy
@@ -68,4 +68,30 @@ fn main() {
         //~| HELP: the value is now dropped here in Edition 2024
         //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
     }
+
+    #[rustfmt::skip]
+    if (if let Some(_value) = droppy().get() { true } else { false }) {
+        //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
+        //~| WARN: this changes meaning in Rust 2024
+        //~| HELP: the value is now dropped here in Edition 2024
+        //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
+        // do something
+    } else if (((if let Some(_value) = droppy().get() { true } else { false }))) {
+        //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
+        //~| WARN: this changes meaning in Rust 2024
+        //~| HELP: the value is now dropped here in Edition 2024
+        //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
+    }
+
+    while let Some(_value) = droppy().get() {
+        // Should not lint
+        break;
+    }
+
+    while (if let Some(_value) = droppy().get() { false } else { true }) {
+        //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
+        //~| WARN: this changes meaning in Rust 2024
+        //~| HELP: the value is now dropped here in Edition 2024
+        //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
+    }
 }
diff --git a/tests/ui/drop/lint-if-let-rescope.stderr b/tests/ui/drop/lint-if-let-rescope.stderr
index 25ca3cf1ca8..ef60d141b79 100644
--- a/tests/ui/drop/lint-if-let-rescope.stderr
+++ b/tests/ui/drop/lint-if-let-rescope.stderr
@@ -131,5 +131,65 @@ help: a `match` with a single arm can preserve the drop order up to Edition 2021
 LL |     if let () = { match Droppy.get() { Some(_value) => {} _ => {}} } {
    |                   ~~~~~              +++++++++++++++++    ++++++++
 
-error: aborting due to 5 previous errors
+error: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/lint-if-let-rescope.rs:73:12
+   |
+LL |     if (if let Some(_value) = droppy().get() { true } else { false }) {
+   |            ^^^^^^^^^^^^^^^^^^^--------^^^^^^
+   |                               |
+   |                               this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #124085 <https://github.com/rust-lang/rust/issues/124085>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/lint-if-let-rescope.rs:73:53
+   |
+LL |     if (if let Some(_value) = droppy().get() { true } else { false }) {
+   |                                                     ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL |     if (match droppy().get() { Some(_value) => { true } _ => { false }}) {
+   |         ~~~~~                +++++++++++++++++          ~~~~          +
+
+error: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/lint-if-let-rescope.rs:79:21
+   |
+LL |     } else if (((if let Some(_value) = droppy().get() { true } else { false }))) {
+   |                     ^^^^^^^^^^^^^^^^^^^--------^^^^^^
+   |                                        |
+   |                                        this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #124085 <https://github.com/rust-lang/rust/issues/124085>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/lint-if-let-rescope.rs:79:62
+   |
+LL |     } else if (((if let Some(_value) = droppy().get() { true } else { false }))) {
+   |                                                              ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL |     } else if (((match droppy().get() { Some(_value) => { true } _ => { false }}))) {
+   |                  ~~~~~                +++++++++++++++++          ~~~~          +
+
+error: `if let` assigns a shorter lifetime since Edition 2024
+  --> $DIR/lint-if-let-rescope.rs:91:15
+   |
+LL |     while (if let Some(_value) = droppy().get() { false } else { true }) {
+   |               ^^^^^^^^^^^^^^^^^^^--------^^^^^^
+   |                                  |
+   |                                  this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #124085 <https://github.com/rust-lang/rust/issues/124085>
+help: the value is now dropped here in Edition 2024
+  --> $DIR/lint-if-let-rescope.rs:91:57
+   |
+LL |     while (if let Some(_value) = droppy().get() { false } else { true }) {
+   |                                                         ^
+help: a `match` with a single arm can preserve the drop order up to Edition 2021
+   |
+LL |     while (match droppy().get() { Some(_value) => { false } _ => { true }}) {
+   |            ~~~~~                +++++++++++++++++           ~~~~         +
+
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/error-codes/E0607.stderr b/tests/ui/error-codes/E0607.stderr
index 835ababf449..3fa134c2028 100644
--- a/tests/ui/error-codes/E0607.stderr
+++ b/tests/ui/error-codes/E0607.stderr
@@ -1,4 +1,4 @@
-error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]`
+error[E0607]: cannot cast thin pointer `*const u8` to wide pointer `*const [u8]`
   --> $DIR/E0607.rs:3:5
    |
 LL |     v as *const [u8];
diff --git a/tests/ui/error-festival.stderr b/tests/ui/error-festival.stderr
index 9d75671c4e6..26393352b2b 100644
--- a/tests/ui/error-festival.stderr
+++ b/tests/ui/error-festival.stderr
@@ -81,7 +81,7 @@ help: dereference the expression
 LL |     let y: u32 = *x as u32;
    |                  +
 
-error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]`
+error[E0607]: cannot cast thin pointer `*const u8` to wide pointer `*const [u8]`
   --> $DIR/error-festival.rs:41:5
    |
 LL |     v as *const [u8];
diff --git a/tests/ui/errors/remap-path-prefix-sysroot.rs b/tests/ui/errors/remap-path-prefix-sysroot.rs
new file mode 100644
index 00000000000..4cbb38709be
--- /dev/null
+++ b/tests/ui/errors/remap-path-prefix-sysroot.rs
@@ -0,0 +1,24 @@
+//@ revisions: with-remap without-remap
+//@ compile-flags: -g -Ztranslate-remapped-path-to-local-path=yes
+//@ [with-remap]compile-flags: --remap-path-prefix={{rust-src-base}}=remapped
+//@ [with-remap]compile-flags: --remap-path-prefix={{src-base}}=remapped-tests-ui
+//@ [without-remap]compile-flags:
+//@ error-pattern: E0507
+
+// The $SRC_DIR*.rs:LL:COL normalisation doesn't kick in automatically
+// as the remapped revision will not begin with $SRC_DIR_REAL,
+// so we have to do it ourselves.
+//@ normalize-stderr-test: ".rs:\d+:\d+" -> ".rs:LL:COL"
+
+use std::thread;
+struct Worker {
+    thread: thread::JoinHandle<()>,
+}
+
+impl Drop for Worker {
+    fn drop(&mut self) {
+        self.thread.join().unwrap();
+    }
+}
+
+pub fn main(){}
diff --git a/tests/ui/errors/remap-path-prefix-sysroot.with-remap.stderr b/tests/ui/errors/remap-path-prefix-sysroot.with-remap.stderr
new file mode 100644
index 00000000000..88d713d2b04
--- /dev/null
+++ b/tests/ui/errors/remap-path-prefix-sysroot.with-remap.stderr
@@ -0,0 +1,17 @@
+error[E0507]: cannot move out of `self.thread` which is behind a mutable reference
+  --> remapped-tests-ui/errors/remap-path-prefix-sysroot.rs:LL:COL
+   |
+LL |         self.thread.join().unwrap();
+   |         ^^^^^^^^^^^ ------ `self.thread` moved due to this method call
+   |         |
+   |         move occurs because `self.thread` has type `JoinHandle<()>`, which does not implement the `Copy` trait
+   |
+note: `JoinHandle::<T>::join` takes ownership of the receiver `self`, which moves `self.thread`
+  --> remapped/library/std/src/thread/mod.rs:LL:COL
+   |
+LL |     pub fn join(self) -> Result<T> {
+   |                 ^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/errors/remap-path-prefix-sysroot.without-remap.stderr b/tests/ui/errors/remap-path-prefix-sysroot.without-remap.stderr
new file mode 100644
index 00000000000..9b337699c32
--- /dev/null
+++ b/tests/ui/errors/remap-path-prefix-sysroot.without-remap.stderr
@@ -0,0 +1,17 @@
+error[E0507]: cannot move out of `self.thread` which is behind a mutable reference
+  --> $DIR/remap-path-prefix-sysroot.rs:LL:COL
+   |
+LL |         self.thread.join().unwrap();
+   |         ^^^^^^^^^^^ ------ `self.thread` moved due to this method call
+   |         |
+   |         move occurs because `self.thread` has type `JoinHandle<()>`, which does not implement the `Copy` trait
+   |
+note: `JoinHandle::<T>::join` takes ownership of the receiver `self`, which moves `self.thread`
+  --> $SRC_DIR_REAL/std/src/thread/mod.rs:LL:COL
+   |
+LL |     pub fn join(self) -> Result<T> {
+   |                 ^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/feature-gates/feature-gate-adt_const_params.stderr b/tests/ui/feature-gates/feature-gate-adt_const_params.stderr
index 649e936888b..18d514f8cb5 100644
--- a/tests/ui/feature-gates/feature-gate-adt_const_params.stderr
+++ b/tests/ui/feature-gates/feature-gate-adt_const_params.stderr
@@ -4,7 +4,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter
 LL | struct Foo<const NAME: &'static str>;
    |                        ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs
new file mode 100644
index 00000000000..6784b445049
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs
@@ -0,0 +1,10 @@
+#[cfg(true)] //~ ERROR `cfg(true)` is experimental
+fn foo() {}
+
+#[cfg_attr(true, cfg(false))] //~ ERROR `cfg(true)` is experimental
+//~^ ERROR `cfg(false)` is experimental
+fn foo() {}
+
+fn main() {
+    cfg!(false); //~ ERROR `cfg(false)` is experimental
+}
diff --git a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr
new file mode 100644
index 00000000000..64491464f1d
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr
@@ -0,0 +1,43 @@
+error[E0658]: `cfg(true)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-boolean-literals.rs:1:7
+   |
+LL | #[cfg(true)]
+   |       ^^^^
+   |
+   = note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
+   = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `cfg(true)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-boolean-literals.rs:4:12
+   |
+LL | #[cfg_attr(true, cfg(false))]
+   |            ^^^^
+   |
+   = note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
+   = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `cfg(false)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-boolean-literals.rs:4:22
+   |
+LL | #[cfg_attr(true, cfg(false))]
+   |                      ^^^^^
+   |
+   = note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
+   = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `cfg(false)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-boolean-literals.rs:9:10
+   |
+LL |     cfg!(false);
+   |          ^^^^^
+   |
+   = note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
+   = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr
index d8a85c8838d..7dfd79c7286 100644
--- a/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr
+++ b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr
@@ -18,14 +18,6 @@ LL |     type Bop = impl std::fmt::Debug;
    = help: add `#![feature(impl_trait_in_assoc_type)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: unconstrained opaque type
-  --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:6:16
-   |
-LL |     type Bar = impl std::fmt::Debug;
-   |                ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `Bar` must be used in combination with a concrete type within the same impl
-
 error[E0658]: inherent associated types are unstable
   --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:14:5
    |
@@ -37,6 +29,14 @@ LL |     type Bop = impl std::fmt::Debug;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: unconstrained opaque type
+  --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:6:16
+   |
+LL |     type Bar = impl std::fmt::Debug;
+   |                ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Bar` must be used in combination with a concrete type within the same impl
+
+error: unconstrained opaque type
   --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:14:16
    |
 LL |     type Bop = impl std::fmt::Debug;
diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.rs b/tests/ui/feature-gates/feature-gate-naked_functions.rs
index 36980fd74c2..5fe0bbdc774 100644
--- a/tests/ui/feature-gates/feature-gate-naked_functions.rs
+++ b/tests/ui/feature-gates/feature-gate-naked_functions.rs
@@ -1,19 +1,22 @@
 //@ needs-asm-support
 
-use std::arch::asm;
+use std::arch::naked_asm;
+//~^ ERROR use of unstable library feature 'naked_functions'
 
 #[naked]
 //~^ the `#[naked]` attribute is an experimental feature
 extern "C" fn naked() {
-    asm!("", options(noreturn))
-    //~^ ERROR: requires unsafe
+    naked_asm!("")
+    //~^ ERROR use of unstable library feature 'naked_functions'
+    //~| ERROR: requires unsafe
 }
 
 #[naked]
 //~^ the `#[naked]` attribute is an experimental feature
 extern "C" fn naked_2() -> isize {
-    asm!("", options(noreturn))
-    //~^ ERROR: requires unsafe
+    naked_asm!("")
+    //~^ ERROR use of unstable library feature 'naked_functions'
+    //~| ERROR: requires unsafe
 }
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.stderr b/tests/ui/feature-gates/feature-gate-naked_functions.stderr
index ffdf31e147a..709234eb023 100644
--- a/tests/ui/feature-gates/feature-gate-naked_functions.stderr
+++ b/tests/ui/feature-gates/feature-gate-naked_functions.stderr
@@ -1,5 +1,25 @@
+error[E0658]: use of unstable library feature 'naked_functions'
+  --> $DIR/feature-gate-naked_functions.rs:9:5
+   |
+LL |     naked_asm!("")
+   |     ^^^^^^^^^
+   |
+   = note: see issue #90957 <https://github.com/rust-lang/rust/issues/90957> for more information
+   = help: add `#![feature(naked_functions)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'naked_functions'
+  --> $DIR/feature-gate-naked_functions.rs:17:5
+   |
+LL |     naked_asm!("")
+   |     ^^^^^^^^^
+   |
+   = note: see issue #90957 <https://github.com/rust-lang/rust/issues/90957> for more information
+   = help: add `#![feature(naked_functions)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
 error[E0658]: the `#[naked]` attribute is an experimental feature
-  --> $DIR/feature-gate-naked_functions.rs:5:1
+  --> $DIR/feature-gate-naked_functions.rs:6:1
    |
 LL | #[naked]
    | ^^^^^^^^
@@ -9,7 +29,7 @@ LL | #[naked]
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the `#[naked]` attribute is an experimental feature
-  --> $DIR/feature-gate-naked_functions.rs:12:1
+  --> $DIR/feature-gate-naked_functions.rs:14:1
    |
 LL | #[naked]
    | ^^^^^^^^
@@ -18,23 +38,33 @@ LL | #[naked]
    = help: add `#![feature(naked_functions)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
+error[E0658]: use of unstable library feature 'naked_functions'
+  --> $DIR/feature-gate-naked_functions.rs:3:5
+   |
+LL | use std::arch::naked_asm;
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #90957 <https://github.com/rust-lang/rust/issues/90957> for more information
+   = help: add `#![feature(naked_functions)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
 error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
-  --> $DIR/feature-gate-naked_functions.rs:8:5
+  --> $DIR/feature-gate-naked_functions.rs:9:5
    |
-LL |     asm!("", options(noreturn))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of inline assembly
+LL |     naked_asm!("")
+   |     ^^^^^^^^^^^^^^ use of inline assembly
    |
    = note: inline assembly is entirely unchecked and can cause undefined behavior
 
 error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
-  --> $DIR/feature-gate-naked_functions.rs:15:5
+  --> $DIR/feature-gate-naked_functions.rs:17:5
    |
-LL |     asm!("", options(noreturn))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of inline assembly
+LL |     naked_asm!("")
+   |     ^^^^^^^^^^^^^^ use of inline assembly
    |
    = note: inline assembly is entirely unchecked and can cause undefined behavior
 
-error: aborting due to 4 previous errors
+error: aborting due to 7 previous errors
 
 Some errors have detailed explanations: E0133, E0658.
 For more information about an error, try `rustc --explain E0133`.
diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs
index d694531d53a..3382504af9d 100644
--- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs
+++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs
@@ -4,6 +4,11 @@ use std::pin::Pin;
 
 struct Foo;
 
+impl Foo {
+    fn foo(self: Pin<&mut Self>) {
+    }
+}
+
 fn foo(_: Pin<&mut Foo>) {
 }
 
@@ -12,4 +17,9 @@ fn bar(mut x: Pin<&mut Foo>) {
     foo(x); //~ ERROR use of moved value: `x`
 }
 
+fn baz(mut x: Pin<&mut Foo>) {
+    x.foo();
+    x.foo(); //~ ERROR use of moved value: `x`
+}
+
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr
index 6c9029d8176..430b7866241 100644
--- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr
+++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `x`
-  --> $DIR/feature-gate-pin_ergonomics.rs:12:9
+  --> $DIR/feature-gate-pin_ergonomics.rs:17:9
    |
 LL | fn bar(mut x: Pin<&mut Foo>) {
    |        ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
@@ -9,13 +9,33 @@ LL |     foo(x);
    |         ^ value used here after move
    |
 note: consider changing this parameter type in function `foo` to borrow instead if owning the value isn't necessary
-  --> $DIR/feature-gate-pin_ergonomics.rs:7:11
+  --> $DIR/feature-gate-pin_ergonomics.rs:12:11
    |
 LL | fn foo(_: Pin<&mut Foo>) {
    |    ---    ^^^^^^^^^^^^^ this parameter takes ownership of the value
    |    |
    |    in this function
 
-error: aborting due to 1 previous error
+error[E0382]: use of moved value: `x`
+  --> $DIR/feature-gate-pin_ergonomics.rs:22:5
+   |
+LL | fn baz(mut x: Pin<&mut Foo>) {
+   |        ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
+LL |     x.foo();
+   |       ----- `x` moved due to this method call
+LL |     x.foo();
+   |     ^ value used here after move
+   |
+note: `Foo::foo` takes ownership of the receiver `self`, which moves `x`
+  --> $DIR/feature-gate-pin_ergonomics.rs:8:12
+   |
+LL |     fn foo(self: Pin<&mut Self>) {
+   |            ^^^^
+help: consider reborrowing the `Pin` instead of moving it
+   |
+LL |     x.as_mut().foo();
+   |      +++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr b/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr
index 0a87f34f4f5..85ca2f59cb6 100644
--- a/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr
+++ b/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr
@@ -4,7 +4,7 @@ error: `[u8]` is forbidden as the type of a const generic parameter
 LL | struct Foo<const N: [u8]>;
    |                     ^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/float/classify-runtime-const.rs b/tests/ui/float/classify-runtime-const.rs
index b19e67d5284..ca852ea2468 100644
--- a/tests/ui/float/classify-runtime-const.rs
+++ b/tests/ui/float/classify-runtime-const.rs
@@ -6,9 +6,8 @@
 
 // This tests the float classification functions, for regular runtime code and for const evaluation.
 
-#![feature(f16_const)]
-#![feature(f128_const)]
-#![feature(const_float_classify)]
+#![feature(f16)]
+#![feature(f128)]
 
 use std::num::FpCategory::*;
 
diff --git a/tests/ui/float/conv-bits-runtime-const.rs b/tests/ui/float/conv-bits-runtime-const.rs
index e85a889d2c2..3046728fe66 100644
--- a/tests/ui/float/conv-bits-runtime-const.rs
+++ b/tests/ui/float/conv-bits-runtime-const.rs
@@ -3,11 +3,8 @@
 
 // This tests the float classification functions, for regular runtime code and for const evaluation.
 
-#![feature(const_float_classify)]
 #![feature(f16)]
 #![feature(f128)]
-#![feature(f16_const)]
-#![feature(f128_const)]
 #![allow(unused_macro_rules)]
 
 use std::hint::black_box;
diff --git a/tests/ui/generic-associated-types/self-outlives-lint.stderr b/tests/ui/generic-associated-types/self-outlives-lint.stderr
index 9e9b2e18abe..58172bf06b5 100644
--- a/tests/ui/generic-associated-types/self-outlives-lint.stderr
+++ b/tests/ui/generic-associated-types/self-outlives-lint.stderr
@@ -108,17 +108,6 @@ LL |     type Bar<'b>;
    = note: this bound is currently required to ensure that impls have maximum flexibility
    = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
 
-error: missing required bound on `Iterator`
-  --> $DIR/self-outlives-lint.rs:142:5
-   |
-LL |     type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |                                                       |
-   |                                                       help: add the required where clause: `where Self: 'a`
-   |
-   = note: this bound is currently required to ensure that impls have maximum flexibility
-   = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
-
 error: missing required bound on `Item`
   --> $DIR/self-outlives-lint.rs:140:5
    |
@@ -130,6 +119,17 @@ LL |     type Item<'a>;
    = note: this bound is currently required to ensure that impls have maximum flexibility
    = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
 
+error: missing required bound on `Iterator`
+  --> $DIR/self-outlives-lint.rs:142:5
+   |
+LL |     type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                                       |
+   |                                                       help: add the required where clause: `where Self: 'a`
+   |
+   = note: this bound is currently required to ensure that impls have maximum flexibility
+   = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
+
 error: missing required bound on `Item`
   --> $DIR/self-outlives-lint.rs:148:5
    |
diff --git a/tests/ui/generic-const-items/elided-lifetimes.rs b/tests/ui/generic-const-items/elided-lifetimes.rs
index cca73e2e81e..90899de5af6 100644
--- a/tests/ui/generic-const-items/elided-lifetimes.rs
+++ b/tests/ui/generic-const-items/elided-lifetimes.rs
@@ -9,7 +9,6 @@ where
 
 const I<const S: &str>: &str = "";
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
-//~| ERROR `&str` is forbidden as the type of a const generic parameter
 
 const B<T: Trait<'_>>: () = (); //~ ERROR `'_` cannot be used here
 
diff --git a/tests/ui/generic-const-items/elided-lifetimes.stderr b/tests/ui/generic-const-items/elided-lifetimes.stderr
index 85807a1b631..2b543d02b5d 100644
--- a/tests/ui/generic-const-items/elided-lifetimes.stderr
+++ b/tests/ui/generic-const-items/elided-lifetimes.stderr
@@ -16,27 +16,11 @@ LL | const I<const S: &str>: &str = "";
    |                  ^ explicit lifetime name needed here
 
 error[E0637]: `'_` cannot be used here
-  --> $DIR/elided-lifetimes.rs:14:18
+  --> $DIR/elided-lifetimes.rs:13:18
    |
 LL | const B<T: Trait<'_>>: () = ();
    |                  ^^ `'_` is a reserved lifetime name
 
-error: `&str` is forbidden as the type of a const generic parameter
-  --> $DIR/elided-lifetimes.rs:10:18
-   |
-LL | const I<const S: &str>: &str = "";
-   |                  ^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
-   |
-LL + #![feature(unsized_const_params)]
-   |
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0637`.
diff --git a/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.rs b/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.rs
new file mode 100644
index 00000000000..856f7b622d7
--- /dev/null
+++ b/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.rs
@@ -0,0 +1,7 @@
+//! Regression test for #118179: `adt_const_params` feature shouldn't leak
+//! `{type error}` in error messages.
+
+struct G<T, const N: Vec<T>>(T);
+//~^ ERROR the type of const parameters must not depend on other generic parameters
+
+fn main() {}
diff --git a/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.stderr b/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.stderr
new file mode 100644
index 00000000000..654004571db
--- /dev/null
+++ b/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.stderr
@@ -0,0 +1,11 @@
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/wfcheck_err_leak_issue_118179.rs:4:26
+   |
+LL | struct G<T, const N: Vec<T>>(T);
+   |                          ^ the type must not depend on the parameter `T`
+   |
+   = note: type parameters may not be used in the type of const parameters
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0770`.
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr
index 9831348de75..e2916725fbd 100644
--- a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr
@@ -2,8 +2,9 @@ error: expected a pattern range bound, found an expression
   --> $DIR/range_pat_interactions1.rs:17:16
    |
 LL |             0..5+1 => errors_only.push(x),
-   |                ^^^ arbitrary expressions are not allowed in patterns
+   |                ^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider extracting the expression into a `const`
    |
 LL +         const VAL: /* Type */ = 5+1;
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr
index 1b5e875cccb..f54e07c3a63 100644
--- a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr
@@ -14,8 +14,9 @@ error: expected a pattern range bound, found an expression
   --> $DIR/range_pat_interactions2.rs:10:18
    |
 LL |             0..=(5+1) => errors_only.push(x),
-   |                  ^^^ arbitrary expressions are not allowed in patterns
+   |                  ^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider extracting the expression into a `const`
    |
 LL +         const VAL: /* Type */ = 5+1;
diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr
index 50a9f3ebeab..91550f0e284 100644
--- a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr
+++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr
@@ -19,7 +19,10 @@ error[E0720]: cannot resolve opaque type
   --> $DIR/impl-fn-predefined-lifetimes.rs:4:35
    |
 LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
-   |                                   ^^^^^^^^^^^^^^^ cannot resolve opaque type
+   |                                   ^^^^^^^^^^^^^^^ recursive opaque type
+...
+LL |     |x| x
+   |     ----- returning here with type `{closure@$DIR/impl-fn-predefined-lifetimes.rs:7:5: 7:8}`
 
 error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/tests/ui/impl-trait/issues/issue-78722-2.stderr b/tests/ui/impl-trait/issues/issue-78722-2.stderr
index dc5579c1c82..2cf6b94dd9d 100644
--- a/tests/ui/impl-trait/issues/issue-78722-2.stderr
+++ b/tests/ui/impl-trait/issues/issue-78722-2.stderr
@@ -1,9 +1,3 @@
-error[E0271]: expected `{async block@$DIR/issue-78722-2.rs:13:13: 13:18}` to be a future that resolves to `u8`, but it resolves to `()`
-  --> $DIR/issue-78722-2.rs:11:30
-   |
-LL |         fn concrete_use() -> F {
-   |                              ^ expected `()`, found `u8`
-
 error[E0308]: mismatched types
   --> $DIR/issue-78722-2.rs:16:20
    |
@@ -18,6 +12,12 @@ LL |         let f: F = async { 1 };
    = note: expected opaque type `F`
             found `async` block `{async block@$DIR/issue-78722-2.rs:16:20: 16:25}`
 
+error[E0271]: expected `{async block@$DIR/issue-78722-2.rs:13:13: 13:18}` to be a future that resolves to `u8`, but it resolves to `()`
+  --> $DIR/issue-78722-2.rs:11:30
+   |
+LL |         fn concrete_use() -> F {
+   |                              ^ expected `()`, found `u8`
+
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0271, E0308.
diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
index 3692cc77b0f..6485aa20710 100644
--- a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
+++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
@@ -1,24 +1,3 @@
-error: item does not constrain `a::Foo::{opaque#0}`, but has it in its signature
-  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:12
-   |
-LL |         fn eq(&self, _other: &(Foo, i32)) -> bool {
-   |            ^^
-   |
-   = note: consider moving the opaque type's declaration and defining uses into a separate module
-note: this opaque type is in the signature
-  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16
-   |
-LL |     type Foo = impl PartialEq<(Foo, i32)>;
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: unconstrained opaque type
-  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16
-   |
-LL |     type Foo = impl PartialEq<(Foo, i32)>;
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `Foo` must be used in combination with a concrete type within the same module
-
 error[E0053]: method `eq` has an incompatible type for trait
   --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:30
    |
@@ -35,8 +14,21 @@ help: change the parameter type to match the trait
 LL |         fn eq(&self, _other: &(a::Bar, i32)) -> bool {
    |                              ~~~~~~~~~~~~~~
 
+error: item does not constrain `a::Foo::{opaque#0}`, but has it in its signature
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:12
+   |
+LL |         fn eq(&self, _other: &(Foo, i32)) -> bool {
+   |            ^^
+   |
+   = note: consider moving the opaque type's declaration and defining uses into a separate module
+note: this opaque type is in the signature
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16
+   |
+LL |     type Foo = impl PartialEq<(Foo, i32)>;
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: unconstrained opaque type
-  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:19:16
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16
    |
 LL |     type Foo = impl PartialEq<(Foo, i32)>;
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -64,6 +56,14 @@ help: change the parameter type to match the trait
 LL |         fn eq(&self, _other: &(b::Foo, i32)) -> bool {
    |                              ~~~~~~~~~~~~~~
 
+error: unconstrained opaque type
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:19:16
+   |
+LL |     type Foo = impl PartialEq<(Foo, i32)>;
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Foo` must be used in combination with a concrete type within the same module
+
 error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0053`.
diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr
index 2770a6cc40e..13f50fcea7b 100644
--- a/tests/ui/impl-trait/where-allowed.stderr
+++ b/tests/ui/impl-trait/where-allowed.stderr
@@ -342,6 +342,47 @@ LL |     let _in_return_in_local_variable = || -> impl Fn() { || {} };
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
+error[E0053]: method `in_trait_impl_return` has an incompatible type for trait
+  --> $DIR/where-allowed.rs:128:34
+   |
+LL |     type Out = impl Debug;
+   |                ---------- the expected opaque type
+...
+LL |     fn in_trait_impl_return() -> impl Debug { () }
+   |                                  ^^^^^^^^^^ expected opaque type, found a different opaque type
+   |
+note: type in trait
+  --> $DIR/where-allowed.rs:118:34
+   |
+LL |     fn in_trait_impl_return() -> Self::Out;
+   |                                  ^^^^^^^^^
+   = note: expected signature `fn() -> <() as DummyTrait>::Out`
+              found signature `fn() -> impl Debug`
+   = note: distinct uses of `impl Trait` result in different opaque types
+help: change the output type to match the trait
+   |
+LL |     fn in_trait_impl_return() -> <() as DummyTrait>::Out { () }
+   |                                  ~~~~~~~~~~~~~~~~~~~~~~~
+
+error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/where-allowed.rs:245:36
+   |
+LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {}
+   |                                    ^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
+   = note: `#[deny(invalid_type_param_default)]` on by default
+
+error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/where-allowed.rs:238:7
+   |
+LL | impl <T = impl Debug> T {}
+   |       ^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
+
 error[E0283]: type annotations needed
   --> $DIR/where-allowed.rs:46:57
    |
@@ -362,16 +403,6 @@ LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { pani
            - impl<Args, F, A> Fn<Args> for Box<F, A>
              where Args: Tuple, F: Fn<Args>, A: Allocator, F: ?Sized;
 
-error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
-  --> $DIR/where-allowed.rs:238:7
-   |
-LL | impl <T = impl Debug> T {}
-   |       ^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
-   = note: `#[deny(invalid_type_param_default)]` on by default
-
 error[E0118]: no nominal type found for inherent implementation
   --> $DIR/where-allowed.rs:238:1
    |
@@ -380,28 +411,6 @@ LL | impl <T = impl Debug> T {}
    |
    = note: either implement a trait on it or create a newtype to wrap it instead
 
-error[E0053]: method `in_trait_impl_return` has an incompatible type for trait
-  --> $DIR/where-allowed.rs:128:34
-   |
-LL |     type Out = impl Debug;
-   |                ---------- the expected opaque type
-...
-LL |     fn in_trait_impl_return() -> impl Debug { () }
-   |                                  ^^^^^^^^^^ expected opaque type, found a different opaque type
-   |
-note: type in trait
-  --> $DIR/where-allowed.rs:118:34
-   |
-LL |     fn in_trait_impl_return() -> Self::Out;
-   |                                  ^^^^^^^^^
-   = note: expected signature `fn() -> <() as DummyTrait>::Out`
-              found signature `fn() -> impl Debug`
-   = note: distinct uses of `impl Trait` result in different opaque types
-help: change the output type to match the trait
-   |
-LL |     fn in_trait_impl_return() -> <() as DummyTrait>::Out { () }
-   |                                  ~~~~~~~~~~~~~~~~~~~~~~~
-
 error: unconstrained opaque type
   --> $DIR/where-allowed.rs:121:16
    |
@@ -410,25 +419,16 @@ LL |     type Out = impl Debug;
    |
    = note: `Out` must be used in combination with a concrete type within the same impl
 
-error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
-  --> $DIR/where-allowed.rs:245:36
-   |
-LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {}
-   |                                    ^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
-
 error: aborting due to 49 previous errors
 
 Some errors have detailed explanations: E0053, E0118, E0283, E0562, E0658, E0666.
 For more information about an error, try `rustc --explain E0053`.
 Future incompatibility report: Future breakage diagnostic:
 error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
-  --> $DIR/where-allowed.rs:238:7
+  --> $DIR/where-allowed.rs:245:36
    |
-LL | impl <T = impl Debug> T {}
-   |       ^^^^^^^^^^^^^^
+LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {}
+   |                                    ^^^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
@@ -436,10 +436,10 @@ LL | impl <T = impl Debug> T {}
 
 Future breakage diagnostic:
 error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
-  --> $DIR/where-allowed.rs:245:36
+  --> $DIR/where-allowed.rs:238:7
    |
-LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {}
-   |                                    ^^^^^^^^^^^^^^
+LL | impl <T = impl Debug> T {}
+   |       ^^^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
diff --git a/tests/ui/infinite/auxiliary/alias.rs b/tests/ui/infinite/auxiliary/alias.rs
index 59add7eb18b..5ae124e8aba 100644
--- a/tests/ui/infinite/auxiliary/alias.rs
+++ b/tests/ui/infinite/auxiliary/alias.rs
@@ -1,2 +1,5 @@
 pub struct W<T>(T);
 pub type Wrapper<T> = W<T>;
+pub trait Trait {
+    type T;
+}
diff --git a/tests/ui/infinite/infinite-assoc.rs b/tests/ui/infinite/infinite-assoc.rs
new file mode 100644
index 00000000000..d128a7e0d2d
--- /dev/null
+++ b/tests/ui/infinite/infinite-assoc.rs
@@ -0,0 +1,16 @@
+//@ aux-build: alias.rs
+
+// issue#128327
+
+extern crate alias;
+
+use alias::Trait;
+struct S;
+impl Trait for S {
+    type T = ();
+}
+struct A((A, <S as Trait>::T<NOT_EXIST?>));
+//~^ ERROR: invalid `?` in type
+//~| ERROR: recursive type `A` has infinite size
+
+fn main() {}
diff --git a/tests/ui/infinite/infinite-assoc.stderr b/tests/ui/infinite/infinite-assoc.stderr
new file mode 100644
index 00000000000..e6b91f13241
--- /dev/null
+++ b/tests/ui/infinite/infinite-assoc.stderr
@@ -0,0 +1,25 @@
+error: invalid `?` in type
+  --> $DIR/infinite-assoc.rs:12:39
+   |
+LL | struct A((A, <S as Trait>::T<NOT_EXIST?>));
+   |                                       ^ `?` is only allowed on expressions, not types
+   |
+help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
+   |
+LL | struct A((A, <S as Trait>::T<Option<NOT_EXIST>>));
+   |                              +++++++         ~
+
+error[E0072]: recursive type `A` has infinite size
+  --> $DIR/infinite-assoc.rs:12:1
+   |
+LL | struct A((A, <S as Trait>::T<NOT_EXIST?>));
+   | ^^^^^^^^  - recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
+   |
+LL | struct A((Box<A>, <S as Trait>::T<NOT_EXIST?>));
+   |           ++++ +
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0072`.
diff --git a/tests/ui/issues/issue-12041.stderr b/tests/ui/issues/issue-12041.stderr
index 51061c0262e..f2c10b83383 100644
--- a/tests/ui/issues/issue-12041.stderr
+++ b/tests/ui/issues/issue-12041.stderr
@@ -4,7 +4,7 @@ error[E0382]: use of moved value: `tx`
 LL |             let tx = tx;
    |                      ^^ value moved here, in previous iteration of loop
    |
-   = note: move occurs because `tx` has type `Sender<i32>`, which does not implement the `Copy` trait
+   = note: move occurs because `tx` has type `std::sync::mpsc::Sender<i32>`, which does not implement the `Copy` trait
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-31511.rs b/tests/ui/issues/issue-31511.rs
index 53fecb01663..6c8df1157c6 100644
--- a/tests/ui/issues/issue-31511.rs
+++ b/tests/ui/issues/issue-31511.rs
@@ -1,6 +1,6 @@
 fn cast_thin_to_fat(x: *const ()) {
     x as *const [u8];
-    //~^ ERROR: cannot cast thin pointer `*const ()` to fat pointer `*const [u8]`
+    //~^ ERROR: cannot cast thin pointer `*const ()` to wide pointer `*const [u8]`
 }
 
 fn main() {}
diff --git a/tests/ui/issues/issue-31511.stderr b/tests/ui/issues/issue-31511.stderr
index 177b78754cc..2048bd7ec16 100644
--- a/tests/ui/issues/issue-31511.stderr
+++ b/tests/ui/issues/issue-31511.stderr
@@ -1,4 +1,4 @@
-error[E0607]: cannot cast thin pointer `*const ()` to fat pointer `*const [u8]`
+error[E0607]: cannot cast thin pointer `*const ()` to wide pointer `*const [u8]`
   --> $DIR/issue-31511.rs:2:5
    |
 LL |     x as *const [u8];
diff --git a/tests/ui/lifetimes/unusual-rib-combinations.rs b/tests/ui/lifetimes/unusual-rib-combinations.rs
index 0708a00d371..0e92b41ae1e 100644
--- a/tests/ui/lifetimes/unusual-rib-combinations.rs
+++ b/tests/ui/lifetimes/unusual-rib-combinations.rs
@@ -20,11 +20,9 @@ fn c<T = u8()>() {}
 // Elided lifetime in path in ConstGeneric
 fn d<const C: S>() {}
 //~^ ERROR missing lifetime specifier
-//~| ERROR `S<'_>` is forbidden as the type of a const generic parameter
 
 trait Foo<'a> {}
 struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>;
 //~^ ERROR the type of const parameters must not depend on other generic parameters
-//~| ERROR `&dyn for<'a> Foo<'a>` is forbidden as the type of a const generic parameter
 
 fn main() {}
diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr
index ebf6f6ca403..b7effdc8d61 100644
--- a/tests/ui/lifetimes/unusual-rib-combinations.stderr
+++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr
@@ -5,7 +5,7 @@ LL | fn d<const C: S>() {}
    |               ^ expected named lifetime parameter
 
 error[E0770]: the type of const parameters must not depend on other generic parameters
-  --> $DIR/unusual-rib-combinations.rs:26:22
+  --> $DIR/unusual-rib-combinations.rs:25:22
    |
 LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>;
    |                      ^^ the type must not depend on the parameter `'a`
@@ -40,35 +40,7 @@ error[E0308]: mismatched types
 LL | fn a() -> [u8; foo()] {
    |                ^^^^^ expected `usize`, found `()`
 
-error: `S<'_>` is forbidden as the type of a const generic parameter
-  --> $DIR/unusual-rib-combinations.rs:21:15
-   |
-LL | fn d<const C: S>() {}
-   |               ^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-
-error: `&dyn for<'a> Foo<'a>` is forbidden as the type of a const generic parameter
-  --> $DIR/unusual-rib-combinations.rs:26:21
-   |
-LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>;
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   |
-LL + #![feature(adt_const_params)]
-   |
-help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait
-   |
-LL + #![feature(unsized_const_params)]
-   |
-
-error: aborting due to 8 previous errors
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0106, E0214, E0308, E0770.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/tests/ui/lint/invalid-nan-comparison.stderr b/tests/ui/lint/invalid-nan-comparison.stderr
index f2d55c107ba..054c06d38b3 100644
--- a/tests/ui/lint/invalid-nan-comparison.stderr
+++ b/tests/ui/lint/invalid-nan-comparison.stderr
@@ -5,6 +5,11 @@ LL | const TEST: bool = 5f32 == f32::NAN;
    |                    ^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(invalid_nan_comparisons)]` on by default
+help: use `f32::is_nan()` or `f64::is_nan()` instead
+   |
+LL - const TEST: bool = 5f32 == f32::NAN;
+LL + const TEST: bool = 5f32.is_nan();
+   |
 
 warning: incorrect NaN comparison, NaN cannot be directly compared to itself
   --> $DIR/invalid-nan-comparison.rs:14:5
diff --git a/tests/ui/lint/unconditional_panic_promoted.rs b/tests/ui/lint/unconditional_panic_promoted.rs
new file mode 100644
index 00000000000..37bcf046513
--- /dev/null
+++ b/tests/ui/lint/unconditional_panic_promoted.rs
@@ -0,0 +1,8 @@
+//@ build-fail
+
+fn main() {
+    // MIR encodes this as a reborrow from a promoted constant.
+    // But the array lenth can still be gotten from the type.
+    let slice = &[0, 1];
+    let _ = slice[2]; //~ ERROR: this operation will panic at runtime [unconditional_panic]
+}
diff --git a/tests/ui/lint/unconditional_panic_promoted.stderr b/tests/ui/lint/unconditional_panic_promoted.stderr
new file mode 100644
index 00000000000..647a84a55fd
--- /dev/null
+++ b/tests/ui/lint/unconditional_panic_promoted.stderr
@@ -0,0 +1,10 @@
+error: this operation will panic at runtime
+  --> $DIR/unconditional_panic_promoted.rs:7:13
+   |
+LL |     let _ = slice[2];
+   |             ^^^^^^^^ index out of bounds: the length is 2 but the index is 2
+   |
+   = note: `#[deny(unconditional_panic)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lint/unused/unused-macro-with-bad-frag-spec.stderr b/tests/ui/lint/unused/unused-macro-with-bad-frag-spec.stderr
index f027e169b42..003c6975c95 100644
--- a/tests/ui/lint/unused/unused-macro-with-bad-frag-spec.stderr
+++ b/tests/ui/lint/unused/unused-macro-with-bad-frag-spec.stderr
@@ -4,7 +4,7 @@ error: invalid fragment specifier `t_ty`
 LL |     ($wrong:t_ty) => ()
    |      ^^^^^^^^^^^
    |
-   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lint/use_suggestion_json.stderr b/tests/ui/lint/use_suggestion_json.stderr
index 4683e5dd8f3..0d4304e2e2e 100644
--- a/tests/ui/lint/use_suggestion_json.stderr
+++ b/tests/ui/lint/use_suggestion_json.stderr
@@ -369,6 +369,29 @@ mod foo {
             }
           ],
           "label": null,
+          "suggested_replacement": "use std::sync::mpmc::Iter;
+
+",
+          "suggestion_applicability": "MaybeIncorrect",
+          "expansion": null
+        },
+        {
+          "file_name": "$DIR/use_suggestion_json.rs",
+          "byte_start": 541,
+          "byte_end": 541,
+          "line_start": 11,
+          "line_end": 11,
+          "column_start": 1,
+          "column_end": 1,
+          "is_primary": true,
+          "text": [
+            {
+              "text": "fn main() {",
+              "highlight_start": 1,
+              "highlight_end": 1
+            }
+          ],
+          "label": null,
           "suggested_replacement": "use std::sync::mpsc::Iter;
 
 ",
@@ -396,7 +419,7 @@ mod foo {
 \u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
 \u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[38;5;10m+ use std::collections::hash_map::Iter;\u001b[0m
 \u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m     and 8 other candidates\u001b[0m
+\u001b[0m     and 9 other candidates\u001b[0m
 
 "
 }
diff --git a/tests/ui/macros/cfg.rs b/tests/ui/macros/cfg.rs
index 2aac50a9d01..50998572274 100644
--- a/tests/ui/macros/cfg.rs
+++ b/tests/ui/macros/cfg.rs
@@ -1,6 +1,6 @@
 fn main() {
     cfg!(); //~ ERROR macro requires a cfg-pattern
-    cfg!(123); //~ ERROR expected identifier
+    cfg!(123); //~ ERROR literal in `cfg` predicate value must be a boolean
     cfg!(foo = 123); //~ ERROR literal in `cfg` predicate value must be a string
     cfg!(foo, bar); //~ ERROR expected 1 cfg-pattern
 }
diff --git a/tests/ui/macros/cfg.stderr b/tests/ui/macros/cfg.stderr
index 2633d5f720d..53326914865 100644
--- a/tests/ui/macros/cfg.stderr
+++ b/tests/ui/macros/cfg.stderr
@@ -6,11 +6,11 @@ LL |     cfg!();
    |
    = note: this error originates in the macro `cfg` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: expected identifier, found `123`
+error[E0565]: literal in `cfg` predicate value must be a boolean
   --> $DIR/cfg.rs:3:10
    |
 LL |     cfg!(123);
-   |          ^^^ expected identifier
+   |          ^^^
 
 error[E0565]: literal in `cfg` predicate value must be a string
   --> $DIR/cfg.rs:4:16
diff --git a/tests/ui/macros/expr_2021.rs b/tests/ui/macros/expr_2021.rs
new file mode 100644
index 00000000000..8a274e77533
--- /dev/null
+++ b/tests/ui/macros/expr_2021.rs
@@ -0,0 +1,14 @@
+//@ check-pass
+//@ edition: 2015
+
+// Ensures expr_2021 fragment specifier is accepted in old editions
+
+macro_rules! my_macro {
+    ($x:expr_2021) => {
+        println!("Hello, {}!", $x);
+    };
+}
+
+fn main() {
+    my_macro!("world");
+}
diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.fixed b/tests/ui/macros/expr_2021_cargo_fix_edition.fixed
index 1becd8a92d6..061a4b98033 100644
--- a/tests/ui/macros/expr_2021_cargo_fix_edition.fixed
+++ b/tests/ui/macros/expr_2021_cargo_fix_edition.fixed
@@ -1,8 +1,6 @@
 //@ run-rustfix
 //@ check-pass
 //@ compile-flags: --edition=2021
-#![allow(incomplete_features)]
-#![feature(expr_fragment_specifier_2024)]
 #![warn(edition_2024_expr_fragment_specifier)]
 
 macro_rules! m {
diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.rs b/tests/ui/macros/expr_2021_cargo_fix_edition.rs
index ec0b86d2c23..cd9cd965fad 100644
--- a/tests/ui/macros/expr_2021_cargo_fix_edition.rs
+++ b/tests/ui/macros/expr_2021_cargo_fix_edition.rs
@@ -1,8 +1,6 @@
 //@ run-rustfix
 //@ check-pass
 //@ compile-flags: --edition=2021
-#![allow(incomplete_features)]
-#![feature(expr_fragment_specifier_2024)]
 #![warn(edition_2024_expr_fragment_specifier)]
 
 macro_rules! m {
diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.stderr b/tests/ui/macros/expr_2021_cargo_fix_edition.stderr
index e8a44fed322..fe1fd4a26a0 100644
--- a/tests/ui/macros/expr_2021_cargo_fix_edition.stderr
+++ b/tests/ui/macros/expr_2021_cargo_fix_edition.stderr
@@ -1,5 +1,5 @@
 warning: the `expr` fragment specifier will accept more expressions in the 2024 edition
-  --> $DIR/expr_2021_cargo_fix_edition.rs:9:9
+  --> $DIR/expr_2021_cargo_fix_edition.rs:7:9
    |
 LL |     ($e:expr) => {
    |         ^^^^
@@ -7,7 +7,7 @@ LL |     ($e:expr) => {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see Migration Guide <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/macro-fragment-specifiers.html>
 note: the lint level is defined here
-  --> $DIR/expr_2021_cargo_fix_edition.rs:6:9
+  --> $DIR/expr_2021_cargo_fix_edition.rs:4:9
    |
 LL | #![warn(edition_2024_expr_fragment_specifier)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |     ($e:expr_2021) => {
    |         ~~~~~~~~~
 
 warning: the `expr` fragment specifier will accept more expressions in the 2024 edition
-  --> $DIR/expr_2021_cargo_fix_edition.rs:13:11
+  --> $DIR/expr_2021_cargo_fix_edition.rs:11:11
    |
 LL |     ($($i:expr)*) => { };
    |           ^^^^
diff --git a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
index b55ae62030c..22d662aaaf2 100644
--- a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
+++ b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
@@ -1,5 +1,5 @@
 error: no rules expected the token `const`
-  --> $DIR/expr_2021_inline_const.rs:26:12
+  --> $DIR/expr_2021_inline_const.rs:23:12
    |
 LL | macro_rules! m2021 {
    | ------------------ when calling this macro
@@ -8,13 +8,13 @@ LL |     m2021!(const { 1 });
    |            ^^^^^ no rules expected this token in macro call
    |
 note: while trying to match meta-variable `$e:expr_2021`
-  --> $DIR/expr_2021_inline_const.rs:10:6
+  --> $DIR/expr_2021_inline_const.rs:7:6
    |
 LL |     ($e:expr_2021) => {
    |      ^^^^^^^^^^^^
 
 error: no rules expected the token `const`
-  --> $DIR/expr_2021_inline_const.rs:27:12
+  --> $DIR/expr_2021_inline_const.rs:24:12
    |
 LL | macro_rules! m2024 {
    | ------------------ when calling this macro
@@ -23,7 +23,7 @@ LL |     m2024!(const { 1 });
    |            ^^^^^ no rules expected this token in macro call
    |
 note: while trying to match meta-variable `$e:expr`
-  --> $DIR/expr_2021_inline_const.rs:16:6
+  --> $DIR/expr_2021_inline_const.rs:13:6
    |
 LL |     ($e:expr) => {
    |      ^^^^^^^
diff --git a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
index 285db53d6c8..2555e4f757a 100644
--- a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
+++ b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
@@ -1,5 +1,5 @@
 error: no rules expected the token `const`
-  --> $DIR/expr_2021_inline_const.rs:26:12
+  --> $DIR/expr_2021_inline_const.rs:23:12
    |
 LL | macro_rules! m2021 {
    | ------------------ when calling this macro
@@ -8,7 +8,7 @@ LL |     m2021!(const { 1 });
    |            ^^^^^ no rules expected this token in macro call
    |
 note: while trying to match meta-variable `$e:expr_2021`
-  --> $DIR/expr_2021_inline_const.rs:10:6
+  --> $DIR/expr_2021_inline_const.rs:7:6
    |
 LL |     ($e:expr_2021) => {
    |      ^^^^^^^^^^^^
diff --git a/tests/ui/macros/expr_2021_inline_const.rs b/tests/ui/macros/expr_2021_inline_const.rs
index 06b74a466d6..39a542fe4d9 100644
--- a/tests/ui/macros/expr_2021_inline_const.rs
+++ b/tests/ui/macros/expr_2021_inline_const.rs
@@ -3,9 +3,6 @@
 //@[edi2021]compile-flags: --edition=2021
 
 // This test ensures that the inline const match only on edition 2024
-#![feature(expr_fragment_specifier_2024)]
-#![allow(incomplete_features)]
-
 macro_rules! m2021 {
     ($e:expr_2021) => {
         $e
diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr
index 335b3f61343..34df20a69ef 100644
--- a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr
+++ b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr
@@ -1,5 +1,5 @@
 error: no rules expected the token `_`
-  --> $DIR/expr_2024_underscore_expr.rs:22:12
+  --> $DIR/expr_2024_underscore_expr.rs:19:12
    |
 LL | macro_rules! m2021 {
    | ------------------ when calling this macro
@@ -8,13 +8,13 @@ LL |     m2021!(_);
    |            ^ no rules expected this token in macro call
    |
 note: while trying to match meta-variable `$e:expr_2021`
-  --> $DIR/expr_2024_underscore_expr.rs:10:6
+  --> $DIR/expr_2024_underscore_expr.rs:7:6
    |
 LL |     ($e:expr_2021) => {
    |      ^^^^^^^^^^^^
 
 error: no rules expected the token `_`
-  --> $DIR/expr_2024_underscore_expr.rs:23:12
+  --> $DIR/expr_2024_underscore_expr.rs:20:12
    |
 LL | macro_rules! m2024 {
    | ------------------ when calling this macro
@@ -23,7 +23,7 @@ LL |     m2024!(_);
    |            ^ no rules expected this token in macro call
    |
 note: while trying to match meta-variable `$e:expr`
-  --> $DIR/expr_2024_underscore_expr.rs:16:6
+  --> $DIR/expr_2024_underscore_expr.rs:13:6
    |
 LL |     ($e:expr) => {
    |      ^^^^^^^
diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr
index 9e49f66a89a..372c5d8637c 100644
--- a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr
+++ b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr
@@ -1,5 +1,5 @@
 error: no rules expected the token `_`
-  --> $DIR/expr_2024_underscore_expr.rs:22:12
+  --> $DIR/expr_2024_underscore_expr.rs:19:12
    |
 LL | macro_rules! m2021 {
    | ------------------ when calling this macro
@@ -8,7 +8,7 @@ LL |     m2021!(_);
    |            ^ no rules expected this token in macro call
    |
 note: while trying to match meta-variable `$e:expr_2021`
-  --> $DIR/expr_2024_underscore_expr.rs:10:6
+  --> $DIR/expr_2024_underscore_expr.rs:7:6
    |
 LL |     ($e:expr_2021) => {
    |      ^^^^^^^^^^^^
diff --git a/tests/ui/macros/expr_2024_underscore_expr.rs b/tests/ui/macros/expr_2024_underscore_expr.rs
index b2129bf154f..86e31374506 100644
--- a/tests/ui/macros/expr_2024_underscore_expr.rs
+++ b/tests/ui/macros/expr_2024_underscore_expr.rs
@@ -3,9 +3,6 @@
 //@[edi2021]compile-flags: --edition=2021
 // This test ensures that the `_` tok is considered an
 // expression on edition 2024.
-#![feature(expr_fragment_specifier_2024)]
-#![allow(incomplete_features)]
-
 macro_rules! m2021 {
     ($e:expr_2021) => {
         $e = 1;
diff --git a/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs b/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs
deleted file mode 100644
index 5a737b29821..00000000000
--- a/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@  compile-flags: --edition=2024 -Z unstable-options
-
-macro_rules! m {
-    ($e:expr_2021) => { //~ ERROR: fragment specifier `expr_2021` is unstable
-        $e
-    };
-}
-
-fn main() {
-    m!(());
-}
diff --git a/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr b/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr
deleted file mode 100644
index 273a93877ce..00000000000
--- a/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: fragment specifier `expr_2021` is unstable
-  --> $DIR/feature-gate-expr_fragment_specifier_2024.rs:4:6
-   |
-LL |     ($e:expr_2021) => {
-   |      ^^^^^^^^^^^^
-   |
-   = note: see issue #123742 <https://github.com/rust-lang/rust/issues/123742> for more information
-   = help: add `#![feature(expr_fragment_specifier_2024)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/macros/invalid-fragment-specifier.stderr b/tests/ui/macros/invalid-fragment-specifier.stderr
index 7516dbc3a08..a51ea619b36 100644
--- a/tests/ui/macros/invalid-fragment-specifier.stderr
+++ b/tests/ui/macros/invalid-fragment-specifier.stderr
@@ -4,7 +4,7 @@ error: invalid fragment specifier `id`
 LL |     ($wrong:id) => {};
    |      ^^^^^^^^^
    |
-   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 
 error: invalid fragment specifier `r#if`
   --> $DIR/invalid-fragment-specifier.rs:7:6
@@ -12,7 +12,7 @@ error: invalid fragment specifier `r#if`
 LL |     ($wrong:r#if) => {};
    |      ^^^^^^^^^^^
    |
-   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/macros/issue-21356.stderr b/tests/ui/macros/issue-21356.stderr
index dd09da6df4f..5ff92642514 100644
--- a/tests/ui/macros/issue-21356.stderr
+++ b/tests/ui/macros/issue-21356.stderr
@@ -4,7 +4,7 @@ error: invalid fragment specifier `t_ty`
 LL | macro_rules! test { ($wrong:t_ty ..) => () }
    |                      ^^^^^^^^^^^
    |
-   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/macros/macro-missing-fragment.e2024.stderr b/tests/ui/macros/macro-missing-fragment.e2024.stderr
index 3afa069c170..0dc48e0c7b2 100644
--- a/tests/ui/macros/macro-missing-fragment.e2024.stderr
+++ b/tests/ui/macros/macro-missing-fragment.e2024.stderr
@@ -5,7 +5,7 @@ LL |     ( $( any_token $field_rust_type )* ) => {};
    |                    ^^^^^^^^^^^^^^^^
    |
    = note: fragment specifiers must be specified in the 2024 edition
-   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 help: try adding a specifier here
    |
 LL |     ( $( any_token $field_rust_type:spec )* ) => {};
@@ -18,7 +18,7 @@ LL |     ( $name ) => {};
    |       ^^^^^
    |
    = note: fragment specifiers must be specified in the 2024 edition
-   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 help: try adding a specifier here
    |
 LL |     ( $name:spec ) => {};
@@ -31,7 +31,7 @@ LL |     ( $name ) => {};
    |       ^^^^^
    |
    = note: fragment specifiers must be specified in the 2024 edition
-   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 help: try adding a specifier here
    |
 LL |     ( $name:spec ) => {};
diff --git a/tests/ui/macros/metavar_cross_edition_recursive_macros.rs b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs
index 3eec1208b89..9a5b92f5032 100644
--- a/tests/ui/macros/metavar_cross_edition_recursive_macros.rs
+++ b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs
@@ -6,7 +6,6 @@
 // This test captures the behavior of macro-generating-macros with fragment
 // specifiers across edition boundaries.
 
-#![feature(expr_fragment_specifier_2024)]
 #![feature(macro_metavar_expr)]
 #![allow(incomplete_features)]
 
diff --git a/tests/ui/methods/dont-suggest-import-on-deref-err.rs b/tests/ui/methods/dont-suggest-import-on-deref-err.rs
new file mode 100644
index 00000000000..c24ab791982
--- /dev/null
+++ b/tests/ui/methods/dont-suggest-import-on-deref-err.rs
@@ -0,0 +1,13 @@
+use std::clone::Clone;
+use std::ops::Deref;
+
+#[derive(Clone)]
+pub struct Foo {}
+
+impl Deref for Foo {}
+//~^ ERROR not all trait items implemented
+
+pub fn main() {
+    let f = Foo {};
+    let _ = f.clone();
+}
diff --git a/tests/ui/methods/dont-suggest-import-on-deref-err.stderr b/tests/ui/methods/dont-suggest-import-on-deref-err.stderr
new file mode 100644
index 00000000000..20a63ff375d
--- /dev/null
+++ b/tests/ui/methods/dont-suggest-import-on-deref-err.stderr
@@ -0,0 +1,12 @@
+error[E0046]: not all trait items implemented, missing: `Target`, `deref`
+  --> $DIR/dont-suggest-import-on-deref-err.rs:7:1
+   |
+LL | impl Deref for Foo {}
+   | ^^^^^^^^^^^^^^^^^^ missing `Target`, `deref` in implementation
+   |
+   = help: implement the missing item: `type Target = /* Type */;`
+   = help: implement the missing item: `fn deref(&self) -> &<Self as Deref>::Target { todo!() }`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0046`.
diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr
index 3d12ba9899b..2e5cbb90036 100644
--- a/tests/ui/mismatched_types/cast-rfc0401.stderr
+++ b/tests/ui/mismatched_types/cast-rfc0401.stderr
@@ -158,7 +158,7 @@ LL |     let _ = 42usize as *const [u8];
    |             |
    |             consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
 
-error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]`
+error[E0607]: cannot cast thin pointer `*const u8` to wide pointer `*const [u8]`
   --> $DIR/cast-rfc0401.rs:52:13
    |
 LL |     let _ = v as *const [u8];
diff --git a/tests/ui/never_type/diverging-place-match.rs b/tests/ui/never_type/diverging-place-match.rs
new file mode 100644
index 00000000000..b9bc29a218c
--- /dev/null
+++ b/tests/ui/never_type/diverging-place-match.rs
@@ -0,0 +1,74 @@
+#![feature(never_type)]
+
+fn not_a_read() -> ! {
+    unsafe {
+    //~^ ERROR mismatched types
+        let x: *const ! = 0 as _;
+        let _: ! = *x;
+        // Since `*x` "diverges" in HIR, but doesn't count as a read in MIR, this
+        // is unsound since we act as if it diverges but it doesn't.
+    }
+}
+
+fn not_a_read_implicit() -> ! {
+    unsafe {
+    //~^ ERROR mismatched types
+        let x: *const ! = 0 as _;
+        let _ = *x;
+    }
+}
+
+fn not_a_read_guide_coercion() -> ! {
+    unsafe {
+        //~^ ERROR mismatched types
+        let x: *const ! = 0 as _;
+        let _: () = *x;
+        //~^ ERROR mismatched types
+    }
+}
+
+fn empty_match() -> ! {
+    unsafe {
+    //~^ ERROR mismatched types
+        let x: *const ! = 0 as _;
+        match *x { _ => {} };
+    }
+}
+
+fn field_projection() -> ! {
+    unsafe {
+    //~^ ERROR mismatched types
+        let x: *const (!, ()) = 0 as _;
+        let _ = (*x).0;
+        // ^ I think this is still UB, but because of the inbounds projection.
+    }
+}
+
+fn covered_arm() -> ! {
+    unsafe {
+    //~^ ERROR mismatched types
+        let x: *const ! = 0 as _;
+        let (_ | 1i32) = *x;
+        //~^ ERROR mismatched types
+    }
+}
+
+// FIXME: This *could* be considered a read of `!`, but we're not that sophisticated..
+fn uncovered_arm() -> ! {
+    unsafe {
+    //~^ ERROR mismatched types
+        let x: *const ! = 0 as _;
+        let (1i32 | _) = *x;
+        //~^ ERROR mismatched types
+    }
+}
+
+fn coerce_ref_binding() -> ! {
+    unsafe {
+        let x: *const ! = 0 as _;
+        let ref _x: () = *x;
+        //~^ ERROR mismatched types
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/never_type/diverging-place-match.stderr b/tests/ui/never_type/diverging-place-match.stderr
new file mode 100644
index 00000000000..74e1bfa0a6b
--- /dev/null
+++ b/tests/ui/never_type/diverging-place-match.stderr
@@ -0,0 +1,142 @@
+error[E0308]: mismatched types
+  --> $DIR/diverging-place-match.rs:4:5
+   |
+LL | /     unsafe {
+LL | |
+LL | |         let x: *const ! = 0 as _;
+LL | |         let _: ! = *x;
+LL | |         // Since `*x` "diverges" in HIR, but doesn't count as a read in MIR, this
+LL | |         // is unsound since we act as if it diverges but it doesn't.
+LL | |     }
+   | |_____^ expected `!`, found `()`
+   |
+   = note:   expected type `!`
+           found unit type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/diverging-place-match.rs:14:5
+   |
+LL | /     unsafe {
+LL | |
+LL | |         let x: *const ! = 0 as _;
+LL | |         let _ = *x;
+LL | |     }
+   | |_____^ expected `!`, found `()`
+   |
+   = note:   expected type `!`
+           found unit type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/diverging-place-match.rs:25:21
+   |
+LL |         let _: () = *x;
+   |                --   ^^ expected `()`, found `!`
+   |                |
+   |                expected due to this
+   |
+   = note: expected unit type `()`
+                   found type `!`
+
+error[E0308]: mismatched types
+  --> $DIR/diverging-place-match.rs:22:5
+   |
+LL | /     unsafe {
+LL | |
+LL | |         let x: *const ! = 0 as _;
+LL | |         let _: () = *x;
+LL | |
+LL | |     }
+   | |_____^ expected `!`, found `()`
+   |
+   = note:   expected type `!`
+           found unit type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/diverging-place-match.rs:31:5
+   |
+LL | /     unsafe {
+LL | |
+LL | |         let x: *const ! = 0 as _;
+LL | |         match *x { _ => {} };
+LL | |     }
+   | |_____^ expected `!`, found `()`
+   |
+   = note:   expected type `!`
+           found unit type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/diverging-place-match.rs:39:5
+   |
+LL | /     unsafe {
+LL | |
+LL | |         let x: *const (!, ()) = 0 as _;
+LL | |         let _ = (*x).0;
+LL | |         // ^ I think this is still UB, but because of the inbounds projection.
+LL | |     }
+   | |_____^ expected `!`, found `()`
+   |
+   = note:   expected type `!`
+           found unit type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/diverging-place-match.rs:51:18
+   |
+LL |         let (_ | 1i32) = *x;
+   |                  ^^^^    -- this expression has type `!`
+   |                  |
+   |                  expected `!`, found `i32`
+   |
+   = note: expected type `!`
+              found type `i32`
+
+error[E0308]: mismatched types
+  --> $DIR/diverging-place-match.rs:48:5
+   |
+LL | /     unsafe {
+LL | |
+LL | |         let x: *const ! = 0 as _;
+LL | |         let (_ | 1i32) = *x;
+LL | |
+LL | |     }
+   | |_____^ expected `!`, found `()`
+   |
+   = note:   expected type `!`
+           found unit type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/diverging-place-match.rs:61:14
+   |
+LL |         let (1i32 | _) = *x;
+   |              ^^^^        -- this expression has type `!`
+   |              |
+   |              expected `!`, found `i32`
+   |
+   = note: expected type `!`
+              found type `i32`
+
+error[E0308]: mismatched types
+  --> $DIR/diverging-place-match.rs:58:5
+   |
+LL | /     unsafe {
+LL | |
+LL | |         let x: *const ! = 0 as _;
+LL | |         let (1i32 | _) = *x;
+LL | |
+LL | |     }
+   | |_____^ expected `!`, found `()`
+   |
+   = note:   expected type `!`
+           found unit type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/diverging-place-match.rs:69:26
+   |
+LL |         let ref _x: () = *x;
+   |                          ^^ expected `()`, found `!`
+   |
+   = note: expected unit type `()`
+                   found type `!`
+
+error: aborting due to 11 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/panic-handler/panic-handler-with-track-caller.stderr b/tests/ui/panic-handler/panic-handler-with-track-caller.stderr
index 9ed387fc8d1..605567acdb5 100644
--- a/tests/ui/panic-handler/panic-handler-with-track-caller.stderr
+++ b/tests/ui/panic-handler/panic-handler-with-track-caller.stderr
@@ -5,7 +5,7 @@ LL | #[track_caller]
    | ^^^^^^^^^^^^^^^
 LL |
 LL | fn panic(info: &PanicInfo) -> ! {
-   | ------------------------------- `#[panic_handler]` function is not allowed to have `#[target_feature]`
+   | ------------------------------- `#[panic_handler]` function is not allowed to have `#[track_caller]`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/bad-name.stderr b/tests/ui/parser/bad-name.stderr
index 3fc416dd531..5ca248380ee 100644
--- a/tests/ui/parser/bad-name.stderr
+++ b/tests/ui/parser/bad-name.stderr
@@ -8,7 +8,9 @@ error: expected a pattern, found an expression
   --> $DIR/bad-name.rs:2:7
    |
 LL |   let x.y::<isize>.z foo;
-   |       ^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |       ^^^^^^^^^^^^^^ not a pattern
+   |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 
 error: expected one of `(`, `.`, `::`, `:`, `;`, `=`, `?`, `|`, or an operator, found `foo`
   --> $DIR/bad-name.rs:2:22
diff --git a/tests/ui/parser/issues/issue-24197.stderr b/tests/ui/parser/issues/issue-24197.stderr
index 7ebbf4ac370..c92e165b23b 100644
--- a/tests/ui/parser/issues/issue-24197.stderr
+++ b/tests/ui/parser/issues/issue-24197.stderr
@@ -2,7 +2,9 @@ error: expected a pattern, found an expression
   --> $DIR/issue-24197.rs:2:9
    |
 LL |     let buf[0] = 0;
-   |         ^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^ not a pattern
+   |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-24375.stderr b/tests/ui/parser/issues/issue-24375.stderr
index a25c277d78a..fef3fcde7b7 100644
--- a/tests/ui/parser/issues/issue-24375.stderr
+++ b/tests/ui/parser/issues/issue-24375.stderr
@@ -2,8 +2,9 @@ error: expected a pattern, found an expression
   --> $DIR/issue-24375.rs:6:9
    |
 LL |         tmp[0] => {}
-   |         ^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == tmp[0] => {}
diff --git a/tests/ui/parser/pat-lt-bracket-5.stderr b/tests/ui/parser/pat-lt-bracket-5.stderr
index 18cf2df0282..a2a972652d1 100644
--- a/tests/ui/parser/pat-lt-bracket-5.stderr
+++ b/tests/ui/parser/pat-lt-bracket-5.stderr
@@ -2,7 +2,9 @@ error: expected a pattern, found an expression
   --> $DIR/pat-lt-bracket-5.rs:2:9
    |
 LL |     let v[0] = v[1];
-   |         ^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^ not a pattern
+   |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 
 error[E0425]: cannot find value `v` in this scope
   --> $DIR/pat-lt-bracket-5.rs:2:16
diff --git a/tests/ui/parser/pat-lt-bracket-6.stderr b/tests/ui/parser/pat-lt-bracket-6.stderr
index 892883c4aed..14ae602fedf 100644
--- a/tests/ui/parser/pat-lt-bracket-6.stderr
+++ b/tests/ui/parser/pat-lt-bracket-6.stderr
@@ -2,7 +2,9 @@ error: expected a pattern, found an expression
   --> $DIR/pat-lt-bracket-6.rs:5:14
    |
 LL |     let Test(&desc[..]) = x;
-   |              ^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |              ^^^^^^^^^ not a pattern
+   |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 
 error[E0308]: mismatched types
   --> $DIR/pat-lt-bracket-6.rs:10:30
diff --git a/tests/ui/parser/pat-ranges-3.stderr b/tests/ui/parser/pat-ranges-3.stderr
index 5e1f35d1b6f..ef080368e19 100644
--- a/tests/ui/parser/pat-ranges-3.stderr
+++ b/tests/ui/parser/pat-ranges-3.stderr
@@ -2,13 +2,17 @@ error: expected a pattern range bound, found an expression
   --> $DIR/pat-ranges-3.rs:4:16
    |
 LL |     let 10 ..= 10 + 3 = 12;
-   |                ^^^^^^ arbitrary expressions are not allowed in patterns
+   |                ^^^^^^ not a pattern
+   |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 
 error: expected a pattern range bound, found an expression
   --> $DIR/pat-ranges-3.rs:7:9
    |
 LL |     let 10 - 3 ..= 10 = 8;
-   |         ^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^ not a pattern
+   |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/recover/recover-pat-exprs.stderr b/tests/ui/parser/recover/recover-pat-exprs.stderr
index 63956f35c07..6cb3753de8d 100644
--- a/tests/ui/parser/recover/recover-pat-exprs.stderr
+++ b/tests/ui/parser/recover/recover-pat-exprs.stderr
@@ -2,8 +2,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:5:9
    |
 LL |         x.y => (),
-   |         ^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == x.y => (),
@@ -24,8 +25,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:6:9
    |
 LL |         x.0 => (),
-   |         ^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == x.0 => (),
@@ -47,8 +49,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:7:9
    |
 LL |         x._0 => (),
-   |         ^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == x._0 => (),
@@ -71,8 +74,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:8:9
    |
 LL |         x.0.1 => (),
-   |         ^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == x.0.1 => (),
@@ -95,8 +99,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:9:9
    |
 LL |         x.4.y.17.__z => (),
-   |         ^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == x.4.y.17.__z => (),
@@ -149,8 +154,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:23:9
    |
 LL |         x[0] => (),
-   |         ^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == x[0] => (),
@@ -170,8 +176,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:24:9
    |
 LL |         x[..] => (),
-   |         ^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == x[..] => (),
@@ -219,8 +226,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:37:9
    |
 LL |         x.f() => (),
-   |         ^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == x.f() => (),
@@ -240,8 +248,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:38:9
    |
 LL |         x._f() => (),
-   |         ^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == x._f() => (),
@@ -262,8 +271,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:39:9
    |
 LL |         x? => (),
-   |         ^^ arbitrary expressions are not allowed in patterns
+   |         ^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == x? => (),
@@ -285,8 +295,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:40:9
    |
 LL |         ().f() => (),
-   |         ^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == ().f() => (),
@@ -309,8 +320,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:41:9
    |
 LL |         (0, x)?.f() => (),
-   |         ^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == (0, x)?.f() => (),
@@ -333,8 +345,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:42:9
    |
 LL |         x.f().g() => (),
-   |         ^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == x.f().g() => (),
@@ -357,8 +370,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:43:9
    |
 LL |         0.f()?.g()?? => (),
-   |         ^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == 0.f()?.g()?? => (),
@@ -381,8 +395,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:50:9
    |
 LL |         x as usize => (),
-   |         ^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == x as usize => (),
@@ -402,8 +417,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:51:9
    |
 LL |         0 as usize => (),
-   |         ^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == 0 as usize => (),
@@ -424,8 +440,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:52:9
    |
 LL |         x.f().0.4 as f32 => (),
-   |         ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^^^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == x.f().0.4 as f32 => (),
@@ -447,8 +464,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:59:9
    |
 LL |         1 + 1 => (),
-   |         ^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == 1 + 1 => (),
@@ -468,8 +486,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:60:9
    |
 LL |         (1 + 2) * 3 => (),
-   |         ^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == (1 + 2) * 3 => (),
@@ -490,8 +509,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:63:9
    |
 LL |         x.0 > 2 => (),
-   |         ^^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == (x.0 > 2) => (),
@@ -514,8 +534,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:64:9
    |
 LL |         x.0 == 2 => (),
-   |         ^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == (x.0 == 2) => (),
@@ -538,8 +559,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:69:13
    |
 LL |         (x, y.0 > 2) if x != 0 => (),
-   |             ^^^^^^^ arbitrary expressions are not allowed in patterns
+   |             ^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to the match arm guard
    |
 LL |         (x, val) if x != 0 && val == (y.0 > 2) => (),
@@ -559,8 +581,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:70:13
    |
 LL |         (x, y.0 > 2) if x != 0 || x != 1 => (),
-   |             ^^^^^^^ arbitrary expressions are not allowed in patterns
+   |             ^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to the match arm guard
    |
 LL |         (x, val) if (x != 0 || x != 1) && val == (y.0 > 2) => (),
@@ -598,8 +621,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:81:9
    |
 LL |         u8::MAX.abs() => (),
-   |         ^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == u8::MAX.abs() => (),
@@ -619,8 +643,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:86:17
    |
 LL |         z @ w @ v.u() => (),
-   |                 ^^^^^ arbitrary expressions are not allowed in patterns
+   |                 ^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         z @ w @ val if val == v.u() => (),
@@ -643,8 +668,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:88:9
    |
 LL |         y.ilog(3) => (),
-   |         ^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == y.ilog(3) => (),
@@ -667,8 +693,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:90:9
    |
 LL |         n + 1 => (),
-   |         ^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == n + 1 => (),
@@ -691,8 +718,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:92:10
    |
 LL |         ("".f() + 14 * 8) => (),
-   |          ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |          ^^^^^^^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         (val) if val == "".f() + 14 * 8 => (),
@@ -715,8 +743,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:95:9
    |
 LL |         f?() => (),
-   |         ^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         val if val == f?() => (),
@@ -739,7 +768,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:101:9
    |
 LL |     let 1 + 1 = 2;
-   |         ^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^ not a pattern
+   |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 
 error: expected one of `)`, `,`, `@`, or `|`, found `*`
   --> $DIR/recover-pat-exprs.rs:104:28
@@ -754,19 +785,25 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:60:10
    |
 LL |         (1 + 2) * 3 => (),
-   |          ^^^^^ arbitrary expressions are not allowed in patterns
+   |          ^^^^^ not a pattern
+   |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 
 error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:75:5
    |
 LL |     1 + 2 * PI.cos() => 2,
-   |     ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |     ^^^^^^^^^^^^^^^^ not a pattern
+   |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 
 error: expected a pattern, found an expression
   --> $DIR/recover-pat-exprs.rs:83:9
    |
 LL |         x.sqrt() @ .. => (),
-   |         ^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^^^ not a pattern
+   |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 
 error: aborting due to 45 previous errors
 
diff --git a/tests/ui/parser/recover/recover-pat-issues.stderr b/tests/ui/parser/recover/recover-pat-issues.stderr
index 596bff21395..17cb7b4aead 100644
--- a/tests/ui/parser/recover/recover-pat-issues.stderr
+++ b/tests/ui/parser/recover/recover-pat-issues.stderr
@@ -2,8 +2,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-issues.rs:6:13
    |
 LL |         Foo("hi".to_owned()) => true,
-   |             ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |             ^^^^^^^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         Foo(val) if val == "hi".to_owned() => true,
@@ -23,8 +24,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-issues.rs:14:20
    |
 LL |         Bar { baz: "hi".to_owned() } => true,
-   |                    ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |                    ^^^^^^^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         Bar { baz } if baz == "hi".to_owned() => true,
@@ -44,8 +46,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-issues.rs:25:11
    |
 LL |         &["foo".to_string()] => {}
-   |           ^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |           ^^^^^^^^^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider moving the expression to a match arm guard
    |
 LL |         &[val] if val == "foo".to_string() => {}
@@ -65,8 +68,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-issues.rs:36:17
    |
 LL |     if let Some(MAGIC.0 as usize) = None::<usize> {}
-   |                 ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |                 ^^^^^^^^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider extracting the expression into a `const`
    |
 LL +     const VAL: /* Type */ = MAGIC.0 as usize;
@@ -81,8 +85,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-issues.rs:41:13
    |
 LL |     if let (-1.some(4)) = (0, Some(4)) {}
-   |             ^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |             ^^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider extracting the expression into a `const`
    |
 LL +     const VAL: /* Type */ = -1.some(4);
@@ -97,8 +102,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-issues.rs:44:13
    |
 LL |     if let (-1.Some(4)) = (0, Some(4)) {}
-   |             ^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |             ^^^^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider extracting the expression into a `const`
    |
 LL +     const VAL: /* Type */ = -1.Some(4);
diff --git a/tests/ui/parser/recover/recover-pat-lets.stderr b/tests/ui/parser/recover/recover-pat-lets.stderr
index e54586b0924..b481813b246 100644
--- a/tests/ui/parser/recover/recover-pat-lets.stderr
+++ b/tests/ui/parser/recover/recover-pat-lets.stderr
@@ -2,26 +2,33 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-lets.rs:4:9
    |
 LL |     let x.expect("foo");
-   |         ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^^^^^^^^^^ not a pattern
+   |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 
 error: expected a pattern, found an expression
   --> $DIR/recover-pat-lets.rs:7:9
    |
 LL |     let x.unwrap(): u32;
-   |         ^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^^^^^^ not a pattern
+   |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 
 error: expected a pattern, found an expression
   --> $DIR/recover-pat-lets.rs:10:9
    |
 LL |     let x[0] = 1;
-   |         ^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^ not a pattern
+   |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 
 error: expected a pattern, found an expression
   --> $DIR/recover-pat-lets.rs:13:14
    |
 LL |     let Some(1 + 1) = x else {
-   |              ^^^^^ arbitrary expressions are not allowed in patterns
+   |              ^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider extracting the expression into a `const`
    |
 LL +     const VAL: /* Type */ = 1 + 1;
@@ -36,8 +43,9 @@ error: expected a pattern, found an expression
   --> $DIR/recover-pat-lets.rs:17:17
    |
 LL |     if let Some(1 + 1) = x {
-   |                 ^^^^^ arbitrary expressions are not allowed in patterns
+   |                 ^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider extracting the expression into a `const`
    |
 LL +     const VAL: /* Type */ = 1 + 1;
diff --git a/tests/ui/parser/recover/recover-pat-ranges.stderr b/tests/ui/parser/recover/recover-pat-ranges.stderr
index 088f83b0ccb..0a9b5447468 100644
--- a/tests/ui/parser/recover/recover-pat-ranges.stderr
+++ b/tests/ui/parser/recover/recover-pat-ranges.stderr
@@ -86,8 +86,9 @@ error: expected a pattern range bound, found an expression
   --> $DIR/recover-pat-ranges.rs:11:12
    |
 LL |         ..=1 + 2 => (),
-   |            ^^^^^ arbitrary expressions are not allowed in patterns
+   |            ^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider extracting the expression into a `const`
    |
 LL +     const VAL: /* Type */ = 1 + 2;
@@ -106,8 +107,9 @@ error: expected a pattern range bound, found an expression
   --> $DIR/recover-pat-ranges.rs:15:10
    |
 LL |         (-4 + 0).. => (),
-   |          ^^^^^^ arbitrary expressions are not allowed in patterns
+   |          ^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider extracting the expression into a `const`
    |
 LL +     const VAL: /* Type */ = -4 + 0;
@@ -126,8 +128,9 @@ error: expected a pattern range bound, found an expression
   --> $DIR/recover-pat-ranges.rs:18:10
    |
 LL |         (1 + 4)...1 * 2 => (),
-   |          ^^^^^ arbitrary expressions are not allowed in patterns
+   |          ^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider extracting the expression into a `const`
    |
 LL +     const VAL: /* Type */ = 1 + 4;
@@ -146,8 +149,9 @@ error: expected a pattern range bound, found an expression
   --> $DIR/recover-pat-ranges.rs:18:19
    |
 LL |         (1 + 4)...1 * 2 => (),
-   |                   ^^^^^ arbitrary expressions are not allowed in patterns
+   |                   ^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider extracting the expression into a `const`
    |
 LL +     const VAL: /* Type */ = 1 * 2;
@@ -166,8 +170,9 @@ error: expected a pattern range bound, found an expression
   --> $DIR/recover-pat-ranges.rs:24:9
    |
 LL |         0.x()..="y".z() => (),
-   |         ^^^^^ arbitrary expressions are not allowed in patterns
+   |         ^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider extracting the expression into a `const`
    |
 LL +     const VAL: /* Type */ = 0.x();
@@ -186,8 +191,9 @@ error: expected a pattern range bound, found an expression
   --> $DIR/recover-pat-ranges.rs:24:17
    |
 LL |         0.x()..="y".z() => (),
-   |                 ^^^^^^^ arbitrary expressions are not allowed in patterns
+   |                 ^^^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider extracting the expression into a `const`
    |
 LL +     const VAL: /* Type */ = "y".z();
diff --git a/tests/ui/parser/recover/recover-pat-wildcards.stderr b/tests/ui/parser/recover/recover-pat-wildcards.stderr
index 30307726a97..8d4212ed389 100644
--- a/tests/ui/parser/recover/recover-pat-wildcards.stderr
+++ b/tests/ui/parser/recover/recover-pat-wildcards.stderr
@@ -75,8 +75,9 @@ error: expected a pattern range bound, found an expression
   --> $DIR/recover-pat-wildcards.rs:55:14
    |
 LL |         4..=(2 + _) => ()
-   |              ^^^^^ arbitrary expressions are not allowed in patterns
+   |              ^^^^^ not a pattern
    |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 help: consider extracting the expression into a `const`
    |
 LL +     const VAL: /* Type */ = 2 + _;
diff --git a/tests/ui/pattern/at-in-struct-patterns.rs b/tests/ui/pattern/at-in-struct-patterns.rs
new file mode 100644
index 00000000000..e8fad61f317
--- /dev/null
+++ b/tests/ui/pattern/at-in-struct-patterns.rs
@@ -0,0 +1,14 @@
+struct Foo {
+    field1: u8,
+    field2: u8,
+}
+
+fn main() {
+    let foo = Foo { field1: 1, field2: 2 };
+    let Foo { var @ field1, .. } = foo; //~ ERROR Unexpected `@` in struct pattern
+    dbg!(var); //~ ERROR cannot find value `var` in this scope
+    let Foo { field1: _, bar @ .. } = foo; //~ ERROR `@ ..` is not supported in struct patterns
+    let Foo { bar @ .. } = foo; //~ ERROR `@ ..` is not supported in struct patterns
+    let Foo { @ } = foo; //~ ERROR expected identifier, found `@`
+    let Foo { @ .. } = foo; //~ ERROR expected identifier, found `@`
+}
diff --git a/tests/ui/pattern/at-in-struct-patterns.stderr b/tests/ui/pattern/at-in-struct-patterns.stderr
new file mode 100644
index 00000000000..ff75edfe681
--- /dev/null
+++ b/tests/ui/pattern/at-in-struct-patterns.stderr
@@ -0,0 +1,69 @@
+error: Unexpected `@` in struct pattern
+  --> $DIR/at-in-struct-patterns.rs:8:15
+   |
+LL |     let Foo { var @ field1, .. } = foo;
+   |         ---   ^^^^^
+   |         |
+   |         while parsing the fields for this pattern
+   |
+   = note: struct patterns use `field: pattern` syntax to bind to fields
+   = help: consider replacing `new_name @ field_name` with `field_name: new_name` if that is what you intended
+
+error: `@ ..` is not supported in struct patterns
+  --> $DIR/at-in-struct-patterns.rs:10:26
+   |
+LL |     let Foo { field1: _, bar @ .. } = foo;
+   |         ---              ^^^^^^^^
+   |         |
+   |         while parsing the fields for this pattern
+   |
+help: bind to each field separately or, if you don't need them, just remove `bar @`
+   |
+LL -     let Foo { field1: _, bar @ .. } = foo;
+LL +     let Foo { field1: _, .. } = foo;
+   |
+
+error: `@ ..` is not supported in struct patterns
+  --> $DIR/at-in-struct-patterns.rs:11:15
+   |
+LL |     let Foo { bar @ .. } = foo;
+   |         ---   ^^^^^^^^
+   |         |
+   |         while parsing the fields for this pattern
+   |
+help: bind to each field separately or, if you don't need them, just remove `bar @`
+   |
+LL -     let Foo { bar @ .. } = foo;
+LL +     let Foo { .. } = foo;
+   |
+
+error: expected identifier, found `@`
+  --> $DIR/at-in-struct-patterns.rs:12:15
+   |
+LL |     let Foo { @ } = foo;
+   |         ---   ^ expected identifier
+   |         |
+   |         while parsing the fields for this pattern
+
+error: expected identifier, found `@`
+  --> $DIR/at-in-struct-patterns.rs:13:15
+   |
+LL |     let Foo { @ .. } = foo;
+   |         ---   ^ expected identifier
+   |         |
+   |         while parsing the fields for this pattern
+
+error[E0425]: cannot find value `var` in this scope
+  --> $DIR/at-in-struct-patterns.rs:9:10
+   |
+LL |     dbg!(var);
+   |          ^^^ not found in this scope
+   |
+help: consider importing this function
+   |
+LL + use std::env::var;
+   |
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/privacy/private-type-in-interface.rs b/tests/ui/privacy/private-type-in-interface.rs
index 2e8be28d76e..9eadd09867d 100644
--- a/tests/ui/privacy/private-type-in-interface.rs
+++ b/tests/ui/privacy/private-type-in-interface.rs
@@ -26,7 +26,5 @@ type A = <m::Alias as m::Trait>::X; //~ ERROR type `Priv` is private
 trait Tr2<T> {}
 impl<T> Tr2<T> for u8 {}
 fn g() -> impl Tr2<m::Alias> { 0 } //~ ERROR type `Priv` is private
-                                   //~| ERROR type `Priv` is private
 fn g_ext() -> impl Tr2<ext::Alias> { 0 } //~ ERROR type `ext::Priv` is private
-                                         //~| ERROR type `ext::Priv` is private
 fn main() {}
diff --git a/tests/ui/privacy/private-type-in-interface.stderr b/tests/ui/privacy/private-type-in-interface.stderr
index 091cae42dea..03225d84fdb 100644
--- a/tests/ui/privacy/private-type-in-interface.stderr
+++ b/tests/ui/privacy/private-type-in-interface.stderr
@@ -46,23 +46,11 @@ error: type `Priv` is private
 LL | fn g() -> impl Tr2<m::Alias> { 0 }
    |           ^^^^^^^^^^^^^^^^^^ private type
 
-error: type `Priv` is private
-  --> $DIR/private-type-in-interface.rs:28:11
-   |
-LL | fn g() -> impl Tr2<m::Alias> { 0 }
-   |           ^^^^^^^^^^^^^^^^^^ private type
-
-error: type `ext::Priv` is private
-  --> $DIR/private-type-in-interface.rs:30:15
-   |
-LL | fn g_ext() -> impl Tr2<ext::Alias> { 0 }
-   |               ^^^^^^^^^^^^^^^^^^^^ private type
-
 error: type `ext::Priv` is private
-  --> $DIR/private-type-in-interface.rs:30:15
+  --> $DIR/private-type-in-interface.rs:29:15
    |
 LL | fn g_ext() -> impl Tr2<ext::Alias> { 0 }
    |               ^^^^^^^^^^^^^^^^^^^^ private type
 
-error: aborting due to 11 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/tests/ui/raw-ref-op/never-place-isnt-diverging.rs b/tests/ui/raw-ref-op/never-place-isnt-diverging.rs
new file mode 100644
index 00000000000..80d441729f7
--- /dev/null
+++ b/tests/ui/raw-ref-op/never-place-isnt-diverging.rs
@@ -0,0 +1,22 @@
+#![feature(never_type)]
+
+fn make_up_a_value<T>() -> T {
+    unsafe {
+    //~^ ERROR mismatched types
+        let x: *const ! = 0 as _;
+        &raw const *x;
+        // Since `*x` is `!`, HIR typeck used to think that it diverges
+        // and allowed the block to coerce to any value, leading to UB.
+    }
+}
+
+
+fn make_up_a_pointer<T>() -> *const T {
+    unsafe {
+        let x: *const ! = 0 as _;
+        &raw const *x
+        //~^ ERROR mismatched types
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/raw-ref-op/never-place-isnt-diverging.stderr b/tests/ui/raw-ref-op/never-place-isnt-diverging.stderr
new file mode 100644
index 00000000000..af9e7889821
--- /dev/null
+++ b/tests/ui/raw-ref-op/never-place-isnt-diverging.stderr
@@ -0,0 +1,34 @@
+error[E0308]: mismatched types
+  --> $DIR/never-place-isnt-diverging.rs:4:5
+   |
+LL |   fn make_up_a_value<T>() -> T {
+   |                      - expected this type parameter
+LL | /     unsafe {
+LL | |
+LL | |         let x: *const ! = 0 as _;
+LL | |         &raw const *x;
+LL | |         // Since `*x` is `!`, HIR typeck used to think that it diverges
+LL | |         // and allowed the block to coerce to any value, leading to UB.
+LL | |     }
+   | |_____^ expected type parameter `T`, found `()`
+   |
+   = note: expected type parameter `T`
+                   found unit type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/never-place-isnt-diverging.rs:17:9
+   |
+LL | fn make_up_a_pointer<T>() -> *const T {
+   |                      -       -------- expected `*const T` because of return type
+   |                      |
+   |                      expected this type parameter
+...
+LL |         &raw const *x
+   |         ^^^^^^^^^^^^^ expected `*const T`, found `*const !`
+   |
+   = note: expected raw pointer `*const T`
+              found raw pointer `*const !`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/reachable/expr_assign.stderr b/tests/ui/reachable/expr_assign.stderr
index c51156b3f40..cfbbe04db76 100644
--- a/tests/ui/reachable/expr_assign.stderr
+++ b/tests/ui/reachable/expr_assign.stderr
@@ -14,12 +14,13 @@ LL | #![deny(unreachable_code)]
    |         ^^^^^^^^^^^^^^^^
 
 error: unreachable expression
-  --> $DIR/expr_assign.rs:20:14
+  --> $DIR/expr_assign.rs:20:9
    |
 LL |         *p = return;
-   |         --   ^^^^^^ unreachable expression
-   |         |
-   |         any code following this expression is unreachable
+   |         ^^^^^------
+   |         |    |
+   |         |    any code following this expression is unreachable
+   |         unreachable expression
 
 error: unreachable expression
   --> $DIR/expr_assign.rs:26:15
diff --git a/tests/ui/resolve/issue-10200.rs b/tests/ui/resolve/issue-10200.rs
index fe36a7e00bf..d529536b952 100644
--- a/tests/ui/resolve/issue-10200.rs
+++ b/tests/ui/resolve/issue-10200.rs
@@ -3,7 +3,7 @@ fn foo(_: usize) -> Foo { Foo(false) }
 
 fn main() {
     match Foo(true) {
-        foo(x) //~ ERROR expected tuple struct or tuple variant, found function `foo`
+        foo(x) //~ ERROR expected a pattern, found a function call
         => ()
     }
 }
diff --git a/tests/ui/resolve/issue-10200.stderr b/tests/ui/resolve/issue-10200.stderr
index 7b218694b26..172d016c6e6 100644
--- a/tests/ui/resolve/issue-10200.stderr
+++ b/tests/ui/resolve/issue-10200.stderr
@@ -1,4 +1,4 @@
-error[E0532]: expected tuple struct or tuple variant, found function `foo`
+error[E0532]: expected a pattern, found a function call
   --> $DIR/issue-10200.rs:6:9
    |
 LL | struct Foo(bool);
@@ -6,6 +6,8 @@ LL | struct Foo(bool);
 ...
 LL |         foo(x)
    |         ^^^ help: a tuple struct with a similar name exists (notice the capitalization): `Foo`
+   |
+   = note: function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs
index 0c73b9abf35..0e85515fd10 100644
--- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs
+++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs
@@ -1,14 +1,14 @@
 //@ needs-asm-support
 #![feature(naked_functions)]
 
-use std::arch::asm;
+use std::arch::naked_asm;
 
 #[track_caller] //~ ERROR [E0736]
 //~^ ERROR `#[track_caller]` requires Rust ABI
 #[naked]
 extern "C" fn f() {
     unsafe {
-        asm!("", options(noreturn));
+        naked_asm!("");
     }
 }
 
@@ -20,7 +20,7 @@ impl S {
     #[naked]
     extern "C" fn g() {
         unsafe {
-            asm!("", options(noreturn));
+            naked_asm!("");
         }
     }
 }
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr
index fb491453b37..8288c660ce7 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr
@@ -3,11 +3,11 @@ error: using `#![feature(effects)]` without enabling next trait solver globally
    = note: the next trait solver must be enabled globally for the effects feature to work correctly
    = help: use `-Znext-solver` to enable
 
-error[E0277]: the trait bound `Trait::{synthetic#0}: Compat` is not satisfied
+error[E0277]: the trait bound `<T as Trait>::Assoc: Trait` is not satisfied
   --> $DIR/assoc-type-const-bound-usage-0.rs:13:5
    |
 LL |     T::Assoc::func()
-   |     ^^^^^^^^ the trait `Compat` is not implemented for `Trait::{synthetic#0}`
+   |     ^^^^^^^^ the trait `Trait` is not implemented for `<T as Trait>::Assoc`
    |
 note: required by a bound in `Trait::func`
   --> $DIR/assoc-type-const-bound-usage-0.rs:6:1
@@ -17,12 +17,16 @@ LL | #[const_trait]
 ...
 LL |     fn func() -> i32;
    |        ---- required by a bound in this associated function
+help: consider further restricting the associated type
+   |
+LL | const fn unqualified<T: ~const Trait>() -> i32 where <T as Trait>::Assoc: Trait {
+   |                                                ++++++++++++++++++++++++++++++++
 
-error[E0277]: the trait bound `Trait::{synthetic#0}: Compat` is not satisfied
+error[E0277]: the trait bound `<T as Trait>::Assoc: Trait` is not satisfied
   --> $DIR/assoc-type-const-bound-usage-0.rs:17:5
    |
 LL |     <T as Trait>::Assoc::func()
-   |     ^^^^^^^^^^^^^^^^^^^ the trait `Compat` is not implemented for `Trait::{synthetic#0}`
+   |     ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `<T as Trait>::Assoc`
    |
 note: required by a bound in `Trait::func`
   --> $DIR/assoc-type-const-bound-usage-0.rs:6:1
@@ -32,6 +36,10 @@ LL | #[const_trait]
 ...
 LL |     fn func() -> i32;
    |        ---- required by a bound in this associated function
+help: consider further restricting the associated type
+   |
+LL | const fn qualified<T: ~const Trait>() -> i32 where <T as Trait>::Assoc: Trait {
+   |                                              ++++++++++++++++++++++++++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr
index 392b310a4c9..0792d090321 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr
@@ -3,11 +3,11 @@ error: using `#![feature(effects)]` without enabling next trait solver globally
    = note: the next trait solver must be enabled globally for the effects feature to work correctly
    = help: use `-Znext-solver` to enable
 
-error[E0277]: the trait bound `Trait::{synthetic#0}: Compat` is not satisfied
+error[E0277]: the trait bound `<T as Trait>::Assoc: Trait` is not satisfied
   --> $DIR/assoc-type-const-bound-usage-1.rs:15:44
    |
 LL | fn unqualified<T: const Trait>() -> Type<{ T::Assoc::func() }> {
-   |                                            ^^^^^^^^ the trait `Compat` is not implemented for `Trait::{synthetic#0}`
+   |                                            ^^^^^^^^ the trait `Trait` is not implemented for `<T as Trait>::Assoc`
    |
 note: required by a bound in `Trait::func`
   --> $DIR/assoc-type-const-bound-usage-1.rs:7:1
@@ -17,12 +17,16 @@ LL | #[const_trait]
 ...
 LL |     fn func() -> i32;
    |        ---- required by a bound in this associated function
+help: consider further restricting the associated type
+   |
+LL | fn unqualified<T: const Trait>() -> Type<{ T::Assoc::func() }> where <T as Trait>::Assoc: Trait {
+   |                                                                ++++++++++++++++++++++++++++++++
 
-error[E0277]: the trait bound `Trait::{synthetic#0}: Compat` is not satisfied
+error[E0277]: the trait bound `<T as Trait>::Assoc: Trait` is not satisfied
   --> $DIR/assoc-type-const-bound-usage-1.rs:19:42
    |
 LL | fn qualified<T: const Trait>() -> Type<{ <T as Trait>::Assoc::func() }> {
-   |                                          ^^^^^^^^^^^^^^^^^^^ the trait `Compat` is not implemented for `Trait::{synthetic#0}`
+   |                                          ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `<T as Trait>::Assoc`
    |
 note: required by a bound in `Trait::func`
   --> $DIR/assoc-type-const-bound-usage-1.rs:7:1
@@ -32,6 +36,10 @@ LL | #[const_trait]
 ...
 LL |     fn func() -> i32;
    |        ---- required by a bound in this associated function
+help: consider further restricting the associated type
+   |
+LL | fn qualified<T: const Trait>() -> Type<{ <T as Trait>::Assoc::func() }> where <T as Trait>::Assoc: Trait {
+   |                                                                         ++++++++++++++++++++++++++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs
index bb9e9045f8f..878f9a713a0 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs
@@ -1,4 +1,6 @@
-#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete
+//@ compile-flags: -Znext-solver
+#![allow(incomplete_features)]
+#![feature(const_trait_impl, effects)]
 
 #[const_trait]
 pub trait Plus {
@@ -23,7 +25,7 @@ pub const fn add_i32(a: i32, b: i32) -> i32 {
 
 pub const fn add_u32(a: u32, b: u32) -> u32 {
     a.plus(b)
-    //~^ ERROR the trait bound
+    //~^ ERROR the trait bound `u32: ~const Plus`
 }
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr
index 73ea1422bf9..5d2333d94fe 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr
@@ -1,33 +1,22 @@
-warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/call-const-trait-method-fail.rs:1:30
-   |
-LL | #![feature(const_trait_impl, effects)]
-   |                              ^^^^^^^
-   |
-   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error[E0277]: the trait bound `Runtime: ~const Compat` is not satisfied
-  --> $DIR/call-const-trait-method-fail.rs:25:5
+error[E0277]: the trait bound `u32: ~const Plus` is not satisfied
+  --> $DIR/call-const-trait-method-fail.rs:27:5
    |
 LL |     a.plus(b)
-   |     ^ the trait `~const Compat` is not implemented for `Runtime`
+   |     ^ the trait `Plus` is not implemented for `u32`
    |
-   = help: the trait `Compat` is implemented for `Runtime`
 note: required by a bound in `Plus::plus`
-  --> $DIR/call-const-trait-method-fail.rs:3:1
+  --> $DIR/call-const-trait-method-fail.rs:5:1
    |
 LL | #[const_trait]
    | ^^^^^^^^^^^^^^ required by this bound in `Plus::plus`
 LL | pub trait Plus {
 LL |     fn plus(self, rhs: Self) -> Self;
    |        ---- required by a bound in this associated function
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | pub const fn add_u32(a: u32, b: u32) -> u32 where u32: Plus {
+   |                                             +++++++++++++++
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs
index 74e33ca72ff..f9e79d41752 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs
@@ -1,4 +1,6 @@
-#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete
+//@ compile-flags: -Znext-solver
+#![allow(incomplete_features)]
+#![feature(const_trait_impl, effects)]
 
 struct S;
 
@@ -21,7 +23,6 @@ const fn equals_self<T: ~const Foo>(t: &T) -> bool {
 // it not using the impl.
 
 pub const EQ: bool = equals_self(&S);
-//~^ ERROR: the trait bound `Runtime: const Compat` is not satisfied
-// FIXME(effects) diagnostic
+//~^ ERROR: the trait bound `S: const Foo` is not satisfied
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr
index b2a98041c1c..68c9fc40010 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr
@@ -1,32 +1,21 @@
-warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/call-generic-method-nonconst.rs:1:30
-   |
-LL | #![feature(const_trait_impl, effects)]
-   |                              ^^^^^^^
-   |
-   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error[E0277]: the trait bound `Runtime: const Compat` is not satisfied
-  --> $DIR/call-generic-method-nonconst.rs:23:34
+error[E0277]: the trait bound `S: const Foo` is not satisfied
+  --> $DIR/call-generic-method-nonconst.rs:25:34
    |
 LL | pub const EQ: bool = equals_self(&S);
-   |                      ----------- ^^ the trait `const Compat` is not implemented for `Runtime`
+   |                      ----------- ^^ the trait `Foo` is not implemented for `S`
    |                      |
    |                      required by a bound introduced by this call
    |
-   = help: the trait `Compat` is implemented for `Runtime`
 note: required by a bound in `equals_self`
-  --> $DIR/call-generic-method-nonconst.rs:16:25
+  --> $DIR/call-generic-method-nonconst.rs:18:25
    |
 LL | const fn equals_self<T: ~const Foo>(t: &T) -> bool {
    |                         ^^^^^^^^^^ required by this bound in `equals_self`
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | pub const EQ: bool where S: Foo = equals_self(&S);
+   |                    ++++++++++++
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs
index 2fd58b05178..a0333153f85 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs
@@ -1,4 +1,6 @@
-#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete
+//@ compile-flags: -Znext-solver
+#![allow(incomplete_features)]
+#![feature(const_trait_impl, effects)]
 
 #[const_trait]
 trait ConstDefaultFn: Sized {
@@ -22,7 +24,7 @@ impl const ConstDefaultFn for ConstImpl {
 
 const fn test() {
     NonConstImpl.a();
-    //~^ ERROR the trait bound
+    //~^ ERROR the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied
     ConstImpl.a();
 }
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
index 02f9dffba32..0809d9c1e1d 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
@@ -1,33 +1,22 @@
-warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/const-default-method-bodies.rs:1:30
-   |
-LL | #![feature(const_trait_impl, effects)]
-   |                              ^^^^^^^
-   |
-   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error[E0277]: the trait bound `Runtime: ~const Compat` is not satisfied
-  --> $DIR/const-default-method-bodies.rs:24:18
+error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied
+  --> $DIR/const-default-method-bodies.rs:26:18
    |
 LL |     NonConstImpl.a();
-   |                  ^ the trait `~const Compat` is not implemented for `Runtime`
+   |                  ^ the trait `ConstDefaultFn` is not implemented for `NonConstImpl`
    |
-   = help: the trait `Compat` is implemented for `Runtime`
 note: required by a bound in `ConstDefaultFn::a`
-  --> $DIR/const-default-method-bodies.rs:3:1
+  --> $DIR/const-default-method-bodies.rs:5:1
    |
 LL | #[const_trait]
    | ^^^^^^^^^^^^^^ required by this bound in `ConstDefaultFn::a`
 ...
 LL |     fn a(self) {
    |        - required by a bound in this associated function
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | const fn test() where NonConstImpl: ConstDefaultFn {
+   |                 ++++++++++++++++++++++++++++++++++
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr
index 7aa3aa8c6bb..9eda9d98ec5 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `FnOnce<()>::{synthetic#0}: const Compat` is not satisfied
+error[E0277]: the trait bound `fn() {foo}: const FnOnce()` is not satisfied
   --> $DIR/const-fns-are-early-bound.rs:31:17
    |
 LL |     is_const_fn(foo);
-   |     ----------- ^^^ the trait `const Compat` is not implemented for `FnOnce<()>::{synthetic#0}`
+   |     ----------- ^^^ the trait `FnOnce()` is not implemented for fn item `fn() {foo}`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr
index b59c6d1eed8..1040af7541c 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr
@@ -68,76 +68,76 @@ LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
    |                                                ^^^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:25:29
+  --> $DIR/const-impl-trait.rs:29:29
    |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
+LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
    |                             ^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:25:48
+  --> $DIR/const-impl-trait.rs:29:48
    |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
+LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
    |                                                ^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:25:29
+  --> $DIR/const-impl-trait.rs:29:29
    |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
+LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
    |                             ^^^^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:25:48
+  --> $DIR/const-impl-trait.rs:29:48
    |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
+LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
    |                                                ^^^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:29:29
+  --> $DIR/const-impl-trait.rs:50:41
    |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
-   |                             ^^^^^^^^^
+LL | const fn apit(_: impl ~const T + ~const Destruct) {}
+   |                                         ^^^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:29:48
+  --> $DIR/const-impl-trait.rs:54:73
    |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
-   |                                                ^^^^^^^^
+LL | const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~const Destruct) {}
+   |                                                                         ^^^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:29:29
+  --> $DIR/const-impl-trait.rs:25:29
    |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
+LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
    |                             ^^^^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:29:48
+  --> $DIR/const-impl-trait.rs:25:48
    |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
+LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
    |                                                ^^^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:50:41
+  --> $DIR/const-impl-trait.rs:25:29
    |
-LL | const fn apit(_: impl ~const T + ~const Destruct) {}
-   |                                         ^^^^^^^^
+LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
+   |                             ^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:54:73
+  --> $DIR/const-impl-trait.rs:25:48
    |
-LL | const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~const Destruct) {}
-   |                                                                         ^^^^^^^^
+LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
+   |                                                ^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-impl-trait.rs:25:29
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr
index b7209827c22..a34bae843c8 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `cross_crate::MyTrait::{synthetic#0}: ~const Compat` is not satisfied
+error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied
   --> $DIR/cross-crate.rs:19:14
    |
 LL |     NonConst.func();
-   |              ^^^^ the trait `~const Compat` is not implemented for `cross_crate::MyTrait::{synthetic#0}`
+   |              ^^^^ the trait `cross_crate::MyTrait` is not implemented for `cross_crate::NonConst`
    |
 note: required by a bound in `func`
   --> $DIR/auxiliary/cross-crate.rs:5:1
@@ -12,6 +12,10 @@ LL | #[const_trait]
 ...
 LL |     fn func(self);
    |        ---- required by a bound in this associated function
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | const fn const_context() where cross_crate::NonConst: cross_crate::MyTrait {
+   |                          +++++++++++++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
index 64f23824b39..0c2d93775a4 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
@@ -1,4 +1,6 @@
-#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete
+//@ compile-flags: -Znext-solver
+#![allow(incomplete_features)]
+#![feature(const_trait_impl, effects)]
 
 #[const_trait]
 pub trait Tr {
@@ -6,7 +8,7 @@ pub trait Tr {
 
     fn b(&self) {
         ().a()
-        //~^ ERROR the trait bound
+        //~^ ERROR the trait bound `(): ~const Tr` is not satisfied
     }
 }
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
index 1b5aa9c9191..d0f22c0b9b6 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
@@ -1,33 +1,22 @@
-warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/default-method-body-is-const-same-trait-ck.rs:1:30
-   |
-LL | #![feature(const_trait_impl, effects)]
-   |                              ^^^^^^^
-   |
-   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error[E0277]: the trait bound `Runtime: ~const Compat` is not satisfied
-  --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12
+error[E0277]: the trait bound `(): ~const Tr` is not satisfied
+  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
    |
 LL |         ().a()
-   |            ^ the trait `~const Compat` is not implemented for `Runtime`
+   |            ^ the trait `Tr` is not implemented for `()`
    |
-   = help: the trait `Compat` is implemented for `Runtime`
 note: required by a bound in `Tr::a`
-  --> $DIR/default-method-body-is-const-same-trait-ck.rs:3:1
+  --> $DIR/default-method-body-is-const-same-trait-ck.rs:5:1
    |
 LL | #[const_trait]
    | ^^^^^^^^^^^^^^ required by this bound in `Tr::a`
 LL | pub trait Tr {
 LL |     fn a(&self) {}
    |        - required by a bound in this associated function
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | pub trait Tr where (): Tr {
+   |              ++++++++++++
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr
index 8c814295de4..8e12b40381f 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr
@@ -22,7 +22,7 @@ error: `Dimension` is forbidden as the type of a const generic parameter
 LL | pub struct Quantity<S, const D: Dimension>(S);
    |                                 ^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -40,7 +40,7 @@ error: `Dimension` is forbidden as the type of a const generic parameter
 LL | impl<const D: Dimension, LHS, RHS> Add<LHS, D> for Quantity<LHS, { Dimension }> {}
    |               ^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -52,7 +52,7 @@ error: `Dimension` is forbidden as the type of a const generic parameter
 LL | pub fn add<const U: Dimension>(x: Quantity<f32, U>) -> Quantity<f32, U> {
    |                     ^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs
index 0d659744e70..93a6f385e47 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs
@@ -17,8 +17,7 @@ trait Bar: ~const Foo {}
 
 const fn foo<T: Bar>(x: &T) {
     x.a();
-    //[yy,yn]~^ ERROR the trait bound
-    // FIXME(effects) diagnostic
+    //[yy,yn]~^ ERROR the trait bound `T: ~const Foo`
 }
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr
index d4064e01ef1..873c57ec71f 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr
@@ -10,11 +10,11 @@ note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bou
 LL | trait Bar: ~const Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied
+error[E0277]: the trait bound `T: ~const Foo` is not satisfied
   --> $DIR/super-traits-fail-2.rs:19:7
    |
 LL |     x.a();
-   |       ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}`
+   |       ^ the trait `Foo` is not implemented for `T`
    |
 note: required by a bound in `Foo::a`
   --> $DIR/super-traits-fail-2.rs:6:25
@@ -24,10 +24,10 @@ LL | #[cfg_attr(any(yy, yn), const_trait)]
 LL | trait Foo {
 LL |     fn a(&self);
    |        - required by a bound in this associated function
-help: consider further restricting the associated type
+help: consider further restricting this bound
    |
-LL | const fn foo<T: Bar>(x: &T) where Foo::{synthetic#0}: ~const Compat {
-   |                             +++++++++++++++++++++++++++++++++++++++
+LL | const fn foo<T: Bar + Foo>(x: &T) {
+   |                     +++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr
index 9f9f96c6b48..bea3aea2f3a 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied
+error[E0277]: the trait bound `T: ~const Foo` is not satisfied
   --> $DIR/super-traits-fail-2.rs:19:7
    |
 LL |     x.a();
-   |       ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}`
+   |       ^ the trait `Foo` is not implemented for `T`
    |
 note: required by a bound in `Foo::a`
   --> $DIR/super-traits-fail-2.rs:6:25
@@ -12,10 +12,10 @@ LL | #[cfg_attr(any(yy, yn), const_trait)]
 LL | trait Foo {
 LL |     fn a(&self);
    |        - required by a bound in this associated function
-help: consider further restricting the associated type
+help: consider further restricting this bound
    |
-LL | const fn foo<T: Bar>(x: &T) where Foo::{synthetic#0}: ~const Compat {
-   |                             +++++++++++++++++++++++++++++++++++++++
+LL | const fn foo<T: Bar + Foo>(x: &T) {
+   |                     +++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs
index 66943512650..b5643b11700 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs
@@ -3,7 +3,7 @@
 #![feature(const_trait_impl, effects)]
 
 //@ revisions: yy yn ny nn
-//@[yy] known-bug: #110395
+//@[yy] check-pass
 
 #[cfg_attr(any(yy, yn), const_trait)]
 trait Foo {
@@ -20,7 +20,7 @@ trait Bar: ~const Foo {}
 const fn foo<T: ~const Bar>(x: &T) {
     //[yn,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
     x.a();
-    //[yn]~^ ERROR: the trait bound
+    //[yn]~^ ERROR: the trait bound `T: ~const Foo` is not satisfied
 }
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr
index 0b48633a10e..bbc95948a59 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr
@@ -16,11 +16,11 @@ error: `~const` can only be applied to `#[const_trait]` traits
 LL | const fn foo<T: ~const Bar>(x: &T) {
    |                        ^^^
 
-error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied
+error[E0277]: the trait bound `T: ~const Foo` is not satisfied
   --> $DIR/super-traits-fail-3.rs:22:7
    |
 LL |     x.a();
-   |       ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}`
+   |       ^ the trait `Foo` is not implemented for `T`
    |
 note: required by a bound in `Foo::a`
   --> $DIR/super-traits-fail-3.rs:8:25
@@ -30,10 +30,10 @@ LL | #[cfg_attr(any(yy, yn), const_trait)]
 LL | trait Foo {
 LL |     fn a(&self);
    |        - required by a bound in this associated function
-help: consider further restricting the associated type
+help: consider further restricting this bound
    |
-LL | const fn foo<T: ~const Bar>(x: &T) where Foo::{synthetic#0}: ~const Compat {
-   |                                    +++++++++++++++++++++++++++++++++++++++
+LL | const fn foo<T: ~const Bar + Foo>(x: &T) {
+   |                            +++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr
deleted file mode 100644
index ea0e6c690b7..00000000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied
-  --> $DIR/super-traits-fail-3.rs:22:7
-   |
-LL |     x.a();
-   |       ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}`
-   |
-note: required by a bound in `Foo::a`
-  --> $DIR/super-traits-fail-3.rs:8:25
-   |
-LL | #[cfg_attr(any(yy, yn), const_trait)]
-   |                         ^^^^^^^^^^^ required by this bound in `Foo::a`
-LL | trait Foo {
-LL |     fn a(&self);
-   |        - required by a bound in this associated function
-help: consider further restricting the associated type
-   |
-LL | const fn foo<T: ~const Bar>(x: &T) where Foo::{synthetic#0}: ~const Compat {
-   |                                    +++++++++++++++++++++++++++++++++++++++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs
index 6c320c0462e..da41d7fcc72 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs
@@ -17,6 +17,6 @@ impl Foo for S {
 }
 
 impl const Bar for S {}
-// FIXME(effects) bad span
+//~^ ERROR the trait bound
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr
index 9a907bbee0a..3870f0f722f 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr
@@ -1,11 +1,24 @@
-error[E0277]: the trait bound `Maybe: TyCompat<<(Foo::{synthetic#0},) as std::marker::effects::Intersection>::Output>` is not satisfied
+error[E0277]: the trait bound `Bar::{synthetic#0}: TyCompat<Foo::{synthetic#0}>` is not satisfied
+  --> $DIR/super-traits-fail.rs:19:12
+   |
+LL | impl const Bar for S {}
+   |            ^^^ the trait `TyCompat<Foo::{synthetic#0}>` is not implemented for `Bar::{synthetic#0}`, which is required by `S: Bar`
+   |
+   = help: the trait `Bar` is implemented for `S`
+note: required for `S` to implement `Bar`
+  --> $DIR/super-traits-fail.rs:12:7
+   |
+LL | trait Bar: ~const Foo {}
+   |       ^^^
+
+error[E0277]: the trait bound `Maybe: TyCompat<Foo::{synthetic#0}>` is not satisfied
    |
 note: required by a bound in `Bar::{synthetic#0}`
-  --> $DIR/super-traits-fail.rs:11:1
+  --> $DIR/super-traits-fail.rs:12:12
    |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ required by this bound in `Bar::{synthetic#0}`
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^^^^^ required by this bound in `Bar::{synthetic#0}`
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs
index fbe89b00b97..ff7349bba3c 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs
@@ -1,5 +1,4 @@
-// FIXME(effects) check-pass
-//@ known-bug: #110395
+//@ check-pass
 //@ compile-flags: -Znext-solver
 #![allow(incomplete_features)]
 #![feature(const_trait_impl, effects)]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr
deleted file mode 100644
index 5b6b39ee05e..00000000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied
-  --> $DIR/super-traits.rs:23:7
-   |
-LL |     t.a();
-   |       ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}`
-   |
-note: required by a bound in `Foo::a`
-  --> $DIR/super-traits.rs:7:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ required by this bound in `Foo::a`
-LL | trait Foo {
-LL |     fn a(&self);
-   |        - required by a bound in this associated function
-help: consider further restricting the associated type
-   |
-LL | const fn foo<T: ~const Bar>(t: &T) where Foo::{synthetic#0}: ~const Compat {
-   |                                    +++++++++++++++++++++++++++++++++++++++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr
index 979f1e798e0..eaa981ec744 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `Foo::{synthetic#0}: Compat` is not satisfied
+error[E0277]: the trait bound `T: Foo` is not satisfied
   --> $DIR/trait-where-clause-const.rs:22:5
    |
 LL |     T::b();
-   |     ^ the trait `Compat` is not implemented for `Foo::{synthetic#0}`
+   |     ^ the trait `Foo` is not implemented for `T`
    |
 note: required by a bound in `Foo::b`
   --> $DIR/trait-where-clause-const.rs:13:1
@@ -12,10 +12,6 @@ LL | #[const_trait]
 ...
 LL |     fn b() where Self: ~const Bar;
    |        - required by a bound in this associated function
-help: consider further restricting the associated type
-   |
-LL | const fn test1<T: ~const Foo + Bar>() where Foo::{synthetic#0}: Compat {
-   |                                       ++++++++++++++++++++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/trait-where-clause-const.rs:22:5
@@ -26,11 +22,11 @@ LL |     T::b();
    = note: expected constant `host`
               found constant `true`
 
-error[E0277]: the trait bound `Foo::{synthetic#0}: Compat` is not satisfied
+error[E0277]: the trait bound `T: Foo` is not satisfied
   --> $DIR/trait-where-clause-const.rs:25:5
    |
 LL |     T::c::<T>();
-   |     ^ the trait `Compat` is not implemented for `Foo::{synthetic#0}`
+   |     ^ the trait `Foo` is not implemented for `T`
    |
 note: required by a bound in `Foo::c`
   --> $DIR/trait-where-clause-const.rs:13:1
@@ -40,10 +36,6 @@ LL | #[const_trait]
 ...
 LL |     fn c<T: ~const Bar>();
    |        - required by a bound in this associated function
-help: consider further restricting the associated type
-   |
-LL | const fn test1<T: ~const Foo + Bar>() where Foo::{synthetic#0}: Compat {
-   |                                       ++++++++++++++++++++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/trait-where-clause-const.rs:25:5
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs
index 5fffe54fc1a..d336719f52e 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs
@@ -19,7 +19,6 @@ impl Trait for Ty {
 }
 
 fn main() {
-    // FIXME(effects): improve diagnostics on this
     require::<Ty>();
 }
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr
index 0806ffa4b5d..848aa68689b 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr
@@ -7,7 +7,7 @@ LL | #![feature(const_trait_impl, effects, generic_const_exprs)]
    = help: remove one of these features
 
 error[E0308]: mismatched types
-  --> $DIR/unsatisfied-const-trait-bound.rs:30:37
+  --> $DIR/unsatisfied-const-trait-bound.rs:29:37
    |
 LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
    |                                     ^^^^^^^^^ expected `false`, found `true`
@@ -16,7 +16,7 @@ LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
               found constant `true`
 
 error[E0308]: mismatched types
-  --> $DIR/unsatisfied-const-trait-bound.rs:34:50
+  --> $DIR/unsatisfied-const-trait-bound.rs:33:50
    |
 LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
    |                                                  ^^^^^^^^^ expected `false`, found `host`
@@ -24,17 +24,21 @@ LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
    = note: expected constant `false`
               found constant `host`
 
-error[E0277]: the trait bound `Trait::{synthetic#0}: const Compat` is not satisfied
-  --> $DIR/unsatisfied-const-trait-bound.rs:23:15
+error[E0277]: the trait bound `Ty: const Trait` is not satisfied
+  --> $DIR/unsatisfied-const-trait-bound.rs:22:15
    |
 LL |     require::<Ty>();
-   |               ^^ the trait `const Compat` is not implemented for `Trait::{synthetic#0}`
+   |               ^^ the trait `Trait` is not implemented for `Ty`
    |
 note: required by a bound in `require`
   --> $DIR/unsatisfied-const-trait-bound.rs:8:15
    |
 LL | fn require<T: const Trait>() {}
    |               ^^^^^^^^^^^ required by this bound in `require`
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | fn main() where Ty: Trait {
+   |           +++++++++++++++
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/self/arbitrary-self-opaque.stderr b/tests/ui/self/arbitrary-self-opaque.stderr
index 5ccc076bfaf..5634b3d6e64 100644
--- a/tests/ui/self/arbitrary-self-opaque.stderr
+++ b/tests/ui/self/arbitrary-self-opaque.stderr
@@ -1,3 +1,12 @@
+error[E0307]: invalid `self` parameter type: `Bar`
+  --> $DIR/arbitrary-self-opaque.rs:8:18
+   |
+LL |     fn foo(self: Bar) {}
+   |                  ^^^
+   |
+   = note: type of `self` must be `Self` or a type that dereferences to it
+   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
 error: item does not constrain `Bar::{opaque#0}`, but has it in its signature
   --> $DIR/arbitrary-self-opaque.rs:8:8
    |
@@ -19,15 +28,6 @@ LL | type Bar = impl Sized;
    |
    = note: `Bar` must be used in combination with a concrete type within the same module
 
-error[E0307]: invalid `self` parameter type: `Bar`
-  --> $DIR/arbitrary-self-opaque.rs:8:18
-   |
-LL |     fn foo(self: Bar) {}
-   |                  ^^^
-   |
-   = note: type of `self` must be `Self` or a type that dereferences to it
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
-
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0307`.
diff --git a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
index b00260fa0ef..f3393830eeb 100644
--- a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
+++ b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
@@ -9,8 +9,8 @@ LL |     async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f }
-   |               ++++            ++           ++
+LL |     async fn a<'a>(self: Pin<&Foo>, f: &'a Foo) -> &'a Foo { f }
+   |               ++++                      ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:75
@@ -23,8 +23,8 @@ LL |     async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
-   |               ++++            ++            ++
+LL |     async fn c<'a>(self: Pin<&Self>, f: &'a Foo, g: &Foo) -> (Pin<&'a Foo>, &'a Foo) { (self, f) }
+   |               ++++                       ++                        ++        ++
 
 error: lifetime may not live long enough
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64
@@ -37,8 +37,8 @@ LL |     async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
    |
 help: consider reusing a named lifetime parameter and update trait if needed
    |
-LL |     async fn bar<'a>(self: Alias<&'a Self>, arg: &'a ()) -> &() { arg }
-   |                                   ++
+LL |     async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &'a () { arg }
+   |                                                           ++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/self/elision/lt-ref-self-async.fixed b/tests/ui/self/elision/lt-ref-self-async.fixed
index 914511641b8..aae94f7a6cc 100644
--- a/tests/ui/self/elision/lt-ref-self-async.fixed
+++ b/tests/ui/self/elision/lt-ref-self-async.fixed
@@ -11,34 +11,34 @@ struct Struct<'a> {
 impl<'a> Struct<'a> {
     // Test using `&self` sugar:
 
-    async fn ref_self<'b>(&'b self, f: &'b u32) -> &u32 {
+    async fn ref_self<'b>(&self, f: &'b u32) -> &'b u32 {
         f
         //~^ ERROR lifetime may not live long enough
     }
 
     // Test using `&Self` explicitly:
 
-    async fn ref_Self<'b>(self: &'b Self, f: &'b u32) -> &u32 {
+    async fn ref_Self<'b>(self: &Self, f: &'b u32) -> &'b u32 {
         f
         //~^ ERROR lifetime may not live long enough
     }
 
-    async fn box_ref_Self<'b>(self: Box<&'b Self>, f: &'b u32) -> &u32 {
+    async fn box_ref_Self<'b>(self: Box<&Self>, f: &'b u32) -> &'b u32 {
         f
         //~^ ERROR lifetime may not live long enough
     }
 
-    async fn pin_ref_Self<'b>(self: Pin<&'b Self>, f: &'b u32) -> &u32 {
+    async fn pin_ref_Self<'b>(self: Pin<&Self>, f: &'b u32) -> &'b u32 {
         f
         //~^ ERROR lifetime may not live long enough
     }
 
-    async fn box_box_ref_Self<'b>(self: Box<Box<&'b Self>>, f: &'b u32) -> &u32 {
+    async fn box_box_ref_Self<'b>(self: Box<Box<&Self>>, f: &'b u32) -> &'b u32 {
         f
         //~^ ERROR lifetime may not live long enough
     }
 
-    async fn box_pin_Self<'b>(self: Box<Pin<&'b Self>>, f: &'b u32) -> &u32 {
+    async fn box_pin_Self<'b>(self: Box<Pin<&Self>>, f: &'b u32) -> &'b u32 {
         f
         //~^ ERROR lifetime may not live long enough
     }
diff --git a/tests/ui/self/elision/lt-ref-self-async.stderr b/tests/ui/self/elision/lt-ref-self-async.stderr
index b84044f7548..c43ff49d508 100644
--- a/tests/ui/self/elision/lt-ref-self-async.stderr
+++ b/tests/ui/self/elision/lt-ref-self-async.stderr
@@ -10,8 +10,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn ref_self<'b>(&'b self, f: &'b u32) -> &u32 {
-   |                      ++++  ++           ++
+LL |     async fn ref_self<'b>(&self, f: &'b u32) -> &'b u32 {
+   |                      ++++            ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self-async.rs:22:9
@@ -25,8 +25,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn ref_Self<'b>(self: &'b Self, f: &'b u32) -> &u32 {
-   |                      ++++        ++           ++
+LL |     async fn ref_Self<'b>(self: &Self, f: &'b u32) -> &'b u32 {
+   |                      ++++                  ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self-async.rs:27:9
@@ -40,8 +40,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_ref_Self<'b>(self: Box<&'b Self>, f: &'b u32) -> &u32 {
-   |                          ++++            ++            ++
+LL |     async fn box_ref_Self<'b>(self: Box<&Self>, f: &'b u32) -> &'b u32 {
+   |                          ++++                       ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self-async.rs:32:9
@@ -55,8 +55,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn pin_ref_Self<'b>(self: Pin<&'b Self>, f: &'b u32) -> &u32 {
-   |                          ++++            ++            ++
+LL |     async fn pin_ref_Self<'b>(self: Pin<&Self>, f: &'b u32) -> &'b u32 {
+   |                          ++++                       ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self-async.rs:37:9
@@ -70,8 +70,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_box_ref_Self<'b>(self: Box<Box<&'b Self>>, f: &'b u32) -> &u32 {
-   |                              ++++                ++             ++
+LL |     async fn box_box_ref_Self<'b>(self: Box<Box<&Self>>, f: &'b u32) -> &'b u32 {
+   |                              ++++                            ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/lt-ref-self-async.rs:42:9
@@ -85,8 +85,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_pin_Self<'b>(self: Box<Pin<&'b Self>>, f: &'b u32) -> &u32 {
-   |                          ++++                ++             ++
+LL |     async fn box_pin_Self<'b>(self: Box<Pin<&Self>>, f: &'b u32) -> &'b u32 {
+   |                          ++++                            ++          ++
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/self/elision/ref-assoc-async.stderr b/tests/ui/self/elision/ref-assoc-async.stderr
index cf54a86b45f..9f2768d5e69 100644
--- a/tests/ui/self/elision/ref-assoc-async.stderr
+++ b/tests/ui/self/elision/ref-assoc-async.stderr
@@ -10,8 +10,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn ref_AssocType<'a>(self: &'a <Struct as Trait>::AssocType, f: &'a u32) -> &u32 {
-   |                           ++++        ++                                   ++
+LL |     async fn ref_AssocType<'a>(self: &<Struct as Trait>::AssocType, f: &'a u32) -> &'a u32 {
+   |                           ++++                                          ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-assoc-async.rs:24:9
@@ -25,8 +25,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_ref_AssocType<'a>(self: Box<&'a <Struct as Trait>::AssocType>, f: &'a u32) -> &u32 {
-   |                               ++++            ++                                    ++
+LL |     async fn box_ref_AssocType<'a>(self: Box<&<Struct as Trait>::AssocType>, f: &'a u32) -> &'a u32 {
+   |                               ++++                                               ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-assoc-async.rs:29:9
@@ -40,8 +40,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn pin_ref_AssocType<'a>(self: Pin<&'a <Struct as Trait>::AssocType>, f: &'a u32) -> &u32 {
-   |                               ++++            ++                                    ++
+LL |     async fn pin_ref_AssocType<'a>(self: Pin<&<Struct as Trait>::AssocType>, f: &'a u32) -> &'a u32 {
+   |                               ++++                                               ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-assoc-async.rs:34:9
@@ -55,8 +55,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_box_ref_AssocType<'a>(self: Box<Box<&'a <Struct as Trait>::AssocType>>, f: &'a u32) -> &u32 {
-   |                                   ++++                ++                                     ++
+LL |     async fn box_box_ref_AssocType<'a>(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &'a u32) -> &'a u32 {
+   |                                   ++++                                                    ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-assoc-async.rs:39:9
@@ -70,8 +70,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_pin_ref_AssocType<'a>(self: Box<Pin<&'a <Struct as Trait>::AssocType>>, f: &'a u32) -> &u32 {
-   |                                   ++++                ++                                     ++
+LL |     async fn box_pin_ref_AssocType<'a>(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &'a u32) -> &'a u32 {
+   |                                   ++++                                                    ++          ++
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/self/elision/ref-mut-self-async.stderr b/tests/ui/self/elision/ref-mut-self-async.stderr
index 62543ba5339..945fb5e0282 100644
--- a/tests/ui/self/elision/ref-mut-self-async.stderr
+++ b/tests/ui/self/elision/ref-mut-self-async.stderr
@@ -10,8 +10,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
-   |                      ++++  ++               ++
+LL |     async fn ref_self<'a>(&mut self, f: &'a u32) -> &'a u32 {
+   |                      ++++                ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self-async.rs:20:9
@@ -25,8 +25,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
-   |                      ++++        ++               ++
+LL |     async fn ref_Self<'a>(self: &mut Self, f: &'a u32) -> &'a u32 {
+   |                      ++++                      ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self-async.rs:25:9
@@ -40,8 +40,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 {
-   |                          ++++            ++                ++
+LL |     async fn box_ref_Self<'a>(self: Box<&mut Self>, f: &'a u32) -> &'a u32 {
+   |                          ++++                           ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self-async.rs:30:9
@@ -55,8 +55,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 {
-   |                          ++++            ++                ++
+LL |     async fn pin_ref_Self<'a>(self: Pin<&mut Self>, f: &'a u32) -> &'a u32 {
+   |                          ++++                           ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self-async.rs:35:9
@@ -70,8 +70,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 {
-   |                              ++++                ++                 ++
+LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&mut Self>>, f: &'a u32) -> &'a u32 {
+   |                              ++++                                ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-self-async.rs:40:9
@@ -85,8 +85,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
-   |                              ++++                ++                 ++
+LL |     async fn box_pin_ref_Self<'a>(self: Box<Pin<&mut Self>>, f: &'a u32) -> &'a u32 {
+   |                              ++++                                ++          ++
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/self/elision/ref-mut-struct-async.stderr b/tests/ui/self/elision/ref-mut-struct-async.stderr
index f8fb2e4a138..149ab01045c 100644
--- a/tests/ui/self/elision/ref-mut-struct-async.stderr
+++ b/tests/ui/self/elision/ref-mut-struct-async.stderr
@@ -10,8 +10,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 {
-   |                        ++++        ++                 ++
+LL |     async fn ref_Struct<'a>(self: &mut Struct, f: &'a u32) -> &'a u32 {
+   |                        ++++                        ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-struct-async.rs:18:9
@@ -25,8 +25,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 {
-   |                            ++++            ++                  ++
+LL |     async fn box_ref_Struct<'a>(self: Box<&mut Struct>, f: &'a u32) -> &'a u32 {
+   |                            ++++                             ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-struct-async.rs:23:9
@@ -40,8 +40,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 {
-   |                            ++++            ++                  ++
+LL |     async fn pin_ref_Struct<'a>(self: Pin<&mut Struct>, f: &'a u32) -> &'a u32 {
+   |                            ++++                             ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-struct-async.rs:28:9
@@ -55,8 +55,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_box_ref_Struct<'a>(self: Box<Box<&'a mut Struct>>, f: &'a u32) -> &u32 {
-   |                                ++++                ++                   ++
+LL |     async fn box_box_ref_Struct<'a>(self: Box<Box<&mut Struct>>, f: &'a u32) -> &'a u32 {
+   |                                ++++                                  ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-mut-struct-async.rs:33:9
@@ -70,8 +70,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 {
-   |                                ++++                ++                   ++
+LL |     async fn box_pin_ref_Struct<'a>(self: Box<Pin<&mut Struct>>, f: &'a u32) -> &'a u32 {
+   |                                ++++                                  ++          ++
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/self/elision/ref-self-async.stderr b/tests/ui/self/elision/ref-self-async.stderr
index 010d281b002..a75ece5f2c7 100644
--- a/tests/ui/self/elision/ref-self-async.stderr
+++ b/tests/ui/self/elision/ref-self-async.stderr
@@ -10,8 +10,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
-   |                      ++++  ++           ++
+LL |     async fn ref_self<'a>(&self, f: &'a u32) -> &'a u32 {
+   |                      ++++            ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:30:9
@@ -25,8 +25,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
-   |                      ++++        ++           ++
+LL |     async fn ref_Self<'a>(self: &Self, f: &'a u32) -> &'a u32 {
+   |                      ++++                  ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:35:9
@@ -40,8 +40,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
-   |                          ++++            ++            ++
+LL |     async fn box_ref_Self<'a>(self: Box<&Self>, f: &'a u32) -> &'a u32 {
+   |                          ++++                       ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:40:9
@@ -55,8 +55,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
-   |                          ++++            ++            ++
+LL |     async fn pin_ref_Self<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 {
+   |                          ++++                       ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:45:9
@@ -70,8 +70,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
-   |                              ++++                ++             ++
+LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&Self>>, f: &'a u32) -> &'a u32 {
+   |                              ++++                            ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:50:9
@@ -85,8 +85,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_pin_ref_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
-   |                              ++++                ++             ++
+LL |     async fn box_pin_ref_Self<'a>(self: Box<Pin<&Self>>, f: &'a u32) -> &'a u32 {
+   |                              ++++                            ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-self-async.rs:55:9
@@ -100,8 +100,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
-   |                                ++++             ++                  ++
+LL |     async fn wrap_ref_Self_Self<'a>(self: Wrap<&Self, Self>, f: &'a u8) -> &'a u8 {
+   |                                ++++                              ++         ++
 
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/self/elision/ref-struct-async.stderr b/tests/ui/self/elision/ref-struct-async.stderr
index c9376d58f90..6bdc145223a 100644
--- a/tests/ui/self/elision/ref-struct-async.stderr
+++ b/tests/ui/self/elision/ref-struct-async.stderr
@@ -10,8 +10,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 {
-   |                        ++++        ++             ++
+LL |     async fn ref_Struct<'a>(self: &Struct, f: &'a u32) -> &'a u32 {
+   |                        ++++                    ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-struct-async.rs:18:9
@@ -25,8 +25,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 {
-   |                            ++++            ++              ++
+LL |     async fn box_ref_Struct<'a>(self: Box<&Struct>, f: &'a u32) -> &'a u32 {
+   |                            ++++                         ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-struct-async.rs:23:9
@@ -40,8 +40,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 {
-   |                            ++++            ++              ++
+LL |     async fn pin_ref_Struct<'a>(self: Pin<&Struct>, f: &'a u32) -> &'a u32 {
+   |                            ++++                         ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-struct-async.rs:28:9
@@ -55,8 +55,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_box_ref_Struct<'a>(self: Box<Box<&'a Struct>>, f: &'a u32) -> &u32 {
-   |                                ++++                ++               ++
+LL |     async fn box_box_ref_Struct<'a>(self: Box<Box<&Struct>>, f: &'a u32) -> &'a u32 {
+   |                                ++++                              ++          ++
 
 error: lifetime may not live long enough
   --> $DIR/ref-struct-async.rs:33:9
@@ -70,8 +70,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 {
-   |                            ++++                ++               ++
+LL |     async fn box_pin_Struct<'a>(self: Box<Pin<&Struct>>, f: &'a u32) -> &'a u32 {
+   |                            ++++                              ++          ++
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
index fc431eb1412..d40e9822435 100644
--- a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
+++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
@@ -2,7 +2,9 @@ error: expected a pattern, found an expression
   --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:31
    |
 LL |     let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
-   |                               ^^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+   |                               ^^^^^^^^^^^^^^^^^^ not a pattern
+   |
+   = note: arbitrary expressions are not allowed in patterns: <https://doc.rust-lang.org/book/ch18-00-patterns.html>
 
 error[E0412]: cannot find type `T` in this scope
   --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:55
diff --git a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr
index 7094ee8c67c..8df76b296ac 100644
--- a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr
+++ b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr
@@ -4,7 +4,7 @@ error: `<i32 as Trait>::Type` is forbidden as the type of a const generic parame
 LL | struct Wrapper<const C: <i32 as Trait>::Type> {}
    |                         ^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: the constant `C` is not of type `<i32 as Trait>::Type`
   --> $DIR/default-proj-ty-as-type-of-const-issue-125757.rs:15:22
diff --git a/tests/ui/traits/missing-for-type-in-impl.e2015.stderr b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr
new file mode 100644
index 00000000000..541b49b024f
--- /dev/null
+++ b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr
@@ -0,0 +1,74 @@
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/missing-for-type-in-impl.rs:8:6
+   |
+LL | impl Foo<i64> {
+   |      ^^^^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: `#[warn(bare_trait_objects)]` on by default
+help: if this is a dyn-compatible trait, use `dyn`
+   |
+LL | impl dyn Foo<i64> {
+   |      +++
+help: you might have intended to implement this trait for a given type
+   |
+LL | impl Foo<i64> for /* Type */ {
+   |               ++++++++++++++
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/missing-for-type-in-impl.rs:8:6
+   |
+LL | impl Foo<i64> {
+   |      ^^^^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: if this is a dyn-compatible trait, use `dyn`
+   |
+LL | impl dyn Foo<i64> {
+   |      +++
+help: you might have intended to implement this trait for a given type
+   |
+LL | impl Foo<i64> for /* Type */ {
+   |               ++++++++++++++
+
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/missing-for-type-in-impl.rs:8:6
+   |
+LL | impl Foo<i64> {
+   |      ^^^^^^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/missing-for-type-in-impl.rs:4:8
+   |
+LL | trait Foo<T> {
+   |       --- this trait cannot be made into an object...
+LL |     fn id(me: T) -> T;
+   |        ^^ ...because associated function `id` has no `self` parameter
+help: consider turning `id` into a method by giving it a `&self` argument
+   |
+LL |     fn id(&self, me: T) -> T;
+   |           ++++++
+help: alternatively, consider constraining `id` so it does not apply to trait objects
+   |
+LL |     fn id(me: T) -> T where Self: Sized;
+   |                       +++++++++++++++++
+
+error[E0277]: the trait bound `i64: Foo<i64>` is not satisfied
+  --> $DIR/missing-for-type-in-impl.rs:19:19
+   |
+LL |     let x: i64 = <i64 as Foo<i64>>::id(10);
+   |                   ^^^ the trait `Foo<i64>` is not implemented for `i64`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/missing-for-type-in-impl.rs:3:1
+   |
+LL | trait Foo<T> {
+   | ^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 2 warnings emitted
+
+Some errors have detailed explanations: E0038, E0277.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/traits/missing-for-type-in-impl.e2021.stderr b/tests/ui/traits/missing-for-type-in-impl.e2021.stderr
new file mode 100644
index 00000000000..b5a607a54cb
--- /dev/null
+++ b/tests/ui/traits/missing-for-type-in-impl.e2021.stderr
@@ -0,0 +1,31 @@
+error[E0277]: the trait bound `i64: Foo<i64>` is not satisfied
+  --> $DIR/missing-for-type-in-impl.rs:19:19
+   |
+LL |     let x: i64 = <i64 as Foo<i64>>::id(10);
+   |                   ^^^ the trait `Foo<i64>` is not implemented for `i64`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/missing-for-type-in-impl.rs:3:1
+   |
+LL | trait Foo<T> {
+   | ^^^^^^^^^^^^
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/missing-for-type-in-impl.rs:8:6
+   |
+LL | impl Foo<i64> {
+   |      ^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL | impl dyn Foo<i64> {
+   |      +++
+help: you might have intended to implement this trait for a given type
+   |
+LL | impl Foo<i64> for /* Type */ {
+   |               ++++++++++++++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0782.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/missing-for-type-in-impl.rs b/tests/ui/traits/missing-for-type-in-impl.rs
new file mode 100644
index 00000000000..7d4ad479e77
--- /dev/null
+++ b/tests/ui/traits/missing-for-type-in-impl.rs
@@ -0,0 +1,22 @@
+//@revisions: e2021 e2015
+//@[e2021]edition: 2021
+trait Foo<T> {
+    fn id(me: T) -> T;
+}
+
+/* note the "missing" for ... (in this case for i64, in order for this to compile) */
+impl Foo<i64> {
+//[e2021]~^ ERROR trait objects must include the `dyn` keyword
+//[e2015]~^^ WARNING trait objects without an explicit `dyn` are deprecated
+//[e2015]~| WARNING trait objects without an explicit `dyn` are deprecated
+//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+//[e2015]~| ERROR the trait `Foo` cannot be made into an object
+    fn id(me: i64) -> i64 {me}
+}
+
+fn main() {
+    let x: i64 = <i64 as Foo<i64>>::id(10);
+    //~^ ERROR the trait bound `i64: Foo<i64>` is not satisfied
+    println!("{}", x);
+}
diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
index e0cbee88aa1..377dfc8b529 100644
--- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
+++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
@@ -10,7 +10,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | struct X<const FN: fn() = { || {} }>;
    |                    ^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: using function pointers as const generic parameters is forbidden
   --> $DIR/const-region-infer-to-static-in-binder.rs:4:20
@@ -18,7 +18,7 @@ error: using function pointers as const generic parameters is forbidden
 LL | struct X<const FN: fn() = { || {} }>;
    |                    ^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/traits/next-solver/overflow/coherence-alias-hang-with-region.rs b/tests/ui/traits/next-solver/overflow/coherence-alias-hang-with-region.rs
new file mode 100644
index 00000000000..4ade8a13ca9
--- /dev/null
+++ b/tests/ui/traits/next-solver/overflow/coherence-alias-hang-with-region.rs
@@ -0,0 +1,30 @@
+//@ check-pass
+//@ revisions: ai ia ii
+//@ compile-flags: -Znext-solver=coherence
+
+// Regression test for nalgebra hang <https://github.com/rust-lang/rust/issues/130056>.
+
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+type Id<T: ?Sized> = T;
+trait NotImplemented {}
+
+struct W<'a, T: ?Sized, U: ?Sized>(&'a (), *const T, *const U);
+trait Trait {
+    type Assoc: ?Sized;
+}
+impl<'a, T: ?Sized + Trait> Trait for W<'a, T, T> {
+    #[cfg(ai)]
+    type Assoc = W<'a, T::Assoc, Id<T::Assoc>>;
+    #[cfg(ia)]
+    type Assoc = W<'a, Id<T::Assoc>, T::Assoc>;
+    #[cfg(ii)]
+    type Assoc = W<'a, Id<T::Assoc>, Id<T::Assoc>>;
+}
+
+trait Overlap<T: ?Sized> {}
+impl<'a, T: ?Sized> Overlap<T> for W<'a, T, T> {}
+impl<T: ?Sized + Trait + NotImplemented> Overlap<T::Assoc> for T {}
+
+fn main() {}
diff --git a/tests/ui/traits/coherence-alias-hang.rs b/tests/ui/traits/next-solver/overflow/coherence-alias-hang.rs
index c2b4d2e42d2..0d5f42231e4 100644
--- a/tests/ui/traits/coherence-alias-hang.rs
+++ b/tests/ui/traits/next-solver/overflow/coherence-alias-hang.rs
@@ -1,6 +1,8 @@
 //@ check-pass
-//@ revisions: current next
-//[next]@ compile-flags: -Znext-solver
+//@ revisions: ai_current ai_next ia_current ia_next ii_current ii_next
+//@[ai_next] compile-flags: -Znext-solver
+//@[ia_next] compile-flags: -Znext-solver
+//@[ii_next] compile-flags: -Znext-solver
 
 // Regression test for nalgebra hang <https://github.com/rust-lang/rust/issues/130056>.
 
@@ -15,7 +17,12 @@ trait Trait {
     type Assoc: ?Sized;
 }
 impl<T: ?Sized + Trait> Trait for W<T, T> {
+    #[cfg(any(ai_current, ai_next))]
     type Assoc = W<T::Assoc, Id<T::Assoc>>;
+    #[cfg(any(ia_current, ia_next))]
+    type Assoc = W<Id<T::Assoc>, T::Assoc>;
+    #[cfg(any(ii_current, ii_next))]
+    type Assoc = W<Id<T::Assoc>, Id<T::Assoc>>;
 }
 
 trait Overlap<T: ?Sized> {}
diff --git a/tests/ui/traits/next-solver/overflow/nalgebra-hang.rs b/tests/ui/traits/next-solver/overflow/nalgebra-hang.rs
new file mode 100644
index 00000000000..4bc6039c57d
--- /dev/null
+++ b/tests/ui/traits/next-solver/overflow/nalgebra-hang.rs
@@ -0,0 +1,35 @@
+//@ check-pass
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+
+// Regression test for nalgebra hang from
+//     https://github.com/rust-lang/rust/pull/130654#issuecomment-2365465354
+trait HasAlias {}
+
+struct Dummy;
+trait DummyTrait {
+    type DummyType<T: HasAlias>;
+}
+impl DummyTrait for Dummy {
+    type DummyType<T: HasAlias> = T;
+}
+type AliasOf<T> = <Dummy as DummyTrait>::DummyType<T>;
+
+struct Matrix<T, S>(T, S);
+type OMatrix<T> = Matrix<T, AliasOf<T>>;
+
+impl<T: HasAlias> HasAlias for OMatrix<T> {}
+
+trait SimdValue {
+    type Element;
+}
+impl<T: HasAlias + SimdValue<Element: HasAlias>> SimdValue for OMatrix<T> {
+    type Element = OMatrix<T::Element>;
+}
+
+trait Unimplemented {}
+pub trait MyFrom<T> {}
+impl<T: Unimplemented> MyFrom<T> for T {}
+impl<T: SimdValue<Element: HasAlias>> MyFrom<T> for OMatrix<T::Element> {}
+
+fn main() {}
diff --git a/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.rs b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.rs
new file mode 100644
index 00000000000..b174776c596
--- /dev/null
+++ b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.rs
@@ -0,0 +1,24 @@
+// Make sure that when elaborating the principal of a dyn trait for projection predicates
+//  we don't end up in a situation where we have an unconstrained late-bound lifetime in
+// the output of a projection.
+
+// Fix for <https://github.com/rust-lang/rust/issues/130347>.
+
+trait A<T>: B<T = T> {}
+
+trait B {
+    type T;
+}
+
+struct Erase<T: ?Sized + B>(T::T);
+
+fn main() {
+    let x = {
+        let x = String::from("hello");
+
+        Erase::<dyn for<'a> A<&'a _>>(x.as_str())
+        //~^ ERROR binding for associated type `T` references lifetime `'a`, which does not appear in the trait input types
+    };
+
+    dbg!(x.0);
+}
diff --git a/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr
new file mode 100644
index 00000000000..067eaf5e7f3
--- /dev/null
+++ b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr
@@ -0,0 +1,12 @@
+error[E0582]: binding for associated type `T` references lifetime `'a`, which does not appear in the trait input types
+  --> $DIR/elaborated-predicates-unconstrained-late-bound.rs:19:21
+   |
+LL | trait A<T>: B<T = T> {}
+   |               ----- due to this supertrait
+...
+LL |         Erase::<dyn for<'a> A<&'a _>>(x.as_str())
+   |                     ^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0582`.
diff --git a/tests/ui/traits/object/pretty.rs b/tests/ui/traits/object/pretty.rs
index 6660ff040f7..603d7af5260 100644
--- a/tests/ui/traits/object/pretty.rs
+++ b/tests/ui/traits/object/pretty.rs
@@ -13,7 +13,7 @@ trait SuperGeneric<'a> {
 }
 trait AnyGeneric<'a>: SuperGeneric<'a> {}
 trait FixedGeneric1<'a>: SuperGeneric<'a, Assoc2 = &'a u8> {}
-trait FixedGeneric2<'a>: Super<Assoc = &'a u8> {}
+// trait FixedGeneric2<'a>: Super<Assoc = &'a u8> {} // Unsound!
 trait FixedHrtb: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> {}
 trait AnyDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super {}
 trait FixedDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super<Assoc = u8> {}
@@ -32,7 +32,7 @@ fn dyn_fixed_static(x: &dyn FixedStatic) { x } //~ERROR mismatched types
 fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x } //~ERROR mismatched types
 fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x } //~ERROR mismatched types
 fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } //~ERROR mismatched types
-fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } //~ERROR mismatched types
+// fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } // Unsound!
 fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x } //~ERROR mismatched types
 fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x } //~ERROR mismatched types
 fn dyn_any_different_binders(x: &dyn AnyDifferentBinders<Assoc = u8>) { x } //~ERROR mismatched types
diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr
index ca56bdbb67a..af941e69c5f 100644
--- a/tests/ui/traits/object/pretty.stderr
+++ b/tests/ui/traits/object/pretty.stderr
@@ -107,17 +107,6 @@ LL | fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x }
               found reference `&dyn for<'a> FixedGeneric1<'a>`
 
 error[E0308]: mismatched types
-  --> $DIR/pretty.rs:35:60
-   |
-LL | fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x }
-   |                                                         -  ^ expected `()`, found `&dyn FixedGeneric2<'a>`
-   |                                                         |
-   |                                                         help: try adding a return type: `-> &dyn for<'a> FixedGeneric2<'a>`
-   |
-   = note: expected unit type `()`
-              found reference `&dyn for<'a> FixedGeneric2<'a>`
-
-error[E0308]: mismatched types
   --> $DIR/pretty.rs:36:79
    |
 LL | fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x }
@@ -172,6 +161,6 @@ LL | fn dyn_has_gat(x: &dyn HasGat<u8, Assoc<bool> = ()>) { x }
    = note: expected unit type `()`
               found reference `&dyn HasGat<u8, Assoc<bool> = ()>`
 
-error: aborting due to 15 previous errors; 1 warning emitted
+error: aborting due to 14 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs
index 7f793e1269f..c4c070e49fd 100644
--- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs
+++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs
@@ -1,21 +1,22 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
-//@ check-pass
+//@ build-pass
 
-// We should be able to instantiate a binder during trait upcasting.
-// This test could be `check-pass`, but we should make sure that we
-// do so in both trait solvers.
+// Check that we are able to instantiate a binder during trait upcasting,
+// and that it doesn't cause any issues with codegen either.
 
 #![feature(trait_upcasting)]
 
 trait Supertrait<'a, 'b> {}
 trait Subtrait<'a, 'b>: Supertrait<'a, 'b> {}
 
-impl<'a> Supertrait<'a, 'a> for () {}
-impl<'a> Subtrait<'a, 'a> for () {}
+impl Supertrait<'_, '_> for () {}
+impl Subtrait<'_, '_> for () {}
 fn ok(x: &dyn for<'a, 'b> Subtrait<'a, 'b>) -> &dyn for<'a> Supertrait<'a, 'a> {
     x
 }
 
-fn main() {}
+fn main() {
+    ok(&());
+}
diff --git a/tests/ui/transmutability/assoc-bound.rs b/tests/ui/transmutability/assoc-bound.rs
new file mode 100644
index 00000000000..e8a20b45cde
--- /dev/null
+++ b/tests/ui/transmutability/assoc-bound.rs
@@ -0,0 +1,25 @@
+#![crate_type = "lib"]
+#![feature(transmutability)]
+
+trait A {
+    type AssocA;
+}
+
+trait B {
+    type AssocB: std::mem::TransmuteFrom<()>;
+}
+
+impl<T> B for (T, u8)
+where
+    T: A,
+{
+    type AssocB = T::AssocA; //~ERROR: the trait bound `<T as A>::AssocA: TransmuteFrom<(), Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not satisfied [E0277]
+}
+
+
+impl<T> B for (T, u16)
+where
+    for<'a> &'a i32: A,
+{
+    type AssocB = <&'static i32 as A>::AssocA; //~ERROR: `()` cannot be safely transmuted into `<&i32 as A>::AssocA`
+}
diff --git a/tests/ui/transmutability/assoc-bound.stderr b/tests/ui/transmutability/assoc-bound.stderr
new file mode 100644
index 00000000000..08d90894396
--- /dev/null
+++ b/tests/ui/transmutability/assoc-bound.stderr
@@ -0,0 +1,31 @@
+error[E0277]: the trait bound `<T as A>::AssocA: TransmuteFrom<(), Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not satisfied
+  --> $DIR/assoc-bound.rs:16:19
+   |
+LL |     type AssocB = T::AssocA;
+   |                   ^^^^^^^^^ the trait `TransmuteFrom<(), Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `<T as A>::AssocA`
+   |
+note: required by a bound in `B::AssocB`
+  --> $DIR/assoc-bound.rs:9:18
+   |
+LL |     type AssocB: std::mem::TransmuteFrom<()>;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `B::AssocB`
+help: consider further restricting the associated type
+   |
+LL |     T: A, <T as A>::AssocA: TransmuteFrom<(), Assume { alignment: false, lifetimes: false, safety: false, validity: false }>
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0277]: `()` cannot be safely transmuted into `<&i32 as A>::AssocA`
+  --> $DIR/assoc-bound.rs:24:19
+   |
+LL |     type AssocB = <&'static i32 as A>::AssocA;
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<&i32 as A>::AssocA` has an unknown layout
+   |
+note: required by a bound in `B::AssocB`
+  --> $DIR/assoc-bound.rs:9:18
+   |
+LL |     type AssocB: std::mem::TransmuteFrom<()>;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `B::AssocB`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/try-trait/bad-interconversion.rs b/tests/ui/try-trait/bad-interconversion.rs
index 385f5510fb4..9c45bde8898 100644
--- a/tests/ui/try-trait/bad-interconversion.rs
+++ b/tests/ui/try-trait/bad-interconversion.rs
@@ -1,5 +1,3 @@
-#![feature(control_flow_enum)]
-
 use std::ops::ControlFlow;
 
 fn result_to_result() -> Result<u64, u8> {
diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr
index 9aab2cf6ab8..82877baef3e 100644
--- a/tests/ui/try-trait/bad-interconversion.stderr
+++ b/tests/ui/try-trait/bad-interconversion.stderr
@@ -1,5 +1,5 @@
 error[E0277]: `?` couldn't convert the error to `u8`
-  --> $DIR/bad-interconversion.rs:6:20
+  --> $DIR/bad-interconversion.rs:4:20
    |
 LL | fn result_to_result() -> Result<u64, u8> {
    |                          --------------- expected `u8` because of this
@@ -15,7 +15,7 @@ LL |     Ok(Err(123_i32)?)
    = note: required for `Result<u64, u8>` to implement `FromResidual<Result<Infallible, i32>>`
 
 error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
-  --> $DIR/bad-interconversion.rs:11:12
+  --> $DIR/bad-interconversion.rs:9:12
    |
 LL | fn option_to_result() -> Result<u64, String> {
    | -------------------------------------------- this function returns a `Result`
@@ -26,7 +26,7 @@ LL |     Some(3)?;
    = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
 
 error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result`
-  --> $DIR/bad-interconversion.rs:17:31
+  --> $DIR/bad-interconversion.rs:15:31
    |
 LL | fn control_flow_to_result() -> Result<u64, String> {
    | -------------------------------------------------- this function returns a `Result`
@@ -37,7 +37,7 @@ LL |     Ok(ControlFlow::Break(123)?)
    = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
 
 error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
-  --> $DIR/bad-interconversion.rs:22:22
+  --> $DIR/bad-interconversion.rs:20:22
    |
 LL | fn result_to_option() -> Option<u16> {
    | ------------------------------------ this function returns an `Option`
@@ -48,7 +48,7 @@ LL |     Some(Err("hello")?)
    = help: the trait `FromResidual<Option<Infallible>>` is implemented for `Option<T>`
 
 error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option`
-  --> $DIR/bad-interconversion.rs:27:33
+  --> $DIR/bad-interconversion.rs:25:33
    |
 LL | fn control_flow_to_option() -> Option<u64> {
    | ------------------------------------------ this function returns an `Option`
@@ -59,7 +59,7 @@ LL |     Some(ControlFlow::Break(123)?)
    = help: the trait `FromResidual<Option<Infallible>>` is implemented for `Option<T>`
 
 error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
-  --> $DIR/bad-interconversion.rs:32:39
+  --> $DIR/bad-interconversion.rs:30:39
    |
 LL | fn result_to_control_flow() -> ControlFlow<String> {
    | -------------------------------------------------- this function returns a `ControlFlow`
@@ -71,7 +71,7 @@ LL |     ControlFlow::Continue(Err("hello")?)
    = help: for that trait implementation, expected `ControlFlow<String, Infallible>`, found `Result<Infallible, &str>`
 
 error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
-  --> $DIR/bad-interconversion.rs:37:12
+  --> $DIR/bad-interconversion.rs:35:12
    |
 LL | fn option_to_control_flow() -> ControlFlow<u64> {
    | ----------------------------------------------- this function returns a `ControlFlow`
@@ -83,7 +83,7 @@ LL |     Some(3)?;
    = help: for that trait implementation, expected `ControlFlow<u64, Infallible>`, found `Option<Infallible>`
 
 error[E0277]: the `?` operator in a function that returns `ControlFlow<B, _>` can only be used on other `ControlFlow<B, _>`s (with the same Break type)
-  --> $DIR/bad-interconversion.rs:43:29
+  --> $DIR/bad-interconversion.rs:41:29
    |
 LL | fn control_flow_to_control_flow() -> ControlFlow<i64> {
    | ----------------------------------------------------- this function returns a `ControlFlow`
diff --git a/tests/ui/try-trait/try-operator-custom.rs b/tests/ui/try-trait/try-operator-custom.rs
index 936c0b0689a..ebeb0869f98 100644
--- a/tests/ui/try-trait/try-operator-custom.rs
+++ b/tests/ui/try-trait/try-operator-custom.rs
@@ -1,6 +1,5 @@
 //@ run-pass
 
-#![feature(control_flow_enum)]
 #![feature(try_trait_v2)]
 
 use std::ops::{ControlFlow, FromResidual, Try};
diff --git a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs
new file mode 100644
index 00000000000..df589473a84
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs
@@ -0,0 +1,18 @@
+#![feature(type_alias_impl_trait)]
+
+trait Captures<'a> {}
+impl<T> Captures<'_> for T {}
+
+fn dyn_hoops<T: Sized>() -> dyn for<'a> Iterator<Item = impl Captures<'a>> {
+    //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
+    loop {}
+}
+
+pub fn main() {
+    //~^ ERROR item does not constrain `Opaque::{opaque#0}`, but has it in its signature
+    type Opaque = impl Sized;
+    fn define() -> Opaque {
+        let x: Opaque = dyn_hoops::<()>();
+        x
+    }
+}
diff --git a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr
new file mode 100644
index 00000000000..59d9ff86c6e
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr
@@ -0,0 +1,28 @@
+error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
+  --> $DIR/bound-lifetime-through-dyn-trait.rs:6:71
+   |
+LL | fn dyn_hoops<T: Sized>() -> dyn for<'a> Iterator<Item = impl Captures<'a>> {
+   |                                                                       ^^
+   |
+note: lifetime declared here
+  --> $DIR/bound-lifetime-through-dyn-trait.rs:6:37
+   |
+LL | fn dyn_hoops<T: Sized>() -> dyn for<'a> Iterator<Item = impl Captures<'a>> {
+   |                                     ^^
+
+error: item does not constrain `Opaque::{opaque#0}`, but has it in its signature
+  --> $DIR/bound-lifetime-through-dyn-trait.rs:11:8
+   |
+LL | pub fn main() {
+   |        ^^^^
+   |
+   = note: consider moving the opaque type's declaration and defining uses into a separate module
+note: this opaque type is in the signature
+  --> $DIR/bound-lifetime-through-dyn-trait.rs:13:19
+   |
+LL |     type Opaque = impl Sized;
+   |                   ^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0657`.
diff --git a/tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr b/tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr
index 3b6999cabc4..b7999a695e7 100644
--- a/tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr
+++ b/tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr
@@ -4,7 +4,7 @@ error: `Bar` is forbidden as the type of a const generic parameter
 LL | async fn test<const N: crate::Bar>() {
    |                        ^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr b/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr
index 55a5a3d2000..ec8a51b0818 100644
--- a/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr
+++ b/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr
@@ -1,3 +1,11 @@
+error: `Bar` is forbidden as the type of a const generic parameter
+  --> $DIR/const_generic_type.rs:8:24
+   |
+LL | async fn test<const N: crate::Bar>() {
+   |                        ^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool`, and `char`
+
 error: item does not constrain `Bar::{opaque#0}`, but has it in its signature
   --> $DIR/const_generic_type.rs:8:10
    |
@@ -39,13 +47,5 @@ LL | type Bar = impl std::fmt::Display;
    |
    = note: `Bar` must be used in combination with a concrete type within the same module
 
-error: `Bar` is forbidden as the type of a const generic parameter
-  --> $DIR/const_generic_type.rs:8:24
-   |
-LL | async fn test<const N: crate::Bar>() {
-   |                        ^^^^^^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/type-alias-impl-trait/constrain_inputs.stderr b/tests/ui/type-alias-impl-trait/constrain_inputs.stderr
index 2468fb7480b..436326e66c3 100644
--- a/tests/ui/type-alias-impl-trait/constrain_inputs.stderr
+++ b/tests/ui/type-alias-impl-trait/constrain_inputs.stderr
@@ -7,19 +7,6 @@ LL |     fn execute(ty: Ty<'_>) -> &str { todo!() }
    = note: lifetimes appearing in an associated or opaque type are not considered constrained
    = note: consider introducing a named lifetime parameter
 
-error: item does not constrain `lifetime_params::Ty::{opaque#0}`, but has it in its signature
-  --> $DIR/constrain_inputs.rs:6:8
-   |
-LL |     fn execute(ty: Ty<'_>) -> &str { todo!() }
-   |        ^^^^^^^
-   |
-   = note: consider moving the opaque type's declaration and defining uses into a separate module
-note: this opaque type is in the signature
-  --> $DIR/constrain_inputs.rs:4:19
-   |
-LL |     type Ty<'a> = impl Sized;
-   |                   ^^^^^^^^^^
-
 error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types
   --> $DIR/constrain_inputs.rs:10:35
    |
@@ -38,6 +25,19 @@ LL |     type BadTraitRef = dyn Fn(Ty<'_>) -> &str;
    = note: lifetimes appearing in an associated or opaque type are not considered constrained
    = note: consider introducing a named lifetime parameter
 
+error: item does not constrain `lifetime_params::Ty::{opaque#0}`, but has it in its signature
+  --> $DIR/constrain_inputs.rs:6:8
+   |
+LL |     fn execute(ty: Ty<'_>) -> &str { todo!() }
+   |        ^^^^^^^
+   |
+   = note: consider moving the opaque type's declaration and defining uses into a separate module
+note: this opaque type is in the signature
+  --> $DIR/constrain_inputs.rs:4:19
+   |
+LL |     type Ty<'a> = impl Sized;
+   |                   ^^^^^^^^^^
+
 error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types
   --> $DIR/constrain_inputs.rs:19:31
    |
diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr
index be9b07823ae..88529b370f1 100644
--- a/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr
@@ -1,13 +1,8 @@
 error[E0277]: the trait bound `T: Trait` is not satisfied
-  --> $DIR/generic_underconstrained.rs:9:51
+  --> $DIR/generic_underconstrained.rs:9:31
    |
-LL |   fn underconstrain<T>(_: T) -> Underconstrained<T> {
-   |  ___________________________________________________^
-LL | |
-LL | |
-LL | |     unimplemented!()
-LL | | }
-   | |_^ the trait `Trait` is not implemented for `T`
+LL | fn underconstrain<T>(_: T) -> Underconstrained<T> {
+   |                               ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
    |
 note: required by a bound on the type alias `Underconstrained`
   --> $DIR/generic_underconstrained.rs:6:26
@@ -20,10 +15,15 @@ LL | fn underconstrain<T: Trait>(_: T) -> Underconstrained<T> {
    |                    +++++++
 
 error[E0277]: the trait bound `T: Trait` is not satisfied
-  --> $DIR/generic_underconstrained.rs:9:31
+  --> $DIR/generic_underconstrained.rs:9:51
    |
-LL | fn underconstrain<T>(_: T) -> Underconstrained<T> {
-   |                               ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
+LL |   fn underconstrain<T>(_: T) -> Underconstrained<T> {
+   |  ___________________________________________________^
+LL | |
+LL | |
+LL | |     unimplemented!()
+LL | | }
+   | |_^ the trait `Trait` is not implemented for `T`
    |
 note: required by a bound on the type alias `Underconstrained`
   --> $DIR/generic_underconstrained.rs:6:26
diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr
index 15d96191ba9..b3b9cbca968 100644
--- a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr
@@ -1,13 +1,8 @@
 error[E0277]: `U` doesn't implement `Debug`
-  --> $DIR/generic_underconstrained2.rs:8:53
+  --> $DIR/generic_underconstrained2.rs:8:33
    |
-LL |   fn underconstrained<U>(_: U) -> Underconstrained<U> {
-   |  _____________________________________________________^
-LL | |
-LL | |
-LL | |     5u32
-LL | | }
-   | |_^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+LL | fn underconstrained<U>(_: U) -> Underconstrained<U> {
+   |                                 ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
 note: required by a bound on the type alias `Underconstrained`
   --> $DIR/generic_underconstrained2.rs:5:26
@@ -20,15 +15,10 @@ LL | fn underconstrained<U: std::fmt::Debug>(_: U) -> Underconstrained<U> {
    |                      +++++++++++++++++
 
 error[E0277]: `V` doesn't implement `Debug`
-  --> $DIR/generic_underconstrained2.rs:17:64
+  --> $DIR/generic_underconstrained2.rs:17:43
    |
-LL |   fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
-   |  ________________________________________________________________^
-LL | |
-LL | |
-LL | |     5u32
-LL | | }
-   | |_^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+LL | fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
+   |                                           ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
 note: required by a bound on the type alias `Underconstrained2`
   --> $DIR/generic_underconstrained2.rs:14:27
@@ -41,10 +31,15 @@ LL | fn underconstrained2<U, V: std::fmt::Debug>(_: U, _: V) -> Underconstrained
    |                          +++++++++++++++++
 
 error[E0277]: `U` doesn't implement `Debug`
-  --> $DIR/generic_underconstrained2.rs:8:33
+  --> $DIR/generic_underconstrained2.rs:8:53
    |
-LL | fn underconstrained<U>(_: U) -> Underconstrained<U> {
-   |                                 ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+LL |   fn underconstrained<U>(_: U) -> Underconstrained<U> {
+   |  _____________________________________________________^
+LL | |
+LL | |
+LL | |     5u32
+LL | | }
+   | |_^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
 note: required by a bound on the type alias `Underconstrained`
   --> $DIR/generic_underconstrained2.rs:5:26
@@ -57,10 +52,15 @@ LL | fn underconstrained<U: std::fmt::Debug>(_: U) -> Underconstrained<U> {
    |                      +++++++++++++++++
 
 error[E0277]: `V` doesn't implement `Debug`
-  --> $DIR/generic_underconstrained2.rs:17:43
+  --> $DIR/generic_underconstrained2.rs:17:64
    |
-LL | fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
-   |                                           ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+LL |   fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
+   |  ________________________________________________________________^
+LL | |
+LL | |
+LL | |     5u32
+LL | | }
+   | |_^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
 note: required by a bound on the type alias `Underconstrained2`
   --> $DIR/generic_underconstrained2.rs:14:27
diff --git a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr
index 22c776e171c..eace96317dc 100644
--- a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr
+++ b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr
@@ -1,3 +1,9 @@
+error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/ice-failed-to-resolve-instance-for-110696.rs:41:6
+   |
+LL | impl<T: MyFrom<Phantom2<DummyT<U>>>, U> MyIndex<DummyT<T>> for Scope<U> {
+   |      ^ unconstrained type parameter
+
 error: item does not constrain `DummyT::{opaque#0}`, but has it in its signature
   --> $DIR/ice-failed-to-resolve-instance-for-110696.rs:28:8
    |
@@ -24,12 +30,6 @@ note: this opaque type is in the signature
 LL | type DummyT<T> = impl F;
    |                  ^^^^^^
 
-error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/ice-failed-to-resolve-instance-for-110696.rs:41:6
-   |
-LL | impl<T: MyFrom<Phantom2<DummyT<U>>>, U> MyIndex<DummyT<T>> for Scope<U> {
-   |      ^ unconstrained type parameter
-
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.stderr b/tests/ui/type-alias-impl-trait/in-where-clause.stderr
index f1361b47c56..5ac09e20b02 100644
--- a/tests/ui/type-alias-impl-trait/in-where-clause.stderr
+++ b/tests/ui/type-alias-impl-trait/in-where-clause.stderr
@@ -1,14 +1,25 @@
-error[E0391]: cycle detected when computing type of `Bar::{opaque#0}`
-  --> $DIR/in-where-clause.rs:5:12
+error[E0283]: type annotations needed: cannot satisfy `Bar: Send`
+  --> $DIR/in-where-clause.rs:12:9
    |
-LL | type Bar = impl Sized;
-   |            ^^^^^^^^^^
+LL |     [0; 1 + 2]
+   |         ^^^^^
    |
-note: ...which requires computing type of opaque `Bar::{opaque#0}`...
+   = note: cannot satisfy `Bar: Send`
+note: required by a bound in `foo`
+  --> $DIR/in-where-clause.rs:10:10
+   |
+LL | fn foo() -> Bar
+   |    --- required by a bound in this function
+LL | where
+LL |     Bar: Send,
+   |          ^^^^ required by this bound in `foo`
+
+error[E0391]: cycle detected when computing type of opaque `Bar::{opaque#0}`
   --> $DIR/in-where-clause.rs:5:12
    |
 LL | type Bar = impl Sized;
    |            ^^^^^^^^^^
+   |
 note: ...which requires type-checking `foo`...
   --> $DIR/in-where-clause.rs:8:1
    |
@@ -17,30 +28,15 @@ LL | | where
 LL | |     Bar: Send,
    | |______________^
    = note: ...which requires revealing opaque types in `[Binder { value: TraitPredicate(<Bar as core::marker::Send>, polarity:Positive), bound_vars: [] }]`...
-   = note: ...which again requires computing type of `Bar::{opaque#0}`, completing the cycle
-note: cycle used when checking that `Bar::{opaque#0}` is well-formed
+note: ...which requires computing type of `Bar::{opaque#0}`...
   --> $DIR/in-where-clause.rs:5:12
    |
 LL | type Bar = impl Sized;
    |            ^^^^^^^^^^
+   = note: ...which again requires computing type of opaque `Bar::{opaque#0}`, completing the cycle
+   = note: cycle used when evaluating trait selection obligation `Bar: core::marker::Send`
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
-error[E0283]: type annotations needed: cannot satisfy `Bar: Send`
-  --> $DIR/in-where-clause.rs:12:9
-   |
-LL |     [0; 1 + 2]
-   |         ^^^^^
-   |
-   = note: cannot satisfy `Bar: Send`
-note: required by a bound in `foo`
-  --> $DIR/in-where-clause.rs:10:10
-   |
-LL | fn foo() -> Bar
-   |    --- required by a bound in this function
-LL | where
-LL |     Bar: Send,
-   |          ^^^^ required by this bound in `foo`
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0283, E0391.
diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.rs b/tests/ui/type-alias-impl-trait/issue-53092-2.rs
index 2adfad4fc5b..2383008d042 100644
--- a/tests/ui/type-alias-impl-trait/issue-53092-2.rs
+++ b/tests/ui/type-alias-impl-trait/issue-53092-2.rs
@@ -1,15 +1,14 @@
 #![feature(type_alias_impl_trait)]
 #![allow(dead_code)]
 
-type Bug<T, U> = impl Fn(T) -> U + Copy; //~ ERROR cycle detected
+type Bug<T, U> = impl Fn(T) -> U + Copy;
 
 const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
-//~^ ERROR: non-defining opaque type use
-//~| ERROR: item does not constrain
-//~| ERROR: item does not constrain
+//~^ ERROR cycle detected
+//~| ERROR: non-defining opaque type use
 
 fn make_bug<T, U: From<T>>() -> Bug<T, U> {
-    |x| x.into() //~ ERROR the trait bound `U: From<T>` is not satisfied
+    |x| x.into()
 }
 
 fn main() {
diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr
index 121f765e667..ac580866704 100644
--- a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr
@@ -10,75 +10,33 @@ note: for this opaque type
 LL | type Bug<T, U> = impl Fn(T) -> U + Copy;
    |                  ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0391]: cycle detected when computing type of `Bug::{opaque#0}`
-  --> $DIR/issue-53092-2.rs:4:18
-   |
-LL | type Bug<T, U> = impl Fn(T) -> U + Copy;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires computing type of opaque `Bug::{opaque#0}`...
-  --> $DIR/issue-53092-2.rs:4:18
-   |
-LL | type Bug<T, U> = impl Fn(T) -> U + Copy;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires type-checking `CONST_BUG`...
+error[E0391]: cycle detected when type-checking `CONST_BUG`
   --> $DIR/issue-53092-2.rs:6:1
    |
 LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
    = note: ...which requires computing layout of `Bug<u8, ()>`...
    = note: ...which requires normalizing `Bug<u8, ()>`...
-   = note: ...which again requires computing type of `Bug::{opaque#0}`, completing the cycle
-note: cycle used when checking that `Bug::{opaque#0}` is well-formed
+note: ...which requires computing type of `Bug::{opaque#0}`...
   --> $DIR/issue-53092-2.rs:4:18
    |
 LL | type Bug<T, U> = impl Fn(T) -> U + Copy;
    |                  ^^^^^^^^^^^^^^^^^^^^^^
-   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-
-error: item does not constrain `Bug::{opaque#0}`, but has it in its signature
-  --> $DIR/issue-53092-2.rs:6:7
-   |
-LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
-   |       ^^^^^^^^^
-   |
-   = note: consider moving the opaque type's declaration and defining uses into a separate module
-note: this opaque type is in the signature
+note: ...which requires computing type of opaque `Bug::{opaque#0}`...
   --> $DIR/issue-53092-2.rs:4:18
    |
 LL | type Bug<T, U> = impl Fn(T) -> U + Copy;
    |                  ^^^^^^^^^^^^^^^^^^^^^^
-
-error: item does not constrain `Bug::{opaque#0}`, but has it in its signature
-  --> $DIR/issue-53092-2.rs:6:61
+   = note: ...which again requires type-checking `CONST_BUG`, completing the cycle
+note: cycle used when checking that `CONST_BUG` is well-formed
+  --> $DIR/issue-53092-2.rs:6:1
    |
 LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
-   |                                                             ^^^^^^^
-   |
-   = note: consider moving the opaque type's declaration and defining uses into a separate module
-note: this opaque type is in the signature
-  --> $DIR/issue-53092-2.rs:4:18
-   |
-LL | type Bug<T, U> = impl Fn(T) -> U + Copy;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `U: From<T>` is not satisfied
-  --> $DIR/issue-53092-2.rs:12:5
-   |
-LL |     |x| x.into()
-   |     ^^^^^^^^^^^^ the trait `From<T>` is not implemented for `U`
-   |
-note: required by a bound in `make_bug`
-  --> $DIR/issue-53092-2.rs:11:19
-   |
-LL | fn make_bug<T, U: From<T>>() -> Bug<T, U> {
-   |                   ^^^^^^^ required by this bound in `make_bug`
-help: consider restricting type parameter `U`
-   |
-LL | type Bug<T, U: std::convert::From<T>> = impl Fn(T) -> U + Copy;
-   |              +++++++++++++++++++++++
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0277, E0391, E0792.
-For more information about an error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0391, E0792.
+For more information about an error, try `rustc --explain E0391`.
diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.current.stderr b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.current.stderr
index 2b064dcfc31..ec7b9e0e12b 100644
--- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.current.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.current.stderr
@@ -1,3 +1,12 @@
+error[E0119]: conflicting implementations of trait `Trait<Bar, _>`
+  --> $DIR/issue-84660-unsoundness.rs:29:1
+   |
+LL | impl<In, Out> Trait<Bar, In> for Out {
+   | ------------------------------------ first implementation here
+...
+LL | impl<In, Out> Trait<(), In> for Out {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
+
 error: item does not constrain `Bar::{opaque#0}`, but has it in its signature
   --> $DIR/issue-84660-unsoundness.rs:22:8
    |
@@ -11,15 +20,6 @@ note: this opaque type is in the signature
 LL | type Bar = impl Foo;
    |            ^^^^^^^^
 
-error[E0119]: conflicting implementations of trait `Trait<Bar, _>`
-  --> $DIR/issue-84660-unsoundness.rs:29:1
-   |
-LL | impl<In, Out> Trait<Bar, In> for Out {
-   | ------------------------------------ first implementation here
-...
-LL | impl<In, Out> Trait<(), In> for Out {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
-
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr
index 5a728a00138..e33102f687c 100644
--- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr
@@ -1,3 +1,12 @@
+error[E0119]: conflicting implementations of trait `Trait<Bar, _>`
+  --> $DIR/issue-84660-unsoundness.rs:29:1
+   |
+LL | impl<In, Out> Trait<Bar, In> for Out {
+   | ------------------------------------ first implementation here
+...
+LL | impl<In, Out> Trait<(), In> for Out {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
+
 error[E0284]: type annotations needed: cannot satisfy `Bar == _`
   --> $DIR/issue-84660-unsoundness.rs:22:37
    |
@@ -9,15 +18,6 @@ LL | |         unreachable!();
 LL | |     }
    | |_____^ cannot satisfy `Bar == _`
 
-error[E0119]: conflicting implementations of trait `Trait<Bar, _>`
-  --> $DIR/issue-84660-unsoundness.rs:29:1
-   |
-LL | impl<In, Out> Trait<Bar, In> for Out {
-   | ------------------------------------ first implementation here
-...
-LL | impl<In, Out> Trait<(), In> for Out {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0119, E0284.
diff --git a/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr b/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr
index d0fe920b35f..aa0c1076117 100644
--- a/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr
+++ b/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr
@@ -1,11 +1,3 @@
-error: unconstrained opaque type
-  --> $DIR/nested-in-anon-const.rs:13:33
-   |
-LL |                     type B<Z> = impl Sized;
-   |                                 ^^^^^^^^^^
-   |
-   = note: `B` must be used in combination with a concrete type within the same item
-
 error[E0308]: mismatched types
   --> $DIR/nested-in-anon-const.rs:12:17
    |
@@ -15,6 +7,14 @@ LL | |
 LL | |                 },
    | |_________________^ expected `usize`, found `()`
 
+error: unconstrained opaque type
+  --> $DIR/nested-in-anon-const.rs:13:33
+   |
+LL |                     type B<Z> = impl Sized;
+   |                                 ^^^^^^^^^^
+   |
+   = note: `B` must be used in combination with a concrete type within the same item
+
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs
new file mode 100644
index 00000000000..dda42580e0f
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs
@@ -0,0 +1,13 @@
+#![allow(incomplete_features)]
+#![feature(non_lifetime_binders)]
+
+trait Trait<T: ?Sized> {}
+
+fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> {
+    //~^ ERROR associated type `Assoc` not found for `Trait`
+    //~| ERROR associated type `Assoc` not found for `Trait`
+    //~| the trait bound `{integer}: Trait<()>` is not satisfied
+    16
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr
new file mode 100644
index 00000000000..fa3306ff11f
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr
@@ -0,0 +1,30 @@
+error[E0220]: associated type `Assoc` not found for `Trait`
+  --> $DIR/non-lifetime-binder-in-constraint.rs:6:39
+   |
+LL | fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> {
+   |                                       ^^^^^ associated type `Assoc` not found
+
+error[E0220]: associated type `Assoc` not found for `Trait`
+  --> $DIR/non-lifetime-binder-in-constraint.rs:6:39
+   |
+LL | fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> {
+   |                                       ^^^^^ associated type `Assoc` not found
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: the trait bound `{integer}: Trait<()>` is not satisfied
+  --> $DIR/non-lifetime-binder-in-constraint.rs:6:17
+   |
+LL | fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> {
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<()>` is not implemented for `{integer}`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/non-lifetime-binder-in-constraint.rs:4:1
+   |
+LL | trait Trait<T: ?Sized> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0220, E0277.
+For more information about an error, try `rustc --explain E0220`.
diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs b/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs
new file mode 100644
index 00000000000..23951c34270
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs
@@ -0,0 +1,10 @@
+#![allow(incomplete_features)]
+#![feature(non_lifetime_binders)]
+
+trait Trait<T> {}
+
+fn f() -> impl for<T> Trait<impl Trait<T>> {}
+//~^ ERROR nested `impl Trait` is not allowed
+//~| ERROR the trait bound `(): Trait<impl Trait<T>>` is not satisfied
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr b/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr
new file mode 100644
index 00000000000..5859d952b75
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr
@@ -0,0 +1,25 @@
+error[E0666]: nested `impl Trait` is not allowed
+  --> $DIR/non-lifetime-binder.rs:6:29
+   |
+LL | fn f() -> impl for<T> Trait<impl Trait<T>> {}
+   |           ------------------^^^^^^^^^^^^^-
+   |           |                 |
+   |           |                 nested `impl Trait` here
+   |           outer `impl Trait`
+
+error[E0277]: the trait bound `(): Trait<impl Trait<T>>` is not satisfied
+  --> $DIR/non-lifetime-binder.rs:6:11
+   |
+LL | fn f() -> impl for<T> Trait<impl Trait<T>> {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<impl Trait<T>>` is not implemented for `()`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/non-lifetime-binder.rs:4:1
+   |
+LL | trait Trait<T> {}
+   | ^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0666.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr
index aedb78bf5e7..99646aa4d1b 100644
--- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr
+++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr
@@ -11,18 +11,6 @@ LL |     Ty: Id<Assoc = Ty>,
    |         ^^^^^^^^^^^^^^ required by this bound
 
 error[E0275]: overflow evaluating the requirement `Ty: Id`
-  --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:15:19
-   |
-LL | fn define() -> Ty {}
-   |                   ^^
-   |
-note: required by a bound on the type alias `Ty`
-  --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:13:9
-   |
-LL |     Ty: Id<Assoc = Ty>,
-   |         ^^^^^^^^^^^^^^ required by this bound
-
-error[E0275]: overflow evaluating the requirement `Ty: Id`
   --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:15:16
    |
 LL | fn define() -> Ty {}
@@ -34,6 +22,6 @@ note: required by a bound on the type alias `Ty`
 LL |     Ty: Id<Assoc = Ty>,
    |         ^^^^^^^^^^^^^^ required by this bound
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/typeck/ice-unexpected-region-123863.stderr b/tests/ui/typeck/ice-unexpected-region-123863.stderr
index 0479f134a38..742096f3861 100644
--- a/tests/ui/typeck/ice-unexpected-region-123863.stderr
+++ b/tests/ui/typeck/ice-unexpected-region-123863.stderr
@@ -4,7 +4,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter
 LL | const fn concat_strs<const A: &'static str>() -> &'static str {
    |                               ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
@@ -20,7 +20,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter
 LL |     struct Inner<const A: &'static str>;
    |                           ^^^^^^^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    |
 LL + #![feature(adt_const_params)]
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.rs b/tests/ui/typeck/typeck_type_placeholder_item.rs
index 29a21a1f45f..437a1aed403 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.rs
+++ b/tests/ui/typeck/typeck_type_placeholder_item.rs
@@ -160,7 +160,7 @@ impl BadTrait<_> for BadStruct<_> {}
 //~^ ERROR the placeholder `_` is not allowed within types on item signatures for implementations
 
 fn impl_trait() -> impl BadTrait<_> {
-//~^ ERROR the placeholder `_` is not allowed within types on item signatures for opaque types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
     unimplemented!()
 }
 
@@ -180,7 +180,7 @@ struct Struct;
 trait Trait<T> {}
 impl Trait<usize> for Struct {}
 type Y = impl Trait<_>;
-//~^ ERROR the placeholder `_` is not allowed within types on item signatures for opaque types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for type aliases
 fn foo() -> Y {
     Struct
 }
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr
index 2c064fbb19f..8a765c21624 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.stderr
+++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr
@@ -484,11 +484,16 @@ help: use type parameters instead
 LL | impl<T> BadTrait<T> for BadStruct<T> {}
    |     +++          ~                ~
 
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:162:34
    |
 LL | fn impl_trait() -> impl BadTrait<_> {
    |                                  ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL | fn impl_trait<T>() -> impl BadTrait<T> {
+   |              +++                    ~
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
   --> $DIR/typeck_type_placeholder_item.rs:167:25
@@ -518,33 +523,17 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures
 LL | type X = Box<_>;
    |              ^ not allowed in type signatures
 
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases
   --> $DIR/typeck_type_placeholder_item.rs:182:21
    |
 LL | type Y = impl Trait<_>;
    |                     ^ not allowed in type signatures
 
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
-  --> $DIR/typeck_type_placeholder_item.rs:44:27
-   |
-LL |     fn test10(&self, _x : _) { }
-   |                           ^ not allowed in type signatures
-   |
-help: use type parameters instead
-   |
-LL |     fn test10<T>(&self, _x : T) { }
-   |              +++             ~
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
-  --> $DIR/typeck_type_placeholder_item.rs:110:34
-   |
-LL |         fn fn_test10(&self, _x : _) { }
-   |                                  ^ not allowed in type signatures
-   |
-help: use type parameters instead
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
+  --> $DIR/typeck_type_placeholder_item.rs:206:14
    |
-LL |         fn fn_test10<T>(&self, _x : T) { }
-   |                     +++             ~
+LL |     const C: _;
+   |              ^ not allowed in type signatures
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
   --> $DIR/typeck_type_placeholder_item.rs:194:14
@@ -555,6 +544,21 @@ LL |     const D: _ = 42;
    |              not allowed in type signatures
    |              help: replace with the correct type: `i32`
 
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
+  --> $DIR/typeck_type_placeholder_item.rs:209:14
+   |
+LL |     const D: _ = 42;
+   |              ^ not allowed in type signatures
+
+error[E0046]: not all trait items implemented, missing: `F`
+  --> $DIR/typeck_type_placeholder_item.rs:200:1
+   |
+LL |     type F: std::ops::Fn(_);
+   |     ----------------------- `F` from trait
+...
+LL | impl Qux for Struct {
+   | ^^^^^^^^^^^^^^^^^^^ missing `F` in implementation
+
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:217:31
    |
@@ -573,27 +577,6 @@ LL | const _: Option<_> = map(value);
    |          not allowed in type signatures
    |          help: replace with the correct type: `Option<u8>`
 
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
-  --> $DIR/typeck_type_placeholder_item.rs:206:14
-   |
-LL |     const C: _;
-   |              ^ not allowed in type signatures
-
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
-  --> $DIR/typeck_type_placeholder_item.rs:209:14
-   |
-LL |     const D: _ = 42;
-   |              ^ not allowed in type signatures
-
-error[E0046]: not all trait items implemented, missing: `F`
-  --> $DIR/typeck_type_placeholder_item.rs:200:1
-   |
-LL |     type F: std::ops::Fn(_);
-   |     ----------------------- `F` from trait
-...
-LL | impl Qux for Struct {
-   | ^^^^^^^^^^^^^^^^^^^ missing `F` in implementation
-
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:225:31
    |
@@ -624,6 +607,17 @@ LL |     fn test9(&self) -> _ { () }
    |                        not allowed in type signatures
    |                        help: replace with the correct return type: `()`
 
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+  --> $DIR/typeck_type_placeholder_item.rs:44:27
+   |
+LL |     fn test10(&self, _x : _) { }
+   |                           ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL |     fn test10<T>(&self, _x : T) { }
+   |              +++             ~
+
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:107:31
    |
@@ -633,6 +627,17 @@ LL |         fn fn_test9(&self) -> _ { () }
    |                               not allowed in type signatures
    |                               help: replace with the correct return type: `()`
 
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
+  --> $DIR/typeck_type_placeholder_item.rs:110:34
+   |
+LL |         fn fn_test10(&self, _x : _) { }
+   |                                  ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL |         fn fn_test10<T>(&self, _x : T) { }
+   |                     +++             ~
+
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
   --> $DIR/typeck_type_placeholder_item.rs:202:14
    |
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs
index 3f43fbfc0cf..53363319ba0 100644
--- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs
@@ -4,7 +4,6 @@ trait Trait<const N: Trait = bar> {
     //~| ERROR the trait `Trait` cannot be made into an object
     //~| ERROR the trait `Trait` cannot be made into an object
     //~| ERROR the trait `Trait` cannot be made into an object
-    //~| ERROR `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
     //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
     //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
     //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
@@ -15,7 +14,6 @@ trait Trait<const N: Trait = bar> {
         //~| ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
         //~| ERROR associated item referring to unboxed trait object for its own trait
         //~| ERROR the trait `Trait` cannot be made into an object
-        //~| ERROR `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
         //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
         //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
         //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
index 6b309c223af..fefb788fac7 100644
--- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
@@ -1,5 +1,5 @@
 error[E0403]: the name `N` is already used for a generic parameter in this item's generic parameters
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:18
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:18
    |
 LL | trait Trait<const N: Trait = bar> {
    |                   - first use of `N`
@@ -14,13 +14,13 @@ LL | trait Trait<const N: Trait = bar> {
    |                              ^^^ not found in this scope
 
 error[E0423]: expected value, found builtin type `u32`
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:29
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:29
    |
 LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
    |                             ^^^ not a value
 
 error[E0425]: cannot find value `bar` in this scope
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:25:9
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:23:9
    |
 LL |         bar
    |         ^^^ not found in this scope
@@ -54,13 +54,13 @@ LL | trait Trait<const N: Trait = bar> {
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
 error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:12
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:12
    |
 LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
    |            ^^^^^^^^^^^^^^^^^^^^
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:21
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21
    |
 LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
    |                     ^^^^^
@@ -73,7 +73,7 @@ LL |     fn fnc<const N: dyn Trait = u32>(&self) -> Trait {
    |                     +++
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:44
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:44
    |
 LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
    |                                            ^^^^^
@@ -106,7 +106,7 @@ LL | trait Trait<const N: Trait = bar> {
    |                      ^^^^^ `Trait` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8
    |
 LL | trait Trait<const N: Trait = bar> {
    |       ----- this trait cannot be made into an object...
@@ -122,7 +122,7 @@ LL | trait Trait<const N: Trait = bar> {
    |             ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8
    |
 LL | trait Trait<const N: Trait = bar> {
    |       ----- this trait cannot be made into an object...
@@ -131,16 +131,8 @@ LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
    |        ^^^ ...because method `fnc` has generic type parameters
    = help: consider moving `fnc` to another trait
 
-error: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
-   |
-LL | trait Trait<const N: Trait = bar> {
-   |                      ^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-
 error: associated item referring to unboxed trait object for its own trait
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:44
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:44
    |
 LL | trait Trait<const N: Trait = bar> {
    |       ----- in this trait
@@ -154,7 +146,7 @@ LL |     fn fnc<const N: Trait = u32>(&self) -> Self {
    |                                            ~~~~
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:21
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21
    |
 LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
    |                     ^^^^^
@@ -168,13 +160,13 @@ LL |     fn fnc<const N: dyn Trait = u32>(&self) -> Trait {
    |                     +++
 
 error[E0038]: the trait `Trait` cannot be made into an object
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:21
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21
    |
 LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
    |                     ^^^^^ `Trait` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8
    |
 LL | trait Trait<const N: Trait = bar> {
    |       ----- this trait cannot be made into an object...
@@ -190,7 +182,7 @@ LL | trait Trait<const N: Trait = bar> {
    |             ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8
    |
 LL | trait Trait<const N: Trait = bar> {
    |       ----- this trait cannot be made into an object...
@@ -200,15 +192,7 @@ LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
    = help: consider moving `fnc` to another trait
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:21
-   |
-LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
-   |                     ^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-
-error: aborting due to 13 previous errors; 5 warnings emitted
+error: aborting due to 11 previous errors; 5 warnings emitted
 
 Some errors have detailed explanations: E0038, E0391, E0403, E0423, E0425.
 For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr
index d2b0e2d92e0..f8905437c6e 100644
--- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr
@@ -73,7 +73,7 @@ error: `(dyn Bar<2> + 'static)` is forbidden as the type of a const generic para
 LL | trait Foo<const N: Bar<2>> {
    |                    ^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:11
@@ -104,7 +104,7 @@ error: `(dyn Foo<2> + 'static)` is forbidden as the type of a const generic para
 LL | trait Bar<const M: Foo<2>> {}
    |                    ^^^^^^
    |
-   = note: the only supported types are integers, `bool` and `char`
+   = note: the only supported types are integers, `bool`, and `char`
 
 error: aborting due to 5 previous errors; 2 warnings emitted
 
diff --git a/triagebot.toml b/triagebot.toml
index aba36692828..737be4cc457 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -925,6 +925,7 @@ users_on_vacation = [
     "jhpratt",
     "jyn514",
     "oli-obk",
+    "jieyouxu",
 ]
 
 [assign.adhoc_groups]
@@ -938,7 +939,6 @@ compiler-team = [
     "@oli-obk",
     "@pnkfelix",
     "@wesleywiser",
-    "@michaelwoerister",
 ]
 compiler-team-contributors = [
     "@TaKO8Ki",
@@ -989,7 +989,6 @@ query-system = [
     "@cjgillot",
 ]
 incremental = [
-    "@michaelwoerister",
     "@wesleywiser",
 ]
 diagnostics = [
@@ -1048,7 +1047,6 @@ ast_lowering = [
     "@spastorino",
 ]
 debuginfo = [
-    "@michaelwoerister",
     "@davidtwco"
 ]
 fallback = [